新聞中心

EEPW首頁 > 嵌入式系統(tǒng) > 設(shè)計應(yīng)用 > STM32 驅(qū)動無線NRF24L01 完成串口數(shù)據(jù)傳輸

STM32 驅(qū)動無線NRF24L01 完成串口數(shù)據(jù)傳輸

作者: 時間:2016-12-03 來源:網(wǎng)絡(luò) 收藏
2401 一個簡單的SPI 接口的 2.4G 射頻模塊 淘寶價20¥,DIY 的17¥ ,算是廉價。
這個版本的穩(wěn)定修正http://ntn314.blog.163.com/blog/static/16174358420106211118944/
接口CMOS電平3.3V STM32 可直接連接。接受完成 發(fā)送完成 出錯 都有IRQ 低電平中斷產(chǎn)生。程序中 我將其連接至一IO口在外部中斷中處里各類事件 但也發(fā)現(xiàn)這種處理方式并不是特別靈活,或許直接判斷更加靈活。
NRF20L01一次可以傳輸 1~32個字節(jié)比較靈活。最初我是根據(jù)字符串長來不停的轉(zhuǎn)換每次傳輸?shù)拈L度,這樣做十分麻煩最后用截取有效串長的方法實現(xiàn)效果很好。
程序修修改過 總算穩(wěn)定了 不過在傳輸大于32個字節(jié)的信息時出錯的概率很大,原因暫時不清楚,不過能自動恢復(fù)過來。另外在帶有硬件的在線仿真調(diào)試的時候一定要運行前斷開外部硬件的電源再重新連接,保證外部器件的正常初始化。
/***********************s****************************/
u8 tran=0; //中斷標(biāo)志
u8 sta; //定義一個可位尋址的變量sta
uc8 TX_ADDRESS[TX_ADR_WIDTH] = {0x34,0x43,0x10,0x10,0x01};
char RX_BUF[256];
uchar TX_BUF[256];

/**************************************************/
void RF_SPI_Config(void)
{
SPI_InitTypeDef SPI_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
EXTI_InitTypeDef EXTI_InitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2,ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD,ENABLE);

/* PB15-MOSI2,PB13-SCK2*/
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13 |GPIO_Pin_14 | GPIO_Pin_15;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_Init(GPIOB, &GPIO_InitStructure);
//IRQ
GPIO_SetBits(GPIOB, GPIO_Pin_0);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_Init(GPIOB, &GPIO_InitStructure);
GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource0);
/* 配置中斷線0為下降觸發(fā)*/
EXTI_InitStructure.EXTI_Line = EXTI_Line0;
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
EXTI_InitStructure.EXTI_LineCmd = ENABLE;
EXTI_Init(&EXTI_InitStructure);
/*PB2-CS*/
GPIO_SetBits(GPIOB, GPIO_Pin_2);//預(yù)置為高
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(GPIOB, &GPIO_InitStructure);
/*PC4-A0*/
GPIO_SetBits(GPIOC, GPIO_Pin_4);//預(yù)置為高
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(GPIOC, &GPIO_InitStructure);
/*LED*/
GPIO_SetBits(GPIOB, GPIO_Pin_12);//預(yù)置為高
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(GPIOB, &GPIO_InitStructure);
/* SPI2 configuration */
SPI_Cmd(SPI2, DISABLE); //必須先禁能,才能改變MODE
SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;//兩線全雙工
SPI_InitStructure.SPI_Mode = SPI_Mode_Master;//主
SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;//8位
SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;//CPOL=0 時鐘懸空低
SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;//CPHA=0 數(shù)據(jù)捕獲第1個
SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;//軟件NSS
SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_64 ;//64分頻
SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;//高位在前
SPI_InitStructure.SPI_CRCPolynomial = 7;//CRC7

SPI_Init(SPI2, &SPI_InitStructure);
SPI_Cmd(SPI2, ENABLE);
}
/**************************************************************
但切記不可忽略SPI的硬件接收,因為讀SPI_DR才能清除RXEN
***************************************************************/
u8 SPI_RW(u8 byte)
{
/*等待發(fā)送寄存器空*/
while((SPI2->SR & SPI_I2S_FLAG_TXE)==RESET);
/*發(fā)送一個字節(jié)*/
SPI2->DR = byte;
/* 等待接收寄存器有效*/
while((SPI2->SR & SPI_I2S_FLAG_RXNE)==RESET);
return(SPI2->DR);
}
/**************************************************
函數(shù):SPI_RW_Reg()
描述:寫數(shù)據(jù)value到reg寄存器
*************************************************/
u8 SPI_RW_Reg(u8 reg, u8 value)
{
u8 status;
CSN_L; // CSN置低,開始傳輸數(shù)據(jù)
status = SPI_RW(reg); // 選擇寄存器,同時返回狀態(tài)字
SPI_RW(value); // 然后寫數(shù)據(jù)到該寄存器
CSN_H; // CSN拉高,結(jié)束數(shù)據(jù)傳輸
return(status); // 返回狀態(tài)寄存器
}
/**************************************************
函數(shù): init_io()
描述:初始化IO
*************************************************/
void RX_Mode(void);
void init_io(void)
{
CE_L; // 待機(jī)
CSN_H; // SPI禁止
LED1;// 關(guān)閉指示燈
RX_Mode();//接收
}
/**************************************************
函數(shù):SPI_Read()
描述:從reg寄存器讀一字節(jié)
*************************************************/
u8 SPI_Read(u8 reg)
{
u8 reg_val;
CSN_L; // CSN置低,開始傳輸數(shù)據(jù)
SPI_RW(reg); // 選擇寄存器
reg_val = SPI_RW(0); // 然后從該寄存器讀數(shù)據(jù)
CSN_H; // CSN拉高,結(jié)束數(shù)據(jù)傳輸
return(reg_val); // 返回寄存器數(shù)據(jù)
}
/**************************************************
函數(shù):SPI_Read_Buf()
描述:從reg寄存器讀出bytes個字節(jié),通常用來讀取接收通道
數(shù)據(jù)或接收/發(fā)送地址
*************************************************/
uchar SPI_Read_Buf(uchar reg, char * pBuf, uchar bytes)
{
uchar status, i;
CSN_L; // CSN置低,開始傳輸數(shù)據(jù)
status = SPI_RW(reg); // 選擇寄存器,同時返回狀態(tài)字
for(i=0; i pBuf[i] = SPI_RW(0); // 逐個字節(jié)從nRF24L01讀出
CSN_H; // CSN拉高,結(jié)束數(shù)據(jù)傳輸
return(status); // 返回狀態(tài)寄存器
}
/**************************************************
函數(shù):SPI_Write_Buf()
描述:把pBuf緩存中的數(shù)據(jù)寫入到nRF24L01,通常用來寫入發(fā)
射通道數(shù)據(jù)或接收/發(fā)送地址
*************************************************/
uchar SPI_Write_Buf(uchar reg, uchar * pBuf, uchar bytes)
{
uchar status, i;
CSN_L; // CSN置低,開始傳輸數(shù)據(jù)
status = SPI_RW(reg); // 選擇寄存器,同時返回狀態(tài)字
for(i=0; i SPI_RW(pBuf[i]); // 逐個字節(jié)寫入nRF24L01
CSN_H; // CSN拉高,結(jié)束數(shù)據(jù)傳輸
return(status); // 返回狀態(tài)寄存器
}
/**************************************************
函數(shù):RX_Mode()
描述:這個函數(shù)設(shè)置nRF24L01為接收模式,等待接收發(fā)送設(shè)備的數(shù)據(jù)包
*************************************************/
void RX_Mode(void)
{
CE_L;
SPI_Write_Buf(RF_WRITE_REG + RX_ADDR_P0, (u8*)TX_ADDRESS, TX_ADR_WIDTH); // 接收設(shè)備接收通道0使用和發(fā)送設(shè)備相同的發(fā)送地址
SPI_RW_Reg(RF_WRITE_REG + EN_AA, 0x01); // 使能接收通道0自動應(yīng)答
SPI_RW_Reg(RF_WRITE_REG + EN_RXADDR, 0x01); // 使能接收通道0
SPI_RW_Reg(RF_WRITE_REG + RF_CH, 40); // 選擇射頻通道0x40
SPI_RW_Reg(RF_WRITE_REG + RX_PW_P0, TX_PLOAD_WIDTH); // 接收通道0選擇和發(fā)送通道相同有效數(shù)據(jù)寬度
SPI_RW_Reg(RF_WRITE_REG + RF_SETUP, 0x07); // 數(shù)據(jù)傳輸率1Mbps,發(fā)射功率0dBm,低噪聲放大器增益
SPI_RW_Reg(RF_WRITE_REG + CONFIG, 0x0f); // CRC使能,16位CRC校驗,上電,接收模式
CE_H; // 拉高CE啟動接收設(shè)備
}
/**************************************************
函數(shù):TX_Mode()
描述:
這個函數(shù)設(shè)置nRF24L01為發(fā)送模式,(CE=1持續(xù)至少10us),
130us后啟動發(fā)射,數(shù)據(jù)發(fā)送結(jié)束后,發(fā)送模塊自動轉(zhuǎn)入接收
模式等待應(yīng)答信號。
*************************************************/
void TX_Mode(uchar * BUF)
{
CE_L;
SPI_Write_Buf(RF_WRITE_REG + TX_ADDR, (u8*)TX_ADDRESS, TX_ADR_WIDTH); // 寫入發(fā)送地址
SPI_Write_Buf(RF_WRITE_REG + RX_ADDR_P0, (u8*)TX_ADDRESS, TX_ADR_WIDTH); // 為了應(yīng)答接收設(shè)備,接收通道0地址和發(fā)送地址相同
SPI_Write_Buf(WR_TX_PLOAD, BUF, TX_PLOAD_WIDTH); // 寫數(shù)據(jù)包到TX FIFO
SPI_RW_Reg(RF_WRITE_REG + EN_AA, 0x01); // 使能接收通道0自動應(yīng)答
SPI_RW_Reg(RF_WRITE_REG + EN_RXADDR, 0x01); // 使能接收通道0
SPI_RW_Reg(RF_WRITE_REG + SETUP_RETR, 0x0a); // 自動重發(fā)延時等待250us+86us,自動重發(fā)10次
SPI_RW_Reg(RF_WRITE_REG + RF_CH, 40); // 選擇射頻通道0x40
SPI_RW_Reg(RF_WRITE_REG + RF_SETUP, 0x07); // 數(shù)據(jù)傳輸率1Mbps,發(fā)射功率0dBm,低噪聲放大器增益
SPI_RW_Reg(RF_WRITE_REG + CONFIG, 0x0e); // CRC使能,16位CRC校驗,上電
CE_H;CE_H;delay_ms(1);
}
/**************************************************
函數(shù):Check_ACK()
描述:
檢查接收設(shè)備有無接收到數(shù)據(jù)包,設(shè)定沒有收到應(yīng)答信
號是否重發(fā)
***************************************************/
uchar Check_ACK(u8 clear)
{
while(IRQ);
sta = SPI_RW(NOP); // 返回狀態(tài)寄存器
if(MAX_RT)
if(clear) // 是否清除TX FIFO,若沒有清除在清除MAX_RT中斷標(biāo)志后重發(fā)
SPI_RW(FLUSH_TX);
SPI_RW_Reg(RF_WRITE_REG + STATUS, sta); // 清除TX_DS或MAX_RT中斷標(biāo)志
IRQ_H;
if(TX_DS)
return(0x00);
else
return(0xff);
}

void sent_data(u8* fp,u16 flong)
{
u16 i=65535;
TX_Mode((u8*)&flong); //傳送長度
while(!tran&&i>1)i--; //等待完成
tran=0;
flong=flong/33+1;
for(i=0;i<20000;i++);//130uS*2延時
while(flong)
{
if(MAX_RT) return;//無應(yīng)答返回
TX_Mode(fp); //傳送數(shù)據(jù)
while(!tran&&i>1)i--; //等待完成
tran=0;
for(i=0;i<20000;i++);//130uS*2延時
fp+=32;flong--;
}
}
extern u8 RX_NU;
void test (void)
{
if (Uart2_Get_Flag!=0&&Timer2==0)
{
sent_data(TX_BUF,(u16)Uart2_Get_Flag);
Uart2_Get_Flag=0;
}

if(Timer2==0&&RX_NU==2)
{
RX_NU=1;
USART2_Puts("傳輸錯誤 ");
USART2_Puts("rn");
}
}
兩個中斷 串口 和 外部中斷
/*******************************************************************************
* Function Name : EXTI0_IRQHandler
* Description : This function handles External interrupt Line 0 request.
* Input : None
* Output : None
* Return : None
*******************************************************************************/
extern u8 sta;
extern char RX_BUF[256];
extern uchar TX_BUF[256];
extern u8 SPI_RW_Reg(u8 reg, u8 value);
extern void RX_Mode(void);
extern uchar SPI_Read_Buf(uchar reg, char * pBuf, uchar bytes);
u8 RX_NU=1;//1接收長度 2接收數(shù)據(jù)
u16 rectnu,onerc; //接收串長,接收次數(shù)
char* PRX_BUF=RX_BUF;
void EXTI0_IRQHandler(void)
{
EXTI_ClearITPendingBit(EXTI_Line0);
tran=1;
CSN_L;
sta=SPI_RW(NOP); // 返回狀態(tài)寄存器
CSN_H;

if(MAX_RT)
{
USART2_Puts("對方無應(yīng)答 ");
CSN_L;
SPI_RW(FLUSH_TX); // 清除TX FIFO,若沒有清除在清除MAX_RT中斷標(biāo)志后重發(fā)
CSN_H;
SPI_RW_Reg(RF_WRITE_REG + STATUS, sta);
}

if(TX_DS)
{
SPI_RW_Reg(RF_WRITE_REG + STATUS, sta); // 清除TX_DS或MAX_RT中斷標(biāo)志
}
if(RX_DR) // 判斷是否接受到數(shù)據(jù)
{

if(RX_NU==1)
{
CE_L;
SPI_Read_Buf(RD_RX_PLOAD, RX_BUF, TX_PLOAD_WIDTH); // 從RX FIFO讀出數(shù)據(jù)
SPI_RW_Reg(RF_WRITE_REG + STATUS, sta); // 清除RX_DS中斷標(biāo)志
rectnu=RX_BUF[0];rectnu|=RX_BUF[1]<<8; //接收串長
onerc=rectnu/33+1; //計算接收次數(shù)
RX_NU=2;RX_Mode();Timer2=500;/*超時時間*/
return;
}
if(RX_NU==2)
{
CE_L;
SPI_Read_Buf(RD_RX_PLOAD, PRX_BUF, TX_PLOAD_WIDTH); // 從RX FIFO讀出數(shù)據(jù)
SPI_RW_Reg(RF_WRITE_REG + STATUS, sta); // 清除RX_DS中斷標(biāo)志
onerc--;PRX_BUF+=32; //接收計數(shù) 接收指針移動
if(!onerc)
{
RX_BUF[rectnu]=