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. log4j配置项

    log4j 配置文件log4j.rootLogger=INFO,console,dailyFile# 控制台配置项log4j.appender.console=org.apache.log4j.Con ...

  2. 如何制作gif图片?教你把gif图片缩小100倍大小的妙招!

    移动互联网是短视频的时代,5G的到来更是让短视频蓬勃发展,视频的发展让人们看到了动态的机会,图片也需要动起来,图片动起来应该是比较早的,gif图片很早就有,我们常见的动态表情,现在用的比较多的是视频的 ...

  3. Java日期处理组件joda-time

    版权声明:本文为xing_star原创文章,转载请注明出处! 本文同步自http://javaexception.com/archives/175 Java日期处理组件joda-time 平常在开发过 ...

  4. 实时同步sersync实战

    目录 实时同步sersync实战 什么是实时同步 sersync和rsync+inotify对比 sersync项目实战 安装rsync的服务端(backup) NFS服务端部署sersync 实时同 ...

  5. mssql 系统函数 字符串函数 space 功能简介

    转自: http://www.maomao365.com/?p=4672  一.space 函数功能简介 space功能:返回指定数量的空格参数简介: 参数1: 指定数量,参数需为int类型 注意事项 ...

  6. python anaconda 常用操作;conda 命令指南

    在使用 python anaconda时,经常会用到很多常用操作,记录下来,方便以后更好地使用: conda: Conda既是一个包管理器又是一个环境管理器.你肯定知道包管理器,它可以帮你发现和查看包 ...

  7. css 知识点,你有可能不知道欧!

    1.[定位特性] 绝对定位和固定定位,同时设置left和right等同于隐式的设置宽度. <style> span{ position:fixed; left:30px; right:30 ...

  8. AcWing 166. 数独

    题目地址 https://www.acwing.com/problem/content/description/168/ 题目描述 数独是一种传统益智游戏,你需要把一个9 × 9的数独补充完整,使得图 ...

  9. 题解:swj社会摇成佛第六课

    题目链接 solution: dp f[i]表示lhy小伙身长为i,能砍得的最优解 f[i]=f[j]*f[i-j]; public class CuttingRope01 { public stat ...

  10. HDL的三种描述方式

    结构化描述 结构化描述方式是最原始的描述方式,是抽象级别最低的描述方式,但同时也是最接近于实际的硬件结构的描述方式.结构化的描述方式,思路就像在面包板上搭建数字电路一样,唯一的不同点就是我们通过HDL ...