NRF24L01+实现一对一数据双向传输
- 目录
- 说明
- 带负载数据ACK的双向通信
- 配置NRF24L01+的收发程序
- 收发双方数据的处理
- 测试代码和结果
目录
说明
最近在diy四轴飞行器的时候,需要实现四轴和遥控器之间的双向通信。手头上用的模块是NRF24L01+和SI24R1,这两个芯片的引脚功能相同,不仅硬件上可以直接进行替换使用,程序往往还可以互用(因为还是有点差别),两个芯片的差别很小,其中一个是SI24R1的功率最大达到7dB,而NRF24L01+最大是0dB,这个在配置参数的时候要注意。
NRF24L01+和SI24R1都可以配置为发送或接收模式,为了减少打字的麻烦,下文全都以NRF24L01+来写。实现四轴和遥控器的双向通信,可以让NRF24L01+不断在收/发模式之间直接进行切换,小马哥的四轴用的就是这种方式,但我用HAL库实现这种方式的时候,会出现这种问题:两者可以进行双向的数据传输,但一会儿之后就不能传输了,我也不清楚是怎么回事。
后来查询芯片数据手册,仔细研究NRF24L01+的工作方式之后,发现NRF24L01+工作在ACK模式时,发送端发送数据给接收端时,接收端收到并检验数据无误后,会回复一个ACK信号给发送端,收到ACK的发送端就认为数据发送完成,并产生TX_DS中断,这就是一个应答机制。而接收端回复的ACK信号可以是选择带负载数据的,利用这一点,就可以把接收端要回传的数据发送回发送端,以此来实现双向数据传输。
带负载数据ACK的双向通信
要使用带负载数据的ACK信号(ACKPAYLOAD)需要配置FEATURE寄存器中的EN_ACK_PAY位,同时收发双方要开启动态负载长度(通过配置DYNPD和FEATURE寄存器来实现)。
配置NRF24L01+的收发程序
程序改自正点原子的实验例程。
接收方
NRF24L01_CE=0;
NRF24L01_Write_Buf(NRF_WRITE_REG+RX_ADDR_P0,(u8*)RX_ADDRESS,RX_ADR_WIDTH);
NRF24L01_Write_Reg(NRF_WRITE_REG+EN_RXADDR,0x01);
NRF24L01_Write_Reg(NRF_WRITE_REG+RF_CH,40);
NRF24L01_Write_Reg(NRF_WRITE_REG+RX_PW_P0,RX_PLOAD_WIDTH);
NRF24L01_Write_Reg(NRF_WRITE_REG+RF_SETUP,0x0f);
NRF24L01_Write_Reg(NRF_WRITE_REG+EN_AA,0x01);
NRF24L01_Write_Reg(NRF_WRITE_REG+FEATURE,0x06);
NRF24L01_Write_Reg(NRF_WRITE_REG+DYNPD,0x01);
NRF24L01_Write_Reg(NRF_WRITE_REG+CONFIG, 0x0f);
NRF24L01_CE=1;
发送方
NRF24L01_CE=0;
NRF24L01_Write_Buf(NRF_WRITE_REG+TX_ADDR,(u8*)TX_ADDRESS,TX_ADR_WIDTH);
NRF24L01_Write_Buf(NRF_WRITE_REG+RX_ADDR_P0,(u8*)RX_ADDRESS,RX_ADR_WIDTH);
NRF24L01_Write_Reg(NRF_WRITE_REG+EN_RXADDR,0x01);
NRF24L01_Write_Reg(NRF_WRITE_REG+SETUP_RETR,0x1a);
NRF24L01_Write_Reg(NRF_WRITE_REG+RF_CH,40);
NRF24L01_Write_Reg(NRF_WRITE_REG+RF_SETUP,0x0f);
NRF24L01_Write_Reg(NRF_WRITE_REG+FEATURE,0x07);
NRF24L01_Write_Reg(NRF_WRITE_REG+DYNPD,0x01);
NRF24L01_Write_Reg(NRF_WRITE_REG+EN_AA,0x01);
NRF24L01_Write_Reg(NRF_WRITE_REG+CONFIG,0x0e);
NRF24L01_CE=1;
以上配置经过测试是可以使用的,在NRF24L01+之间,SI24R1之间,NRF24L01和SI24R1之间都可以进行双向通信。
收发双方数据的处理
首先是写两个发送数据的函数(其实这两个函数是把数据写入到发送缓冲区,而不是实现数据的发送)
一个是发送端主动发送数据给接收端:
void nrf_txPacket(u8 *txbuf,u8 len)
{
NRF24L01_CE=0;
NRF24L01_Write_Buf(WR_TX_PLOAD,txbuf,len);
NRF24L01_CE=1;
}
另一个是接收端回复带负载数据的ACK信号(把要回传的数据写入到发送缓冲区,等待接收端自动发送应答信号)
void nrf_txPacket_AP(u8 *txbuf,u8 len)
{
NRF24L01_CE=0;
NRF24L01_Write_Buf(W_ACK_PAYLOAD(0),txbuf,len);
NRF24L01_CE=1;
}
然后是处理数据的函数,我是在中断回调函数里处理的
u8 sta = NRF24L01_Read_Reg(NRF_READ_REG + STATUS);
if(sta & TX_OK)
{
NRF24L01_CE = 0;
NRF24L01_Write_Reg(NRF_WRITE_REG + STATUS,TX_OK);
NRF24L01_Write_Reg(FLUSH_TX,0xff);
NRF_TX_DATA[0]++;
NRF24L01_CE = 1;
}
if(sta & RX_OK)
{
NRF24L01_CE=0;
u8 len = NRF24L01_Read_Reg(R_RX_PL_WID);
if(len>0 && len<33)
{
NRF24L01_Read_Buf(RD_RX_PLOAD,NRF_RX_DATA,len);
}
nrf_txPacket_AP(NRF_TX_DATA,1);
NRF24L01_Write_Reg(NRF_WRITE_REG + STATUS,RX_OK);
NRF24L01_Write_Reg(FLUSH_RX,0xff);
NRF24L01_CE=1;
}
if(sta & MAX_TX)
{
NRF24L01_CE = 0;
NRF24L01_Write_Reg(NRF_WRITE_REG+STATUS,MAX_TX);
NRF24L01_Write_Reg(FLUSH_TX,0xff);
NRF24L01_CE = 1;
}
测试代码和结果
接收端的代码:显示接收端接收到的和发送出去的数据
while(1)
{
LCD_ShowxNum(30+14*8,170,NRF_RX_DATA[0],3,16,0);
LCD_ShowxNum(30+14*8,190,NRF_TX_DATA[0],3,16,0);
delay_ms(1);
t++;
if(t==1000)
{
t=0;
LED0=!LED0;
}
}
发送端的代码:显示发送端发送的数据和接收到的数据
while(1)
{
LCD_ShowxNum(30+14*8,170,NRF_RX_DATA[0],3,16,0);
LCD_ShowxNum(30+14*8,190,NRF_TX_DATA[0]++,3,16,0);
delay_ms(1);
t++;
if(t==1000)
{
t=0;
LED0=!LED0;
nrf_txPacket(NRF_TX_DATA,1);
}
}
测试效果
最后,本人没什么写博客的经验,表达不够清晰,写的也比较水,为的是记录一下调试的经历,如果表述中有什么错误的地方欢迎各位大佬批评指正。想知道更详细的内容需要查阅一下数据手册,了解一下NRF24L01+/SI24R1的工作流程。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)