NRF24L01+实现一对一数据双向传输_nrf24l01双向收发_ZuSuKuang
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);//写RX节点地址
NRF24L01_Write_Reg(NRF_WRITE_REG+EN_RXADDR,0x01); //使能通道0的接收地址
NRF24L01_Write_Reg(NRF_WRITE_REG+RF_CH,40); //设置RF通信频率
NRF24L01_Write_Reg(NRF_WRITE_REG+RX_PW_P0,RX_PLOAD_WIDTH);//选择通道0的有效数据宽度
NRF24L01_Write_Reg(NRF_WRITE_REG+RF_SETUP,0x0f); //设置TX发射参数,0db增益,2Mbps,低噪声增益开启
NRF24L01_Write_Reg(NRF_WRITE_REG+EN_AA,0x01); //使能通道0的自动应答
NRF24L01_Write_Reg(NRF_WRITE_REG+FEATURE,0x06); //使能动态负载(收发数据)长度
NRF24L01_Write_Reg(NRF_WRITE_REG+DYNPD,0x01); //使能通道0动态负载长度
NRF24L01_Write_Reg(NRF_WRITE_REG+CONFIG, 0x0f); //配置基本工作模式的参数;PWR_UP,EN_CRC,16BIT_CRC,接收模式
NRF24L01_CE=1;
发送方
NRF24L01_CE=0;
NRF24L01_Write_Buf(NRF_WRITE_REG+TX_ADDR,(u8*)TX_ADDRESS,TX_ADR_WIDTH);//写TX节点地址
NRF24L01_Write_Buf(NRF_WRITE_REG+RX_ADDR_P0,(u8*)RX_ADDRESS,RX_ADR_WIDTH); //设置TX节点地址,主要为了使能ACK
NRF24L01_Write_Reg(NRF_WRITE_REG+EN_RXADDR,0x01); //使能通道0的接收地址
NRF24L01_Write_Reg(NRF_WRITE_REG+SETUP_RETR,0x1a);//设置自动重发间隔时间:500us + 86us;最大自动重发次数:10次
NRF24L01_Write_Reg(NRF_WRITE_REG+RF_CH,40); //设置RF通道为40
NRF24L01_Write_Reg(NRF_WRITE_REG+RF_SETUP,0x0f); //设置TX发射参数,0db增益,2Mbps,低噪声增益开启
NRF24L01_Write_Reg(NRF_WRITE_REG+FEATURE,0x07); //使能动态负载(收发数据)长度
NRF24L01_Write_Reg(NRF_WRITE_REG+DYNPD,0x01); //使能通道0动态负载长度
NRF24L01_Write_Reg(NRF_WRITE_REG+EN_AA,0x01); //使能通道0的自动应答
NRF24L01_Write_Reg(NRF_WRITE_REG+CONFIG,0x0e); //配置基本工作模式的参数;PWR_UP,EN_CRC,16BIT_CRC,接收模式,开启所有中断
NRF24L01_CE=1;//CE为高,10us后启动发送
以上配置经过测试是可以使用的,在NRF24L01+之间,SI24R1之间,NRF24L01和SI24R1之间都可以进行双向通信。
收发双方数据的处理
首先是写两个发送数据的函数(其实这两个函数是把数据写入到发送缓冲区,而不是实现数据的发送)
一个是发送端主动发送数据给接收端:
void nrf_txPacket(u8 *txbuf,u8 len)
{
NRF24L01_CE=0;
NRF24L01_Write_Buf(WR_TX_PLOAD,txbuf,len);//写数据到TX BUF
NRF24L01_CE=1;
}
另一个是接收端回复带负载数据的ACK信号(把要回传的数据写入到发送缓冲区,等待接收端自动发送应答信号)
void nrf_txPacket_AP(u8 *txbuf,u8 len)
{
NRF24L01_CE=0;
NRF24L01_Write_Buf(W_ACK_PAYLOAD(0),txbuf,len);//写数据到TX BUF
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); //清除TX_FIFO
//在这里对发送完的数据进行数据处理
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);//发送ACK Payload,数据长度为1
NRF24L01_Write_Reg(NRF_WRITE_REG + STATUS,RX_OK);//清除发送完成标志
NRF24L01_Write_Reg(FLUSH_RX,0xff); //清除RX_FIFO
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); //清除TX_FIFO
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)//大约1s钟改变一次状态
{
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)//大约1s钟改变一次状态
{
t=0;
LED0=!LED0;
nrf_txPacket(NRF_TX_DATA,1);
}
}
测试效果
最后,本人没什么写博客的经验,表达不够清晰,写的也比较水,为的是记录一下调试的经历,如果表述中有什么错误的地方欢迎各位大佬批评指正。想知道更详细的内容需要查阅一下数据手册,了解一下NRF24L01+/SI24R1的工作流程。
相关文章
- MySQL-连接池_demolife1_mysql连接池
- Windows环境搭建canal服务教程_生产队队长_windows 安装canal
- MySQL group by是如何使用索引的?_编了个程
- Canal安装与配置(保姆级教程)_万家林_canal 配置
- QGIS+ PostgreSQL/PostGIS + GeoServer + Tomcat +Openlayers一条龙配置_Regan_life
- 大数据_数据库(DBMS、DB、SQL )_D大调奏鸣曲_第七序章__大数据 数据库
- 通俗易懂的学会SQL,30道练习题(PostgreSQL基础版)_IT邦德_postgresql 题库
- 35-Spark Streaming反压机制、Spark的数据倾斜的解决和Kylin的简单介绍_大数据下的画像人
- PostgreSQL 创建数据库_瀚高PG实验室_pg建库语句
- 简单有用的jar包下载方法及地址_努力成为大佬的小垃圾_jar包下载地址
- mysql用了索引为什么还是查询很慢?_popofzk_mysql加了索引查询还是很慢
- MybatisPlus 字段更新策略 FieldStrategy使用_kangfu_521_mybatisplus更新策略
- mybatis-plus 关于savebatch,saveorupdatebatch遇到的坑及解决办法_青藤追影_saveorupdatebatch
- mybatis1之xml与注解(基于一对多关系案例)+ 包含多参数、多返回值情况的处理_V I.
- 技术分享 | ProxySQL 搭配 MySQL HA (下)_ActionTech
- LDAP??实现用户统一登录管理_菜鸟琪