《NRF24L01的C51单片机讲解.doc》由会员分享,可在线阅读,更多相关《NRF24L01的C51单片机讲解.doc(12页珍藏版)》请在三一办公上搜索。
1、#include #include /*/*NRF24L01 的管脚定义,以及在本程序中的应用,VCC接3.3V电源,可以通过5V用电压转换芯片/*得到,NC 管脚可以接可以不接,暂时没用途。本程序应用于51或者52单片机,是两个模块进行通讯/*成功的简单指示,现象是:模块1的 KEY1 对应模块1的LED1 和模块2的LED3 ,模块1的 KEY2 对应模/*块1的LED2 和模块2的LED4,发过来也对应。/*/typedef unsigned char uchar;typedef unsigned char uint;/*NRF24L01端口定义*/=P13; sbit MOSI=P12
2、; sbitSCK =P11; sbitCSN=P10; sbitIRQ=P32;/数字输入(可屏蔽中断)/*按键*/sbitKEY1=P27;/按键S1sbitKEY2=P22;/按键S2/*数码管位选*/sbitled1=P10;/LED0sbitled2=P11;/LED1sbit led3 =P12; /LED2sbit led4 =P13;/LED3sbit led5 =P14;/LED4/*NRF24L01*/#define TX_ADR_WIDTH 5 / 5 uints TX address width#define RX_ADR_WIDTH 5 / 5 uints RX ad
3、dress width#define TX_PLOAD_WIDTH 20 / 20 uints TX payload#define RX_PLOAD_WIDTH 20 / 20 uints TX payloaduint const TX_ADDRESSTX_ADR_WIDTH= 0x34,0x43,0x10,0x10,0x01;/本地地址uint const RX_ADDRESSRX_ADR_WIDTH= 0x34,0x43,0x10,0x10,0x01;/接收地址/*NRF24L01寄存器指令*/#define READ_REG 0x00 / 读寄存器指令#define WRITE_REG
4、0x20/ 写寄存器指令#define RD_RX_PLOAD 0x61 / 读取接收数据指令 读RX 有效数据#define WR_TX_PLOAD 0xA0 / 写待发数据指令 写TX 有效数据#define FLUSH_TX 0xE1 / 冲洗发送 FIFO指令 /清除TX FIFO 寄存器应用于发射模式下#define FLUSH_RX 0xE2 / 冲洗接收 FIFO指令 /清除RX FIFO 寄存器应用于接收模式下#define REUSE_TX_PL 0xE3 / 定义重复装载数据指令 /重新使用上一包有效数据#define NOP 0xFF / 保留/*SPI(nRF24L01
5、)寄存器地址*/#define CONFIG 0x00 / 配置收发状态,CRC校验模式以及收发状态响应方式#define EN_AA 0x01 / 自动应答功能设置 /使能自动应答功能 /此功能禁止后可与nRF2401 通讯#define EN_RXADDR 0x02 / 可用信道设置 /接收地址允许#define SETUP_AW 0x03 / 收发地址宽度设置#define SETUP_RETR 0x04 / 自动重发功能设置#define RF_CH 0x05 / 工作频率设置#define RF_SETUP 0x06 / 发射速率、功耗功能设置#define STATUS 0x07
6、/ 状态寄存器#define OBSERVE_TX 0x08 / 发送监测功能#define CD 0x09 / 地址检测 #define RX_ADDR_P0 0x0A / 频道0接收数据地址 数据通道0 接收地址#define RX_ADDR_P1 0x0B / 频道1接收数据地址#define RX_ADDR_P2 0x0C / 频道2接收数据地址#define RX_ADDR_P3 0x0D / 频道3接收数据地址#define RX_ADDR_P4 0x0E / 频道4接收数据地址#define RX_ADDR_P5 0x0F / 频道5接收数据地址#define TX_ADDR 0
7、x10 / 发送地址寄存器#define RX_PW_P0 0x11 / 接收频道0接收数据长度#define RX_PW_P1 0x12 / 接收频道1接收数据长度#define RX_PW_P2 0x13 / 接收频道2接收数据长度#define RX_PW_P3 0x14 / 接收频道3接收数据长度#define RX_PW_P4 0x15 / 接收频道4接收数据长度#define RX_PW_P5 0x16 / 接收频道5接收数据长度#define FIFO_STATUS 0x17 / FIFO栈入栈出状态寄存器设置 /FIFO 状态寄存器/*函数声明 */void Delay(uns
8、igned int s); /大延时void inerDelay_us(unsigned char n);/小延时void init_NRF24L01(void);/NRF24L01 初始化uint SPI_RW(uint dat);/根据SPI协议,写一字节数据到nRF24L01,同时从nRF24L01读出一字节uchar SPI_Read(uchar reg);/从reg寄存器读一字节void SetRX_Mode(void);/数据接收配置uint SPI_RW_Reg(uchar reg, uchar value);/写数据value到reg寄存器uint SPI_Read_Buf(u
9、char reg, uchar *pBuf, uchar uchars); /从reg寄存器读出bytes个字节,通常用来 /读取接收通道数据或接收/发送地址uint SPI_Write_Buf(uchar reg, uchar *pBuf, uchar uchars); /把pBuf缓存中的数据写入到nRF24L01,通常用来写入发/射通道数据或接收/发送地址unsigned char nRF24L01_RxPacket(unsigned char* rx_buf);/数据读取后放入rx_buf接收缓冲区中void nRF24L01_TxPacket(unsigned char * tx_b
10、uf);/发送 tx_buf中数据/*长延时*/void Delay(unsigned int s)unsigned int i;for(i=0; is; i+);for(i=0; i0;n-)_nop_();/*/*NRF24L01初始化/*/void init_NRF24L01(void) inerDelay_us(100);CE=0; / 芯片使能CSN=1; / 禁止 SPISCK=0; / SPI时钟置低SPI_Write_Buf(WRITE_REG + TX_ADDR, TX_ADDRESS, TX_ADR_WIDTH); / 写本地地址/ 发送地址先写低字节 本机地址 长度SPI
11、_Write_Buf(WRITE_REG + RX_ADDR_P0, RX_ADDRESS, RX_ADR_WIDTH); / 写接收端地址SPI_RW_Reg(WRITE_REG + EN_AA, 0x01); / 频道0自动ACK应答允许SPI_RW_Reg(WRITE_REG + EN_RXADDR, 0x01); / 允许接收地址只有频道0,如果需要多频道可以参考Page21 SPI_RW_Reg(WRITE_REG + RF_CH, 0); / 设置信道工作为2.4GHZ,收发必须一致SPI_RW_Reg(WRITE_REG + RX_PW_P0, RX_PLOAD_WIDTH);
12、/设置接收数据长度,本次设置为32字节SPI_RW_Reg(WRITE_REG + RF_SETUP, 0x07); /设置发射速率为1MHZ,发射功率为最大值0dB/*/*函数:uint SPI_RW(uint uchar)/*功能:NRF24L01的SPI写时序-根据SPI协议,写一字节数据到nRF24L01,同时从nRF24L01 读出一字节/*要读/写的是最低字节的高位*/uint SPI_ReadWrite(uint dat)uint i;for(i=0;i8;i+) / 循环8次MOSI = (dat & 0x80); / dat的最高位输出到MOSI MSB to MOSIdat
13、 = (dat 1); / 从右向左进一位 shift next bit into MSB.SCK = 1; / 拉高SCK,nRF24L01从MOSI读入1位数据,同时从MISO输出1位数据 Set SCK high.dat |= MISO; /读MISO到 dat 最低位 capture current MISO bitSCK = 0; / SCK置低 .then set SCK low again return(dat); /返回读出的一字节 return read dat/*/*函数:uchar SPI_Read_byte(uchar reg)/*功能:NRF24L01的SPI时序-从
14、reg寄存器读一字节/*/uchar SPI_Read (uchar reg)uchar reg_val;CSN = 0; /CSN置低,开始传输数据 CSN low, initialize SPI communication.SPI_RW(reg); /选择寄存器 Select register to read from. reg_val = SPI_RW(0); /然后从该寄存器读数据 /#define READ_REG 0x00 / 读寄存器指令 CSN = 1; /CSN拉高,结束数据传 return(reg_val); /返回寄存器数据 return register value/*
15、/* uint SPI_Write_byte(uchar reg, uchar value)/*功能:NRF24L01读写寄存器函数/*描述:写数据value到reg寄存器/*/uint SPI_RW_Reg(uchar reg, uchar value)uchar status;CSN = 0; / CSN置低,开始传输数据 CSN low, init SPI transactionstatus = SPI_RW(reg); / 选择寄存器,同时返回状态字 select registerSPI_RW(value); / 然后写数据到该寄存器 .and write value to it.CS
16、N = 1; / CSN拉高,结束数据传输 CSN high againreturn(status); / 返回状态寄存器 return nRF24L01 status uchar/*/*函数:uint SPI_Read_Buf(uchar reg, uchar *pBuf, uchar uchars)/*功能: 用于读数据,reg:为寄存器地址,pBuf:为待读出数据地址,uchars:读出数据的个数/*描述: 从reg寄存器读出bytes个字节,通常用来读取接收通道数据或接收/发送地址/*/uint SPI_Read_Buf(uchar reg, uchar *pBuf, uchar uc
17、hars)uint status,i;CSN = 0; /CSN置低,开始传输数据 Set CSN low, init SPI tranactionstatus = SPI_RW(reg); /选择寄存器,同时返回状态字 Select register to write to and read status ucharfor(i=0;iuchars;i+)pBufi = SPI_RW(0); /逐个字节从nRF24L01读出CSN = 1; /CSN拉高,结束数据传输 return(status); /返回状态寄存器 return nRF24L01 status uchar/*/*函数:uin
18、t SPI_Write_Buf(uchar reg, uchar *pBuf, uchar uchars)/*功能: 用于写数据:为寄存器地址,pBuf:为待写入数据地址,uchars:写入数据的个数/*描述:把pBuf缓存中的数据写入到nRF24L01,通常用来写入发射通道数据或接收/发送地址/*/uint SPI_Write_Buf(uchar reg, uchar *pBuf, uchar uchars)uint status,i;CSN = 0; /CSN置低,开始传输数据 status = SPI_RW(reg); /选择寄存器,同时返回状态字inerDelay_us(10); fo
19、r(i=0; iuchars; i+)SPI_RW(*pBuf+);/逐个字节写入nRF24L01CSN = 1; /CSN拉高,结束数据传输return(status); /返回状态寄存器/*/*函数:void SetRX_Mode(void)/*功能:数据接收配置/*/void SetRX_Mode(void)CE=0;/待机模式SPI_RW_Reg(WRITE_REG + CONFIG, 0x0f);/CRC使能,16位CRC校验,上电,接收模式CE = 1; / 拉高CE启动接收设备inerDelay_us(130);/*/*函数:unsigned char nRF24L01_RxPa
20、cket(unsigned char *rx_buf)/*功能:数据读取后放入rx_buf接收缓冲区中/*/unsigned char nRF24L01_RxPacket(unsigned char* rx_buf) unsigned char revale=0;sta=SPI_Read(STATUS);/ 读取状态寄存其来判断数据接收状况 /#define STATUS 0x07 / 状态寄存器if(RX_DR)/ 判断是否接收到数据 /RX_DR 为 sta 的第六位当接收到有效数据后置一 CE = 0;/SPI使能SPI_Read_Buf(RD_RX_PLOAD,rx_buf,TX_PL
21、OAD_WIDTH);/ read receive payload from RX_FIFO buffer /#define RD_RX_PLOAD 0x61 / 读取接收数据指令/#define TX_PLOAD_WIDTH 20 revale =1;/读取数据完成标志SPI_RW_Reg(WRITE_REG+STATUS,sta); /接收到数据后RX_DR,TX_DS,MAX_PT都置高为1,通过写1来清楚中断标志 #define WRITE_REG 0x20/ 写寄存器指令return revale;/*/*函数:void nRF24L01_TxPacket(unsigned char
22、 * tx_buf)/*功能:发送 tx_buf中数据/*/void nRF24L01_TxPacket(unsigned char * tx_buf)CE=0;/StandBy I模式SPI_Write_Buf(WRITE_REG + RX_ADDR_P0, TX_ADDRESS, TX_ADR_WIDTH); / 装载接收端地址 /#define RX_ADDR_P0 0x0A / 频道0接收数据地址 数据通道0 接收地址/ uint const TX_ADDRESSTX_ADR_WIDTH= 0x34,0x43,0x10,0x10,0x01;/本地地址 SPI_Write_Buf(WR_
23、TX_PLOAD, tx_buf, TX_PLOAD_WIDTH);/ 装载数据SPI_RW_Reg(WRITE_REG + CONFIG, 0x0e); / IRQ收发完成中断响应,16位CRC,主发送CE=1;/置高CE,激发数据发送inerDelay_us(10);/*主函数*/void main(void)unsigned char tf =0;unsigned char TxBuf20=0; / 要发送的数组unsigned char RxBuf20=0; / 接收的数据 数组 init_NRF24L01() ;/模块初始化led1=1;led2=1;led3 =1;led4 =1;
24、/led 灯关闭Delay(1000);while(1) if(KEY1 =0 ) /按键 1 按下 TxBuf1 = 1 ;/赋值 tf = 1 ;led1=0;/本地led 灯闪烁Delay(200);led1=1;Delay(200); if(KEY2 =0 ) /按键 2 按下 TxBuf2 =1 ;/赋值tf = 1 ;led2=0;/本地led 灯闪烁Delay(200);led2=1;Delay(200); if (tf=1)/有键按下 nRF24L01_TxPacket(TxBuf);/发送数据 Transmit Tx buffer dataTxBuf1 = 0x00;/清零T
25、xBuf2 = 0x00;tf=0;Delay(1000); SetRX_Mode();/设置成接受模式RxBuf1 = 0x00; /接收的数组相应位清零RxBuf2 = 0x00; Delay(1000);nRF24L01_RxPacket(RxBuf); /接收数据if(RxBuf1|RxBuf2)if(RxBuf1=1) led3=RxBuf0;if(RxBuf2=1)led4=RxBuf4;Delay(3000);/old is 1000RxBuf1 = 0x00; /清零RxBuf2 = 0x00;led3=1;/关灯led4=1;本程序存在的问题:反应不够灵敏,当在按键1和按键2
26、之间切换的时候,对方的灯闪烁会有一定的延时,另外本程序没有消除按键的抖动。对部分函数的解释:uint SPI_RW(uint dat) 最基本的函数,完成 GPIO模拟 SPI 的功能。将输出字节(MOSI)从 MSB 循环输出,同时将输入字节(MISO)从 LSB 循环移入。上升沿读入,下降沿输出。 (从 SCK被初始化为低电平可以判断出)uchar SPI_Read(uchar reg);/从reg寄存器读一字节 读取寄存器值的函数:基本思路就是通过 READ_REG命令(也就是 0x00+寄存器地址) ,把寄存器中的值读出来。对于函数来说也就是把 reg 寄存器的值读到 reg_val
27、中去。uint SPI_RW_Reg(uchar reg, uchar value);/写数据value到reg寄存器 寄存器访问函数:用来设置 24L01 的寄存器的值。基本思路就是通过 WRITE_REG命令(也就是 0x20+寄存器地址)把要设定的值写到相应的寄存器地址里面去,并读取返回值。对于函数来说也就是把 value值写到 reg 寄存器中。需要注意的是,访问 NRF24L01 之前首先要 enable 芯片(CSN=0; ) ,访问完了以后再 disable芯片(CSN=1; )。uint SPI_Read_Buf(uchar reg, uchar *pBuf, uchar uc
28、hars); /从reg寄存器读出bytes个字节,通常用来 /读取接收通道数据或接收/发送地址 接收缓冲区访问函数:主要用来在接收时读取 FIFO 缓冲区中的值。基本思路就是通过READ_REG命令把数据从接收 FIFO(RD_RX_PLOAD)中读出并存到数组里面去。uint SPI_Write_Buf(uchar reg, uchar *pBuf, uchar uchars); /把pBuf缓存中的数据写入到nRF24L01,通常 /用来写入发发射缓冲区访问函数:主要用来把数组里的数放到发射 FIFO缓冲区中。基本思路就是通过WRITE_REG命令把数据存到发射 FIFO(WR_TX_P
29、LOAD)中去。Tx 模式初始化过程1)写 Tx 节点的地址 TX_ADDR2)写 Rx 节点的地址(主要是为了使能 Auto Ack) RX_ADDR_P03)使能 AUTO ACK EN_AA4)使能 PIPE 0 EN_RXADDR5)配置自动重发次数 SETUP_RETR6)选择通信频率 RF_CH7)配置发射参数(低噪放大器增益、发射功率、无线速率) RF_SETUP8 ) 选择通道0 有效数据宽度 Rx_Pw_P09)配置 24L01 的基本参数以及切换工作模式 CONFIG。Rx 模式初始化过程:初始化步骤 24L01 相关寄存器1)写 Rx 节点的地址 RX_ADDR_P02)使能 AUTO ACK EN_AA3)使能 PIPE 0 EN_RXADDR4)选择通信频率 RF_CH5) 选择通道0 有效数据宽度 Rx_Pw_P06)配置发射参数(低噪放大器增益、发射功率、无线速率) RF_SETUP7)配置 24L01 的基本参数以及切换工作模式 CONFIG。