NRF24L01_TX_ModeSTM32 在使用 NRF24L01 过程中遇到的问题
一、出现 NRF24L01 Error
1.1 问题情况
在使用 正点原子 的代码中有以下这样一段代码:
while(NRF24L01_Check())
{
LCD_ShowString(30,130,200,16,16,"NRF24L01 Error");
delay_ms(200);
LCD_Fill(30,130,239,130+16,WHITE);
delay_ms(200);
}
LCD_ShowString(30,130,200,16,16,"NRF24L01 OK");
- 我们可以看到,这里调用了 NRF24L01 的自检函数,用于判断自检是否通过,当自检不通过时,在LCD上就会显示
NRF24L01 Error
1.2 解决办法
其实这个问题是 引脚冲突的问题,我们可以在正点原子提供的原理图(这里我使用的是 探索者F407的原理图为例)中可以看到 NRF24L01 的接口为:
其对应到 MCU 上为:
想必这里就可以看到问题了吧,连接 SPI1
的引脚同时也被用于 JTDO
和 JTRST
。那么我们看看这两个引脚有什么作用呢?
那到这里大家应该都明白了吧,这是 下载接口与SPI1冲突的问题,如果想结果NRF自检不过的问题,直接拔掉下载器与开发板的接口即可。
1.3 总结
在本人使用过程中发现,我使用的是一块 STM32F407ZGT6 最小系统板。当然它也是具有 JTAG 接口,兼容 ST-LINK-V2下载器。
- 断开 ST-Link 与电脑的连接,按下 RST 仍然不能解决出现 Error 的问题,需要拔下排线与开发板的连接
- 在个别情况下,有时候即使不拔掉下载器也能正常运行,目前作者也不知道是什么原因
二、NRF24L01 与 PC(电脑)连接无法进行收发
2.1 问题情况
在使用 NRF24L01 进行与电脑的通信过程中,在某宝购买了 USB转NRF24L01模块,链接如下:USB无线串口模块串口转nRF24L01+数传通信遥控采集 开发转接板-淘宝网 (taobao.com),如下图所示:
它的原理也很简单,上面有一个STC的芯片作为主控,而NRF24L01就是与该芯片进行连接,然后将输出通过USART连接到一个串口芯片CH430T上,将串口信号转成USB信号,通过电脑上位机即可实现串口信息的查看与发送。
我们可以看到它的介绍,可以实现一对一、一对多通信,甚至是PC与MCU相互通信,它也有配套的上位机程序,可以快速通过串口进行设置,也可以通过AT指令进行设置,可以说是非常方便啦。那么在以下情况下:
-
我首先配置PC端的NRF模块:
最好还是设置的时候两个地址设置成一样,否则在STM32上切换模式很麻烦
-
这里我解释下:
-
波特率:是串口芯片的波特率,正如前面所说,该模块是通过串口将SPI信息发送给PC的
-
目标地址:目标地址通俗来讲,就是你要给哪个NRF模块发送信息,就填写这个模块的地址
-
本地地址:显而易见,这是本模块的地址
-
通讯频率:通讯频率不是所以为的SPI速率,这是无线信号的发射频率
-
校验方式:可选择 8 或 16 位CRC校验,默认为16
-
空中速率:这个就是空中传输的最大速率啦
注:设置完成一定记得点 应用 否则无效
-
-
-
其次我们设置STM32端的NRF模块:
-
我使用的是正点原子的例程,板子用的是 STM32F407ZGT6 最小系统板,我们可以在正点原子的代码中看到如下:
-
24l01.c文件
const u8 TX_ADDRESS[TX_ADR_WIDTH]={0x34,0x43,0x10,0x10,0x01}; //发送地址 const u8 RX_ADDRESS[RX_ADR_WIDTH]={0x34,0x43,0x10,0x10,0x01}; //发送地址
这里的注释不是我写错了,这是正点原子的代码本来就是这样写的。
我们对其进行更改,以适配我们自己设置的模块地址:
const u8 TX_ADDRESS[TX_ADR_WIDTH]={0xFF,0xFF,0xFF,0xFF,0xFF}; // 发送地址 const u8 RX_ADDRESS[RX_ADR_WIDTH]={0xFF,0xFF,0xFF,0xFF,0xFF}; // 接收地址
-
可以根据前面提到的在PC端设置情况来看
- 发送地址:是由STM32发送给PC,而之前设置的PC端的NRF模块地址为:0xFF,0xFF,0xFF,0xFF,0xFF
- 接收地址:是由STM32接收PC发送来的信息,而之前设置的NRF模块的目的地址为:0xA5,0xA5,0xA5,0xA5,0xA5
-
其实这也很好理解,我们先看设置地址的代码部分:
// NRF24L01_RX_Mode 函数中 NRF24L01_Write_Buf(NRF_WRITE_REG+RX_ADDR_P0,(u8*)RX_ADDRESS,RX_ADR_WIDTH);//写RX节点地址 // NRF24L01_TX_Mode 函数中 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
-
我们将 NRF 设置成 接收模式 的时候,在
NRF24L01_RX_Mode
函数中,写到了将RX_ADDR_P0
数据通道0接收地址寄存器的值设置为RX_ADDRESS
的值 -
我们将 NRF 设置成 接收模式 的时候,在
NRF24L01_TX_Mode
函数中,写到了将TX_ADDR
发送地址寄存器的值设置为TX_ADDRESS
的值,将RX_ADDR_P0
数据通道0接收地址寄存器的值设置为RX_ADDRESS
的值实际上呢,可以这么理解,TX_ADDR寄存器的值就是本模块在发送数据的时候需要的对方的地址,而RX_ADDR_P0寄存器的值就是应答方的地址,设应答,地址就是谁的
-
-
-
-
我们在主函数简单写一段测试发送的函数:
int main(void) { u8 t=0; u8 tmp_buf[32] = {0}; NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置系统中断优先级分组2 delay_init(168); //初始化延时函数 uart_init(9600); //初始化串口波特率为115200 NRF24L01_Init(); //初始化NRF24L01 while(NRF24L01_Check()) { printf("NRF_ERROR!!!\r\n"); delay_ms(200); } printf("NRF_TX_MODE ... \r\n"); delay_ms(500); NRF24L01_TX_Mode(); // 设置为发送模式 tmp_buf[0] = 'A'; tmp_buf[1] = 'B'; tmp_buf[2] = 'C'; tmp_buf[3] = 'D'; tmp_buf[4] = 'E'; printf("Send message: "); for (t=0; t < 32; t++) printf("%x ", tmp_buf[t]); printf("\r\n"); while(1) { if(NRF24L01_TxPacket(tmp_buf)==TX_OK) { printf("\r\nSend Date: "); for (t=0; t < 32; t++) printf("%x ", tmp_buf[t]); } else { printf("\r\nSend failed!\r\n"); } delay_ms(1500); } }
-
我们可以看到这实现了一个简单的逻辑,就是循环发送
A、B、C、D、E
(均为字符型),**但是我们会发现,PC端的NRF收不到任何信息
-
-
- 看似一切都没有问题,但是就是收不到信息,怎么改配置参数都没用,这时候就有很多人陷入了疑惑,那我相信,肯定有很多人选择再买一个这个模块,尝试PC与PC之间的通信吧,然后你会发现PC与PC没问题,反而移植到单片机上就不行了。小小的脑瓜,大大的疑惑!!!
2.2 解决方法
首先,我们看下这个 转串口模块 的使用说明,里面提到了:
-
这是我们第一个需要改动的地方:
-
通过对上面的描述,我们知道了,一次发送的32字节被压缩到了31字节,第一位被用于描述数据长度,确实很过分,但毕竟是别人的通信协议。那么我们对主函数进行修改:
这里不用着急复制,后面我会放出完整代码
tmp_buf[0] = 5; tmp_buf[1] = 'A'; tmp_buf[2] = 'B'; tmp_buf[3] = 'C'; tmp_buf[4] = 'D'; tmp_buf[5] = 'E'; printf("Send message: "); for (t=0; t < 32; t++) printf("%x ", tmp_buf[t]); printf("\r\n");
将第一次数据填入本帧数据的有效数据长度,然后再进行发送。很多人觉得这下彻底行了,结果结局还挺让人失望的,满怀期待啊,结果还是发现收不到任何东西(啊,那个串口就很过分啊,怎么一直打印 “Send Falied!” 啊)
-
其实,bug并没有解决,没有那么简单。
-
这是我们第二个需要改动的地方:
-
我们先看到我们设置的
NRF24L01_TX_Mode()
的函数源码://该函数初始化NRF24L01到TX模式 //设置TX地址,写TX数据宽度,设置RX自动应答的地址,填充TX发送数据,选择RF频道,波特率和LNA HCURR //PWR_UP,CRC使能 //当CE变高后,即进入RX模式,并可以接收数据了 //CE为高大于10us,则启动发送. void NRF24L01_TX_Mode(void) { 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_AA,0x01); //使能通道0的自动应答 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+CONFIG,0x0e); //配置基本工作模式的参数;PWR_UP,EN_CRC,16BIT_CRC,接收模式,开启所有中断 NRF24L01_CE=1;//CE为高,10us后启动发送 }
-
这段函数设置了各种各样的模式,你要粗略的一看,好像确实没啥问题,但是它其实是有问题的
-
在PC端,我们设置了NRF模块默认的通讯频率为:2.400GHz,可是在STM32上怎么没有这个参数呢?其实当你翻阅 NRF24L01 的数据手册的时候,你就会看到以下内容:
-
是不是有点眼熟啊,
RF_CH
寄存器对吧,看看我们怎么设置的NRF24L01_Write_Reg(NRF_WRITE_REG+RF_CH,40); //设置RF通道为40
其中
NRF_WRITE_REG
表示 写寄存器,RF_CH
是该寄存器的地址,我们向这个寄存器写入了40,那代入上面的公式:
F 0 = 2400 + R F _ C H = 2400 + 40 = 2440 ( M H z ) = 2.440 ( G H z ) F_0=2400+RF\_CH=2400+40=2440(MHz)=2.440(GHz) F0=2400+RF_CH=2400+40=2440(MHz)=2.440(GHz)
那这就有问题了吧,频率都不匹配,怪不得收不到数据,那么我们就有了思路,进行以下更改:NRF24L01_Write_Reg(NRF_WRITE_REG+RF_CH,0); //设置RF通道为0
-
-
-
-
由此,我们结束改 bug 的工作,再次运行代码,发现能正常工作了,可喜可贺啊!!!
2.3 总结
- 要想实现通信,首先需要明确通信数据帧格式,其次需要使两个模块进行匹配
以下就是主函数部分:
-
STM32的NRF设置为发数据模式:
#include "sys.h" #include "delay.h" #include "usart.h" #include "spi.h" #include "24l01.h" /* * [注意]:一定要记得更改 24l01.c 中的 NRF24L01_TX_Mode() 函数里面的: * NRF24L01_Write_Reg(NRF_WRITE_REG+RF_CH,0); //设置RF通道为40 * [注意]:要根据你自己设置的模块地址,更改模块的地址信息,同样在 24l01.c 中 * const u8 TX_ADDRESS[TX_ADR_WIDTH]={0xFF,0xFF,0xFF,0xFF,0xFF}; // 发送地址 * const u8 RX_ADDRESS[RX_ADR_WIDTH]={0xFF,0xFF,0xFF,0xFF,0xFF}; // 接收地址 */ int main(void) { u8 t=0; u8 tmp_buf[32] = {0}; NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置系统中断优先级分组2 delay_init(168); //初始化延时函数 uart_init(9600); //初始化串口波特率为115200 NRF24L01_Init(); //初始化NRF24L01 while(NRF24L01_Check()) { printf("NRF_ERROR!!!\r\n"); delay_ms(200); } printf("NRF_OK!!!\r\n"); printf("SET NRF_TX_MODE ... \r\n"); delay_ms(500); NRF24L01_TX_Mode(); /* * 组装数据帧,第一位是有效数据的长度 */ tmp_buf[0] = 5; tmp_buf[1] = 'A'; tmp_buf[2] = 'B'; tmp_buf[3] = 'C'; tmp_buf[4] = 'D'; tmp_buf[5] = 'E'; printf("Send message: "); for (t=0; t < 32; t++) printf("%x ", tmp_buf[t]); printf("\r\n"); while(1) { if(NRF24L01_TxPacket(tmp_buf)==TX_OK) { printf("\r\nSend Date: "); for (t=0; t < 32; t++) printf("%x ", tmp_buf[t]); }else { printf("\r\nSend failed!\r\n"); } delay_ms(1500); } }
-
同时,实现接收数据代码:
#include "sys.h" #include "delay.h" #include "usart.h" #include "spi.h" #include "24l01.h" /* * [注意]:一定要记得更改 24l01.c 中的 NRF24L01_RX_Mode() 函数里面的: * NRF24L01_Write_Reg(NRF_WRITE_REG+RF_CH,0); //设置RF通道为40 * [注意]:要根据你自己设置的模块地址,更改模块的地址信息,同样在 24l01.c 中 * const u8 TX_ADDRESS[TX_ADR_WIDTH]={0xFF,0xFF,0xFF,0xFF,0xFF}; // 发送地址 * const u8 RX_ADDRESS[RX_ADR_WIDTH]={0xA5,0xA5,0xA5,0xA5,0xA5}; // 接收地址 */ int main(void) { u8 t=0; u8 tmp_buf[32] = {0}; NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置系统中断优先级分组2 delay_init(168); //初始化延时函数 uart_init(9600); //初始化串口波特率为115200 NRF24L01_Init(); //初始化NRF24L01 while(NRF24L01_Check()) { printf("NRF_ERROR!!!\r\n"); delay_ms(200); } printf("NRF_OK!!!\r\n"); printf("SET NRF_RX_MODE ... \r\n"); delay_ms(500); NRF24L01_RX_Mode(); while(1) { if(NRF24L01_RxPacket(tmp_buf)==0)//一旦接收到信息,则显示出来. { printf("\r\nRecive Date: "); for (t=0; t < 32; t++) printf("%x ", tmp_buf[t]); }else delay_us(100); } }
-
这里需要更改
RX_ADDRESS
如下:- 最好还是设置的时候两个地址设置成一样,否则切换模式很麻烦
const u8 TX_ADDRESS[TX_ADR_WIDTH]={0xFF,0xFF,0xFF,0xFF,0xFF}; // 发送地址 const u8 RX_ADDRESS[RX_ADR_WIDTH]={0xA5,0xA5,0xA5,0xA5,0xA5}; // 接收地址
-
附结果图:
其第一个字节为0x03是因为这是模块协议中自带的,第一位为发送的数据长度,在说明文档中有写:
-
三、写在最后
遇到问题还是要多去看看源码,别人的代码不一定都通用,多去翻翻芯片数据手册,即使他是英文的,但现在不是有那么多翻译工具吗,试着去理解,不能一味地复制粘贴,那多没意思啊。最后,希望看到这篇文章的你,能够顺利解决bug,哈哈哈,说来惭愧,这个问题也困扰了我几个小时,本着开源精神,大家一起参考借鉴。
最后的最后,介绍下自己,欢迎大家关注我的 CSDN 账号,以后有好的解决问题办法会及时公布开源!!!本文章的代码以后再考虑开不开源吧,目前事情还比较多,有空了会试着整理出来。
个人CSDN账号:刘梓谦_-CSDN博客
Gitee:刘佳豪 (liu-jiahaohappy) - Gitee.com文章来源:https://www.toymoban.com/news/detail-817771.html
GitHub:Jiahao-Liu29 (github.com)文章来源地址https://www.toymoban.com/news/detail-817771.html
到了这里,关于STM32在使用NRF24L01中PC(电脑)连接无显示数据以及出现error的解决办法的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!