NRF24L01 無線模塊,采用的芯片是 NRF24L01,該芯片的主要特點如下:
1)2.4G 全球開放的 ISM 頻段,免許可證使用。
2)最高工作速率 2Mbps,高校的 GFSK 調制,抗干擾能力強。
3)125 個可選的頻道,滿足多點通信和調頻通信的需要。
4)內置 CRC 檢錯和點對多點的通信地址控制。
5)低工作電壓(1.9~3.6V)。
6)可設置自動應答,確保數據可靠傳輸。
模塊引腳圖如下所示

模塊 VCC 腳的電壓范圍為 1.9~3.6V,建議不要超過 3.6V,否則可能燒壞模塊,一般用 3.3V
電壓比較合適。除了 VCC 和 GND 腳,其他引腳都可以和 5V 單片機的 IO 口直連,正是因為其
兼容 5V 單片機的 IO,故使用上具有很大優勢
該芯片在接收模式下可以同時接收六個發送端信息,因為其內部有六個通道,發送模式下只能一個發
該芯片有兩種傳輸模式,第一個是無雙向鏈接的模式,也就是單向發送沒有ACK,第二種芯片自帶ACK模式,推薦用第二種,只要是使能動應答即可,並且,在第二種模式下,發送端的接收通道0用來作為ACK的接收通道,接收端的發送通道用來做ack的發送通道,設置地址時要注意這兩個地方地址應當相同
主要命令如下

寫寄存器命令只有在CE為0處於待機狀態下時才有效,使用時應當注意這一點
具體去掉那個代碼如下
24l01.h
#ifndef __24L01_H #define __24L01_H #include "ioremap.h" #include "delay.h" #include "spi.h" //設備地址設置 #define ADDR1_VALUE 0X34 #define ADDR2_VALUE 0X43 #define ADDR3_VALUE 0X10 #define ADDR4_VALUE 0X10 #define ADDR5_VALUE 0X01 ////////////////////////////////////////////////////////////////////////////////////////////////////////// //NRF24L01寄存器操作命令 #define READ_REG_NRF 0x00 //讀配置寄存器,低5位為寄存器地址 #define WRITE_REG_NRF 0x20 //寫配置寄存器,低5位為寄存器地址 #define RD_RX_PLOAD 0x61 //讀RX有效數據,1~32字節,應用於接收模式下,讀取完成后自動清除FIFO #define WR_TX_PLOAD 0xA0 //寫TX有效數據,1~32字節,應用於發射模式下 #define FLUSH_TX 0xE1 //清除TX FIFO寄存器.發射模式下用 #define FLUSH_RX 0xE2 //清除RX FIFO寄存器.接收模式下用,傳輸應答信號過程中用這個指令會讓應答數據不能完整傳輸 #define REUSE_TX_PL 0xE3 //重新使用上一包數據,CE為高,數據包被不斷發送.發射過程中必須禁止用這個功能 #define NOP 0xFF //空操作,可以用來讀狀態寄存器 //SPI(NRF24L01)寄存器地址 #define CONFIG 0x00 //配置寄存器地址; //bit0:1接收模式,0發射模式; //bit1:1上電 2掉電; //bit2:CRC模式; 0八位CRC 1 16位CRC //bit3:CRC使能;1使能 0不使能(若是使能自動應答,這一位必須為高) //bit4 可屏蔽中斷 MAX_RT 1 屏蔽 0不屏蔽 發生中斷IRQ為低電平(最大重發中斷) //bit5 可屏蔽中斷TX_DS 1屏蔽 0不 數據發送完成並收到應答 //bit6 可屏蔽中斷RX_DR 接收數據完成 1屏蔽 0不屏蔽 //bit7 默認為0 #define EN_AA 0x01 //bit0~5,使能自動應答功能 (自動應答必然啟動CRC)對應通道0~5 #define EN_RXADDR 0x02 //bit0~5,接收數據通道允許,對應通道0~5 #define SETUP_AW 0x03 //bit1,0:設置地址寬度(所有數據通道) 01,3字節; 10,4字節; 11,5字節;(默認11) #define SETUP_RETR 0x04 //建立自動重發; //bit3:0,自動重發計數器;0000 15次 //bit7:4,自動重發延時 0000 250*x+86us #define RF_CH 0x05 //RF通道,bit6:0,工作通道頻率 #define RF_SETUP 0x06 //bit4: pll lock允許,僅用於測試模式,應當為1 //bit3: 傳輸速率(0:1Mbps,1:2Mbps); //bit2:1,發射功率 11 0dbm; //bit0:低噪聲放大器增益 #define STATUS 0x07 //bit0:TX FIFO滿標志; //bit3:1,接收數據通道號(最大:6);接收到數據的通道號碼 //bit4,達到最多次重發 max_rt中斷 //bit5:數據發送完成中斷;寫1清除中斷 //bit6:接收數據中斷; 寫1清除中斷 #define OBSERVE_TX 0x08 //發送檢測寄存器, //bit7:4,數據包丟失計數器; //bit3:0,重發計數器 #define CD 0x09 //載波檢測寄存器, //bit0,載波檢測; #define RX_ADDR_P0 0x0A //數據通道0接收地址,最大長度5個字節,低字節在前 #define RX_ADDR_P1 0x0B //數據通道1接收地址,最大長度5個字節,低字節在前 #define RX_ADDR_P2 0x0C //數據通道2接收地址,最低字節可設置,高字節,必須同RX_ADDR_P1[39:8]相等; #define RX_ADDR_P3 0x0D //數據通道3接收地址,最低字節可設置,高字節,必須同RX_ADDR_P1[39:8]相等; #define RX_ADDR_P4 0x0E //數據通道4接收地址,最低字節可設置,高字節,必須同RX_ADDR_P1[39:8]相等; #define RX_ADDR_P5 0x0F //數據通道5接收地址,最低字節可設置,高字節,必須同RX_ADDR_P1[39:8]相等; #define TX_ADDR 0x10 //發送地址(低字節在前),ShockBurstTM模式下,RX_ADDR_P0與此地址相等 #define RX_PW_P0 0x11 //接收數據通道0有效數據寬度(1~32字節),設置為0則非法 #define RX_PW_P1 0x12 //接收數據通道1有效數據寬度(1~32字節),設置為0則非法 #define RX_PW_P2 0x13 //接收數據通道2有效數據寬度(1~32字節),設置為0則非法 #define RX_PW_P3 0x14 //接收數據通道3有效數據寬度(1~32字節),設置為0則非法 #define RX_PW_P4 0x15 //接收數據通道4有效數據寬度(1~32字節),設置為0則非法 #define RX_PW_P5 0x16 //接收數據通道5有效數據寬度(1~32字節),設置為0則非法 #define NRF_FIFO_STATUS 0x17 //FIFO狀態寄存器; //bit0,RX FIFO寄存器空標志; //bit1,RX FIFO滿標志; //bit2,3,保留 //bit4,TX FIFO空標志; //bit5,TX FIFO滿標志; //bit6,1,循環發送上一數據包.0,不循環; #define MAX_TX 0x10 //達到最大發送次數中斷 #define TX_OK 0x20 //TX發送完成中斷 #define RX_OK 0x40 //接收到數據中斷 ////////////////////////////////////////////////////////////////////////////////////////////////////////// //24L01操作線 #define NRF24L01_CE PGout(6) //24L01片選信號 #define NRF24L01_CSN PGout(7) //SPI片選信號 #define NRF24L01_IRQ PGin(8) //IRQ主機數據輸入 //24L01發送接收數據寬度定義 #define TX_ADR_WIDTH 5 //5字節的地址寬度 #define RX_ADR_WIDTH 5 //5字節的地址寬度 #define TX_PLOAD_WIDTH 32 //32字節的用戶數據寬度 #define RX_PLOAD_WIDTH 32 //32字節的用戶數據寬度 void Nrf24l01Init(void);//初始化 void Nrf24l01RxMode(void);//配置為接收模式 void Nrf24l01TxMode(void);//配置為發送模式 u8 Nrf24l01WriteBuf(u8 reg, u8 *pBuf, u8 u8s);//寫數據區 u8 Nrf24l01ReadBuf(u8 reg, u8 *pBuf, u8 u8s);//讀數據區 u8 Nrf24l01ReadReg(u8 reg); //讀寄存器 u8 Nrf24l01WriteReg(u8 reg, u8 value);//寫寄存器 u8 Nrf24l01Check(void);//檢查24L01是否存在 u8 Nrf24l01TxPacket(u8 *txbuf);//發送一個包的數據 u8 Nrf24l01RxPacket(u8 *rxbuf);//接收一個包的數據 #endif
24l01.c
#include "24l01.h"
const u8 TX_ADDRESS[TX_ADR_WIDTH]={ADDR1_VALUE,ADDR2_VALUE,ADDR3_VALUE,ADDR4_VALUE,ADDR5_VALUE}; //發送地址
const u8 RX_ADDRESS[RX_ADR_WIDTH]={ADDR1_VALUE,ADDR2_VALUE,ADDR3_VALUE,ADDR4_VALUE,ADDR5_VALUE}; //發送地址
//初始化24L01的IO口
void Nrf24l01Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
SPI_InitTypeDef SPI_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB|RCC_APB2Periph_GPIOD|RCC_APB2Periph_GPIOG, ENABLE); //使能PB,D,G端口時鍾
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12; //PB12上拉 防止W25X的干擾
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽輸出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure); //初始化指定IO
GPIO_SetBits(GPIOB,GPIO_Pin_12);//上拉
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2; //PD2推挽輸出上拉 禁止SD卡的干擾
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽輸出
GPIO_SetBits(GPIOD,GPIO_Pin_2);//初始化指定IO
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6|GPIO_Pin_7; //PG6 7 推挽
GPIO_Init(GPIOG, &GPIO_InitStructure);//初始化指定IO
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD; //PG8 輸入
GPIO_Init(GPIOG, &GPIO_InitStructure);
GPIO_ResetBits(GPIOG,GPIO_Pin_6|GPIO_Pin_7|GPIO_Pin_8);//PG6,7,8上拉
Spi2Init(); //初始化SPI
SPI_Cmd(SPI2, DISABLE); // SPI外設不使能
SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex; //SPI設置為雙線雙向全雙工
SPI_InitStructure.SPI_Mode = SPI_Mode_Master; //SPI主機
SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b; //發送接收8位幀結構
SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low; //時鍾懸空低
SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge; //數據捕獲於第1個時鍾沿
SPI_InitStructure.SPI_NSS = SPI_NSS_Soft; //NSS信號由軟件控制
SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_16; //定義波特率預分頻的值:波特率預分頻值為16
SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB; //數據傳輸從MSB位開始
SPI_InitStructure.SPI_CRCPolynomial = 7; //CRC值計算的多項式
SPI_Init(SPI2, &SPI_InitStructure); //根據SPI_InitStruct中指定的參數初始化外設SPIx寄存器
SPI_Cmd(SPI2, ENABLE); //使能SPI外設
NRF24L01_CE=0; //使能24L01,初始化低電平進入待機模式
NRF24L01_CSN=1; //SPI片選取消
}
//SPI寫寄存器
//reg:指定寄存器地址
//value:寫入的值
//每一個命令的執行都需要一次CSN由低到高的過程
u8 Nrf24l01WriteReg(u8 reg,u8 value)
{
u8 status;
NRF24L01_CSN=0; //使能SPI傳輸
NRF24L01_CE=0; //待機模式才能進行寄存器寫入
status =Spi2ReadWriteByte(WRITE_REG_NRF+reg);//發送寄存器號 +讀寄存器命令
Spi2ReadWriteByte(value); //寫入寄存器的值
NRF24L01_CSN=1; //禁止SPI傳輸
return(status); //返回狀態值
}
//讀取SPI寄存器值
//reg:要讀的寄存器
u8 Nrf24l01ReadReg(u8 reg)
{
u8 reg_val;
NRF24L01_CSN = 0; //使能SPI傳輸
Spi2ReadWriteByte(READ_REG_NRF+reg); //發送寄存器號+讀寄存器命令
reg_val=Spi2ReadWriteByte(0XFF);//讀取寄存器內容
NRF24L01_CSN = 1; //禁止SPI傳輸
return(reg_val); //返回狀態值
}
//在指定位置讀出指定長度的數據
//reg:寄存器(位置)
//*pBuf:數據指針
//len:數據長度
//返回值,此次讀到的狀態寄存器值
u8 Nrf24l01ReadBuf(u8 reg,u8 *pBuf,u8 len)
{
u8 status,u8_ctr;
NRF24L01_CSN = 0; //使能SPI傳輸
status=Spi2ReadWriteByte(reg);//發送寄存器值(位置),並讀取狀態值
for(u8_ctr=0;u8_ctr<len;u8_ctr++)pBuf[u8_ctr]=Spi2ReadWriteByte(0XFF);//讀出數據
NRF24L01_CSN=1; //關閉SPI傳輸
return status; //返回讀到的狀態值
}
//在指定位置寫指定長度的數據
//reg:寄存器(位置)
//*pBuf:數據指針
//len:數據長度
//返回值,此次讀到的狀態寄存器值
u8 Nrf24l01WriteBuf(u8 reg, u8 *pBuf, u8 len)
{
u8 status,u8_ctr;
NRF24L01_CSN = 0; //使能SPI傳輸
status = Spi2ReadWriteByte(reg);//發送寄存器值(位置),並讀取狀態值
for(u8_ctr=0; u8_ctr<len; u8_ctr++)Spi2ReadWriteByte(*pBuf++); //寫入數據
NRF24L01_CSN = 1; //關閉SPI傳輸
return status; //返回讀到的狀態值
}
//檢測24L01是否存在
//返回值:0,成功;1,失敗
//通過地址檢測方式檢測24l01是否存在
u8 Nrf24l01Check(void)
{
u8 buf[5]={0XA5,0XA5,0XA5,0XA5,0XA5};
u8 i;
Spi2SetSpeed(SPI_BaudRatePrescaler_4); //spi速度為9Mhz(24L01的最大SPI時鍾為10Mhz)
Nrf24l01WriteBuf(TX_ADDR,buf,5);//寫入5個字節的地址.
Nrf24l01ReadBuf(TX_ADDR,buf,5); //讀出寫入的地址
for(i=0;i<5;i++)if(buf[i]!=0XA5)break;
if(i!=5)return 1;//檢測24L01錯誤
return 0; //檢測到24L01
}
//該函數初始化NRF24L01到RX模式
//設置RX地址,寫RX數據寬度,選擇RF頻道,波特率和LNA HCURR
//當CE變高后,即進入RX模式,並可以接收數據了
void Nrf24l01RxMode(void)
{
NRF24L01_CE=0;
Nrf24l01WriteBuf(RX_ADDR_P0,(u8*)RX_ADDRESS,RX_ADR_WIDTH);//寫RX節點地址,地址默認是五個字節
Nrf24l01WriteReg(EN_AA,0x01); //使能通道0的自動應答
Nrf24l01WriteReg(EN_RXADDR,0x01);//使能通道0的接收地址
Nrf24l01WriteReg(RF_CH,40); //設置RF通信頻率
Nrf24l01WriteReg(RX_PW_P0,RX_PLOAD_WIDTH);//選擇通道0的有效數據寬度
Nrf24l01WriteReg(RF_SETUP,0x0f);//設置TX發射參數,0db增益,2Mbps,低噪聲增益開啟
Nrf24l01WriteReg(CONFIG, 0x0f);//配置基本工作模式的參數;PWR_UP,EN_CRC,16BIT_CRC,接收模式
NRF24L01_CE = 1; //CE為高,進入接收模式
}
//該函數初始化NRF24L01到TX模式
//設置TX地址,寫TX數據寬度,設置RX自動應答的地址,填充TX發送數據,選擇RF頻道,波特率和LNA HCURR
//PWR_UP,CRC使能
//當CE變高后,即進入RX模式,並可以接收數據了
//CE為高大於10us,則啟動發送.
void Nrf24l01TxMode(void)
{
NRF24L01_CE=0;
Nrf24l01WriteBuf(TX_ADDR,(u8*)TX_ADDRESS,TX_ADR_WIDTH);//寫TX節點地址
Nrf24l01WriteBuf(RX_ADDR_P0,(u8*)RX_ADDRESS,RX_ADR_WIDTH); //設置TX節點地址,主要為了使能ACK,通道0作為自動ACK接收地址
Nrf24l01WriteReg(EN_AA,0x01); //使能通道0的自動應答
Nrf24l01WriteReg(EN_RXADDR,0x01); //使能通道0的接收地址
Nrf24l01WriteReg(SETUP_RETR,0x1a);//設置自動重發間隔時間:500us + 86us;最大自動重發次數:10次
Nrf24l01WriteReg(RF_CH,40); //設置RF通道為40
Nrf24l01WriteReg(RF_SETUP,0x0f); //設置TX發射參數,0db增益,2Mbps,低噪聲增益開啟
Nrf24l01WriteReg(CONFIG,0x0e); //配置基本工作模式的參數;PWR_UP,EN_CRC,16BIT_CRC,接收模式,開啟所有中斷
NRF24L01_CE=1;//CE為高,10us后啟動發送
}
//啟動NRF24L01發送一次數據
//txbuf:待發送數據首地址
//返回值:發送完成狀況
u8 Nrf24l01TxPacket(u8 *txbuf)
{
u8 sta;
Spi2SetSpeed(SPI_BaudRatePrescaler_8);//spi速度為9Mhz(24L01的最大SPI時鍾為10Mhz)
NRF24L01_CE=0;
Nrf24l01WriteBuf(WR_TX_PLOAD,txbuf,TX_PLOAD_WIDTH);//寫數據到TX BUF 32個字節
NRF24L01_CE=1;//啟動發送
while(NRF24L01_IRQ!=0);//等待發送完成
sta=Nrf24l01ReadReg(STATUS); //讀取狀態寄存器的值
Nrf24l01WriteReg(STATUS,sta); //清除TX_DS或MAX_RT中斷標志
if(sta&MAX_TX)//達到最大重發次數
{
Nrf24l01WriteReg(FLUSH_TX,0xff);//清除TX FIFO寄存器
return MAX_TX;
}
if(sta&TX_OK)//發送完成
{
return TX_OK;
}
return 0xff;//其他原因發送失敗
}
//檢測接收狀態,為1則有數據
u8 Nrf24l01CheckRxBuffer(void)
{
u8 sta;
sta=Nrf24l01ReadReg(STATUS); //讀取狀態寄存器的值
if(sta&RX_OK)return 1;//接收到數據
else return 0;
}
//啟動NRF24L01發送一次數據
//txbuf:待發送數據首地址
//返回值:0,接收完成;其他,錯誤代碼
u8 Nrf24l01RxPacket(u8 *rxbuf)
{
u8 sta;
Spi2SetSpeed(SPI_BaudRatePrescaler_8); //spi速度為9Mhz(24L01的最大SPI時鍾為10Mhz)
sta=Nrf24l01ReadReg(STATUS); //讀取狀態寄存器的值
Nrf24l01WriteReg(STATUS,sta); //清除TX_DS或MAX_RT中斷標志
if(sta&RX_OK)//接收到數據
{
Nrf24l01ReadBuf(RD_RX_PLOAD,rxbuf,RX_PLOAD_WIDTH);//讀取數據
Nrf24l01WriteReg(FLUSH_RX,0xff);//清除RX FIFO寄存器
return 0;
}
return 1;//沒收到任何數據
}
