nRF24L01+接收异常问题综述

在调试nRF24L01+无线收发模块的时候,最具标志性的环节就是在接收端可以收到数据。在实际应用调试中,会出现很多意想不到的情况,造成nRF24L01+模块接收端无法收到发送端发出的数据。

根据以往对nRF24L01+模块的N多次调试的经验,总结大致可以分为如下几种情况:

现象1:一次也收不到发送端发送的数据

现象2:只能在发送端或接收端重新上电的时候收到一次

现象3:偶尔在发送完数据转为接收模式后就不能接收了

现象4:大功率带PA的模块工作一段时间就不能接收了

现象5:无规律偶发不能接收

下面将根据这5中现象分别有针对性的分享实战中的解决方法。

如何快速判断nRF24L01+通信失败问题是出在接收端

在调试nRF24L01+模块通信过程中,当发生通信失败时,如何才能快速确定问题是出在接收端,而不是发送端的问题呢?这里给他家推荐个方法:

首先使用厂家提供的测试代码,不做任何改动,烧录到两个模块中,如果硬件电路没有问题,一般都是可以正常发送接收的,如发生不能通信,请检查单片机型号变动带来的IO口设置是否正确,千万不要随意改动逻辑代码和nRF24L01+驱动部分代码,只查找IO口相关配置的宏定义修改正确即可。

如果这样可以通信,说明模块硬件电路没有问题。否则问题出在硬件电路上,仔细检查电路部分,参见下面的“正常接收数据时硬件电路必需的基本保障”。

当利用厂家提供的测试代码可以通信之后,把作为接收端的模块里的代码烧录成自己的代码。烧录前参照厂家测试代码中的接收配置部分,更改你项目中的频道、速率、地址、是否自动应答等,与测试项目保持一致。

经过这样调整后,如果还是收不到,那就是你的接收端代码有问题,参见下面的几种现象。

正常接收数据时硬件电路必需的基本保障

在调试代码前,首先要保证硬件电路是正常的,下面是必需具备的前提条件:

1、单片机与模块之间的IO口电路连接正常。单片机代码SPI脚序配置与电路连接实际相符。

2、nRF24L01+模块电源脚附近(越近越好)有滤波电容,最好是两个,一个104,一个22uF或以上。

3、处于接收模式时,CE引脚应为高电平(足够高,3.1V以上)。

4、电源电压稳定在3.3V,波纹低于80mV,波纹越小越好。

以上条件必需具备,否则不能接收那就再正常不过了。

现象1:一次也收不到发送端发送的数据

这种现象多数发生在我们最初调试模块的时候,那么我们要分两个方向来排除。

先排除硬件部分,参照上面“正常接收数据时硬件电路必需的基本保障”一节提到的,仔细检查有没有不能满足的。根据以往经验,最容易被大家忽视的就是nRF24L01+模块电源脚附近的两个电容,如果已经有了,那也更换一套新的试试,排除元件本身问题,最好用电容表或万用表电容档测量一下。如果有但是距离模块不是很近(应小于0.5CM的距离),最好直接在模块引脚上先临时焊上一个,以排除这个原因。

然后测量CE脚是否为3.3V,如果是大于0V且低于3.1V以下,说明CE电平不正常,应检查单片机IO口的上拉能力。如果单片机IO口模式是可以配置上拉模式的(如STC单片机),请使用推挽模式。如果单片机是不能配置上拉模式的,请加上拉电阻,以满足在CE脚拉高时,能维持到3.1V以上的电平。

如果硬件部分没有问题,CE脚也能正常上拉,那重点检查设置接收模式的代码,参考代码如下:

/*-----------------------------------------------------------------------------
函数名称:NRF24_RxMode
输入参数:pSelfAddr:本机硬件地址;ch:通信频道
功能描述:设置nRF24L01+工作在接收模式
------------------------------------------------------------------------------*/
void NRF24_RxMode(U8 *pSelfAddr, U8 ch){
CE = 0; // 拉低CE进入配置模式
nRF24L01P_Write_Buf(WRITE_REG + RX_ADDR_P0, pSelfAddr, TX_ADR_WIDTH); // 设置接收设备自己的通道0地址
nRF24L01P_Write_Reg(WRITE_REG + EN_AA, 0x01); // 使能接收通道0自动应答
nRF24L01P_Write_Reg(WRITE_REG + EN_RXADDR, 0x01); // 使能接收通道0
nRF24L01P_Write_Reg(WRITE_REG + RF_CH, ch); // 选择射频通道为变量ch
nRF24L01P_Write_Reg(WRITE_REG + RX_PW_P0, TX_PLOAD_WIDTH); // 设置接收通道0有效数据宽度
nRF24L01P_Write_Reg(WRITE_REG + RF_SETUP, RF_date_rate|dBm); // 设置数据传输率、发射功率
nRF24L01P_Write_Reg(WRITE_REG + CONFIG, 0x0f); // 使能16位CRC校验,上电,接收模式
nRF24L01P_Write_Reg(WRITE_REG + STATUS, 0xff); // 清除所有的中断标志位
CE = 1; // 拉高CE启动接收设备
}

在上述代码中,要注意:

pSelfAddr:接收端自己的硬件设备地址,要与发送端的发送目标地址一致,否则收不到。

ch:射频工作频道号,可设置值为1-125,要与发送端保持一致,否则收不到。

RF_date_rate:数据的传输速率,可设置值为0x00、0x08、0x20,分别代表1Mbds、2Mbds、250Kbds,必须与发送端的设置保持一致,否则收不到。

dBm:发射功率,在接收模式下没有实际作用,但设置值不能大于0x07,否则影响到速率的配置位。

TX_ADR_WIDTH:描述地址宽度,必须与发送端一致,建议测试时设置为5。

TX_PLOAD_WIDTH:描述传输数据宽度,必须与发送端一致,建议测试时设置为32。

现象2:只能在发送端或接收端重新上电的时候收到一次

原因1:一直发送相同的数据包,也就是每次发送的数据都是相同。

nRF24L01+的接收端首先是根据PID位来区分数据包是否相同的,如果第二次接收的PID与第一次相同,那就视为数据重发,会直接丢弃不处理,也不会产生接收成功的中断。

数据手册中说这个PID是每次写发送FIFO的时候会自动累加,也就是每写一次就会改变一次,但在多次的实验中(使用的是SI24R1模块),发现如果两次写入的是相同的内容,PID并没有变化,接收端会直接抛弃后面接收到的相同数据。

这样就产生了只能接收成功一次,然后就收不到了这个现象。重新上电后,所有寄存器的值都是重新配置的,之前的PID也不一样了,所以就可以再接收到一次,之后就又不能接收了。

解决方法:在你发送的数据内容中选一个字节让它每次都是变的,就不会出现了。

原因2、发送端发送速度比较快而连续,接收端处理比较慢切没有清接收FIFO。

发送端连续发送3组数据后,接收端的96字节缓冲器就会填满,这个时候如果没有读出,那就不会再接收了。发送端仍然以同样的速度再发送几个,在这个时候接收端虽然读出一组32个字节,如果处理的比较慢,那很快接收缓冲区可能被又填满了。

而接收端处理完逻辑代码再去查接收数据的时候,如中间有过模式转换,清除了中断标志,因没有再产生接收成功的中断标志(使用中断IRQ首先判断接收成功的,接收缓冲区满就不会再产生中断了),则认为没有收到数据,所以就再也收不到数据了。

这样就产生了只能接收一次就收不到了这个现象,重新上电后,所有寄存器的值都是重新配置的,中断和缓冲器都是被清除过,所以可以再接收。

解决方法:在每次收到数据读出之后,在处理逻辑完成后,如果经过接收发送模式转换的,转换后清除一下接收FIFO。

原因3、没有及时清除中断标志,接收一次后IRQ一直维持在低电平。

如果单片机使用外部中断,在接收到一次有效数据没有清除中断标志的话,再收到有效数据就不会再产生下一个中断。

解决方法:接收成功一次,清除一次中断。

下面单片机通过查询IRQ的方式识别是否收到数据的代码,结合中断与查询两种方式:

/*-----------------------------------------------------------------------------
函数名称:RF24_RxData
返回数据:是否收到数据,1收到,0未收到
功能描述:nRF24L01P+判断是否收到数据,若收到直接取出,应在主循环中调用
------------------------------------------------------------------------------*/
bit RF24_RxData(){
U8 state; if(IRQ == 0){ //有中断触发,提高CPU效率,减少SPI通讯量
state = nRF24L01P_Read_Reg(STATUS); //读取状态寄存器的值
nRF24L01P_Write_Reg(WR_STATUS, state); //清除RX_DS中断标志
if(state & RX_DR) //接收到数据
{
nRF24L01P_Read_Buf(RD_RX_PLOAD, RF24Buf, TX_PLOAD_WIDTH); //读取数据
nRF24L01P_Write_Reg(FLUSH_RX,0xFF); //清除RX FIFO寄存器
return TRUE;
}
}
return FALSE; //没收到任何数据
}

以上代码注意“清除RX_DS中断标志”和“清除RX FIFO寄存器”的作用,保证每次设置为接收的时候,都能使nRF24L01+全新开始接收。

现象3:偶尔在发送完数据转为接收模式后就不能接收了

原因1、发送失败后,没有清除发送FIFO寄存器,造成转接收模式时异常。

nRF24L01+在发送达到最大发送次数仍然没有收到ACK的时候(启用ACK的情况下),是不会自动清除发送缓冲区的。而在发送模式转到待机模式的时候,根据手册的状态图,必须是发送缓冲区没有数据的情况下,CE=0才可进入待机模式。在待机模式,才可以设置为接收模式。但是数据手册中文字介绍部分又说任何状态下,只要CE=0就可以进入待机模式,出现了描述矛盾。

我们在调试的时候,遇到了这个问题,经过N多次实验,在发送缓冲区还有数据的情况下,直接转接收模式,是会不稳定的,所以在发送结束后,如果是发送次数达到了最大值不再继续发送,一定要记得清洗TX_FIFO。

解决方法:发送完判断发送状态,如果是达到最大发送次数,则清洗TX_FIFO。

参考代码如下:

/*-----------------------------------------------------------------------------
函数名称:RF24_TxData
输入参数:*buf:待发送的数据缓冲区指针
返回数据:是否发送成功,1发送成功,0发送失败
功能描述:nRF24L01P+发送数据
------------------------------------------------------------------------------*/
bit RF24_TxData(U8 *buf){
U8 state; CE = 0; //使能24L01配置
nRF24L01P_Write_Buf(WR_TX_PLOAD, buf, TX_PLOAD_WIDTH); //写数据到TX FIFO,32个字节
CE = 1; //使能发送 while(IRQ == 1); //等待发送完成
state=nRF24L01P_Read_Reg(STATUS); //读取状态寄存器的值
nRF24L01P_Write_Reg(WR_STATUS, state); //清除TX_DS或MAX_RT中断标志
if(state&MAX_RT)
nRF24L01P_Write_Reg(FLUSH_TX, 0xff); //达到最大发送次数,清除TX FIFO寄存器
if(state&TX_DS)
return TRUE; //发送完成
return FALSE; //发送失败
}

原因2、在发送完一次就自动转为接收模式的代码逻辑下,循环发送时,中间收到3次及以上的数据。

因在发送一组数据就会自动置为接收(这样写的逻辑也是有好处的,可以避免某些地方忘记置为接收),那在发送下一组数据之前,是有一段时间间隔的,这个时候如果有数据进来,是可以接收的。但是上层代码并没有处理接收数据,也就是没有去读,而是循环发送完才会进入处理接收阶段。这样如果在循环发送期间受到3次数据,接收缓冲区就满了,而产生的中断也在每次转换模式的时候都被清除了。等循环结束,再判断是否有接收到数据的时候,因接收缓冲区满而不能再产生接收中断了,所以不能再收到数据了。

解决方法 :在每次设置接收模式的时候,清洗一下RX_FIFO。

原因3、置接收模式的代码没有操作所有相关寄存器,其他代码更改过相关寄存器。

在本次置为接收模式之前,其他代码可能更改过与接收相关的寄存器,造成与发送端不一致或更改为错误的值,造成不能正常接收。

解决方法:置为接收模式的函数,完整的操作一遍相关寄存器,这样可以规避这种问题。

现象4:大功率带PA的模块工作一段时间就不能接收了

经过测试多个厂家的多款不同nRF24L01+模块,发现带屏蔽罩并带功率放大的模块,在近距离密集应用的时候,损坏率比较高。PA会先过热然后接收不正常,接收模式下电流大增,表面温度会烫手。

建议劲量不要使用带PA的,如果必需使用,不要密集应用,尽量使用板载天线并不带屏蔽罩的。

这个是目前的实际应用测试经验,不代表全部是这样,不排除有的厂家带屏蔽罩的会更好用。

现象5:无规律偶发不能接收

以上问题都排除的话,如果还是偶尔会发生不能接收的情况,那就重点检查电源和滤波电容,建议更换一个电源,保证电源的低波纹,电压的稳定性要好。滤波电容质量要好,要尽量靠近模块,越近越好。

关于nRF24L01+作为接收端的的常见问题,先分享到这里,其他方面另外分享。

nRF24L01+不能接收或接收偶尔异常等问题实战分享的更多相关文章

  1. nRF24L01+启用自动应答ACK及自动重发的实战分享

    ACK模式(自动应答)功能的官方说明 当用W_TX_PAYLOAD命令对发送端TX FIFO写数据时,将数据打包后,数据包中包控制字段NO_ACK 标志位复位.接收端接收到一帧有效数据后, 产生RX_ ...

  2. 调用 SSPI 失败,请参见内部异常。接收到的消息异常,或格式不正确。

    完整异常信息: System.Security.Authentication.AuthenticationException: 调用 SSPI 失败,请参见内部异常. ---> System.C ...

  3. Provider:SSL提供程序,error:0 - 接收到的消息异常,或格式不正确

    引自 :http://www.cnblogs.com/liuguozhu2015/p/3413496.html 非常感谢这位同学 我用笔记本的sql客户端去连服务器,正常连接. 在页面中连接时,直接导 ...

  4. 已成功与服务器建立连接,但是在登录过程中发生错误。 (provider: SSL Provider, error: 0 - 接收到的消息异常,或格式不正确。)

    之前做好的asp.net部署后,发现 访问数据库时: 异常:已捕获: "已成功与服务器建立连接,但是在登录过程中发生错误. (provider: SSL Provider, error: 0 ...

  5. nRF24L01+组网方式及防撞(防冲突)机制的实战分享

    利用多个nRF24L01+模块组网通信的实现方式 这里讨论的组网方式,不包含使用6个通道实现的多对1通信方式,因其只限于6个发送端,局限性很大,可以附加其他技术实现更好的组网,暂时这里不讨论.这里分享 ...

  6. 记录一次排查使用HttpWebRequest发送请求的发生“基础连接已关闭:接收时发生错误”异常问题的过程

    描述:某次更新程序,需要给测试员MM测试,之前都是正常的,更新后给MM测试就报异常System.Net.WebException 基础连接已经关闭:接收时发生错误 -------> System ...

  7. VB中Winsock连续发送出现接收不到的异常问题解决方法

    VB里面用WINSOCK进行一对多连接的TCP连接时,经常需要群发消息给所有已连接的客户端.代码类似如下: Option Explicit Dim bytMsg() As Byte Private S ...

  8. tcp输入数据 慢速路径处理 && oob数据 接收 && 数据接收 tcp_data_queue

    大致的处理过程 TCP的接收流程:在tcp_v4_do_rcv中的相关处理(网卡收到报文触发)中,会首先通过tcp_check_urg设置tcp_sock的urg_data为TCP_URG_NOTYE ...

  9. ios wkwebview同步cookie ajax请求偶尔异常问题

    let config = WKWebViewConfiguration.init() config.preferences = WKPreferences.init() config.preferen ...

随机推荐

  1. 使用PrintWriter完成写操作 ,实现简易记事本工具

    package seday07; import java.io.BufferedWriter;import java.io.FileOutputStream;import java.io.IOExce ...

  2. PHP+Mysql统计文件下载次数实例

    PHP+Mysql统计文件下载次数实例,实现的原理也很简单,是通过前台点击链接download.php传参id,来更新点击次数. 获取文件列表: <?php require 'conn.php' ...

  3. Vue的MVVM框架理解

    图示 只上图,请不要怪楼主懒. 这是楼主梳理后画的,因为毕竟自己画的印象深刻,更觉得香啊. 黄线: 表示View->Model, 红线: 表示Model->View 具体代码,请查看Vue ...

  4. [转]RPA认证 Developer UIPath Certificate,细说uipath认证学习,Online Quiz和Practical Exam项目详解

    本文转自:https://blog.csdn.net/u010369735/article/details/88621195 UIPath,RPA里算是比较简单易操作的一款软件了,因为公司业务的需要, ...

  5. JavaWeb开发——软件国际化(动态元素国际化)

    软件国际化的第二个部分,就是动态元素国际化. 数值,货币,时间,日期等数据由于可能在程序运行时动态产生,所以无法像文字一样简单地将它们从应用程序中分离出来,而是需要特殊处理.Java 中提供了解决这些 ...

  6. Oracle 统计表空间和对象历史增长量

    最近7天内 每天(某个)表空间的增长量 col TS_NAME for a15 SELECT a.snap_id, a.rtime, c.tablespace_name ts_name, round( ...

  7. SSH agent 的使用 - 资料摘录

    下面是一些ssh agent的资料简要摘录,网路上的相关的文章已经很多了: ssh 推荐的登录方式是使用私钥登录.但是如果生成私钥的时候,设置了口令(passphrase),每次登录时需要输入口令也很 ...

  8. CodeForces - 103B(思维+dfs找环)

    题意 https://vjudge.net/problem/CodeForces-103B 很久很久以前的一天,一位美男子来到海边,海上狂风大作.美男子希望在海中找到美人鱼 ,但是很不幸他只找到了章鱼 ...

  9. 201871010112-梁丽珍《面向对象程序设计(java)》第十三周学习总结

    项目 内容 这个作业属于哪个课程 https://www.cnblogs.com/nwnu-daizh/ 这个作业的要求在哪里 https://www.cnblogs.com/nwnu-daizh/p ...

  10. js 记录几个因惯性思维引发的代码BUG,开发思维方式的自我反省

     壹 ❀ 引 在写这篇文章之前,对于取什么标题其实让我纠结了好几天,这篇文章中我想说的东西与引用类型数据有关,也与我们的惯性思维有关.本文中展示的几段代码都非常简单,原型都来自于我的日常开发,但让你立 ...