您现在的位置是:首页 >技术杂谈 >NRF24L01学习操作教程(二)——NRF实现一对一,一对多通讯网站首页技术杂谈
NRF24L01学习操作教程(二)——NRF实现一对一,一对多通讯
上篇博客链接:https://blog.csdn.net/DIVIDADA/article/details/130599974?spm=1001.2014.3001.5501
以下单片机例程都是基于STM32 HAL库,在文档末尾,我会提供参考博客和源码程序的链接。
通讯实例与代码实现
在CubeMx中配置单片机时钟、SPI通讯接口、NRF24L01接口等,并生成Keil工程
将NRF24L01的驱动程序的.c文件和.h文件添加到工程目录下,重新编译程序
nrf24l01实现一对一单向通讯
1.流程分析:
A端:
- 设置成发送模式(TX_Mode(0))
- 每隔100ms发送一次数据(NRF24L01_TxPacket())
B端:
- 设置成接收模式(RX_Mode(0),B端地址设置要同A端一致)
- 循环判断是否接受到数据(NRF24L01_RxPacket())
2.源码程序
A端:
//....................
uint8_t tx_buf[8];
//....................
int main(void)
{
//...................
NRF24L01_Init(); //NRF24L01初始化
while(NRF24L01_Check()); //检测NRF24L01模块是否在位
TX_Mode(0); //将NRF24L01模块设置为发送模式,传入参数0设置地址
//....................
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
HAL_Delay(100);
if(NRF24L01_TxPacket(tx_buf)==0X20) //NRF24L01模块发送数据并判断是否发送成功
{
HAL_GPIO_TogglePin(LED_GPIO_Port,LED_Pin); //若发送成功,LED电平反转
tx_buf[0]++; //若发送成功,tx_buf[0]自增加
}
}
/* USER CODE END 3 */
}
B端:
//....................
uint8_t rx_buf[8];
//....................
int main(void)
{
//...................
NRF24L01_Init(); //NRF24L01初始化
while(NRF24L01_Check()); //检测NRF24L01模块是否在位
RX_Mode(0); //将NRF24L01模块设置为发送模式,传入参数0设置地址(同发送模块地址相同)
//....................
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
if(NRF24L01_RxPacket(rx_buf)==0X00) //NRF24L01模块接收数据并判断是否接收成功
{
HAL_GPIO_TogglePin(LED_GPIO_Port,LED_Pin); //若接收成功,LED电平反转
}
}
/* USER CODE END 3 */
}
3.实验结果
在B端程序中进入debug模式,将rx_buf添加到watch窗口中,可以观察到rx_buf[0]值不断增加
nrf24l01实现一对一双向通讯
1.流程分析:
A端:
- 设置成发送模式(TX_Mode(0))
- 发送一次数据(NRF24L01_TxPacket())
- 发送完成立马转变成接收模式(RX_Mode(0))
- 等待接收数据成功(while(READ_NRF24L01_IRQ!=0))
- 接收数据成功后立马转换发送模式(TX_Mode(0))
- 进入下一次收发数据,如此循环
B端:
- 设置成接收模式(RX_Mode(0),B端地址设置要同A端一致)
- 循环判断是否接受到数据(NRF24L01_RxPacket())
- 接收到数据成功后立马转换成发送模式(TX_Mode(0))
- 发送成后立马转换成接收模式(RX_Mode(0)),方便下一次接收
实际上这种双向收发的方式对A、B端的时序要求非常高,通俗点说就是A端处于发送模式并发送数据的时候,B端一定要处于接收模式,否则就是两个哑巴在通讯。所以为了保证通讯的稳定性,需要对上述的通讯流程进行一定的优化,具体优化的地方就是:A端在等待接收数据成功的时候(while(READ_NRF24L01_IRQ!=0)计数等待,若计数值超过阈值,再发送一次,最多发送10次;B端在发送数据时候计数,若计数值超过阈值还未发送成功,立马转变成接收模式。具体实现方法可以见下面的源程序。
经过测试,这种双向收发机制,通讯十分稳定(NICE)
2.源码程序
A端:
//....................
uint8_t tx_buf[8];
uint8_t rx_buf[8];
void NRF_Intercommunication(uint8_t Seq_Nrf,uint8_t *Txbuf, uint8_t *Rxbuf);
//....................
int main(void)
{
//...................
NRF24L01_Init(); //NRF24L01初始化
while(NRF24L01_Check()); //检测NRF24L01模块是否在位
TX_Mode(0); //将NRF24L01模块设置为发送模式,传入参数0设置地址
//....................
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
HAL_Delay(100);
HAL_GPIO_TogglePin(LED_GPIO_Port,LED_Pin);
NRF_Intercommunication(0,tx_buf,rx_buf); //进行一次双向通讯
}
/* USER CODE END 3 */
}
//.........................
void NRF_Intercommunication(uint8_t Seq_Nrf,uint8_t *Txbuf, uint8_t *Rxbuf)
{
uint8_t j=1;
uint16_t cnt_01=0,cnt_02=0;
while(j--)
{
TX_Mode(Seq_Nrf); //设置为发送模式
NRF24L01_TxPacket(Txbuf);//将数据发送出去
RX_Mode(Seq_Nrf); //将数据发送出去后立马转换成接收模式
while(READ_NRF24L01_IRQ!=0) //等待接收成功
{
if(++cnt_01>0XAFFF) //如果计数值超过阈值(0XAFFF),则跳出接收等待
break;
}
if(cnt_01>0XAFFF) //若计数值超过阈值,j赋值1,再次进行一次数据收发
{
cnt_01=0;
if(++cnt_02<10) //最多重复进行十次数据收发
{
j=1;
continue;
}
}
NRF24L01_RxPacket(Rxbuf); //读取接收缓存区数据
cnt_01=0;cnt_02=0;
}
}
B端:
//....................
uint8_t tx_buf[8] = {0};
uint8_t rx_buf[8] = {0};
uint8_t Mode=0;//1代表发送模式,0代表接收模式
uint8_t Tx_cnt; //发送次数计数
//....................
int main(void)
{
//...................
NRF24L01_Init(); //NRF24L01初始化
while(NRF24L01_Check()); //检测NRF24L01模块是否在位
RX_Mode(0); //将NRF24L01模块设置为发送模式,传入参数0设置地址(同发送模块地址相同)
//....................
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
if(Mode==1)
{
Tx_cnt++;
if(NRF24L01_TxPacket(tx_buf)==0x20)//发送数据成功
{
tx_buf[0]++;
Tx_cnt=0;
Mode=0; //转变为接收模式
RX_Mode(0); //一但发送成功则变成接收模式;
}
if(Tx_cnt==3) //如果连续发送3次都失败,则转换为接收模式
{
Tx_cnt=0;
Mode=0; //转变为接收模式
RX_Mode(0); //一但达到最大发送次数则变成接收模式;
}
}
if(Mode==0)
{
if(NRF24L01_RxPacket(rx_buf)==0X00)//一旦接收成功则变成发送模式;
{
HAL_GPIO_TogglePin(LED_GPIO_Port,LED_Pin);
Mode=1;//转变为发送模式
TX_Mode(0);
}
}
}
/* USER CODE END 3 */
}
3.实验结果
在A端程序中进入debug模式,将rx_buf添加到watch窗口中,可以观察到rx_buf[0]值不断增加
nrf24l01实现一对多双向通讯
以1对2双向通讯为例,给B端、C端设置不同的地址(Mode(0)和Mode(1)),A端地址设为Mode(0)先与B端进行双向通讯,然后设为Mode(1)先与C端进行双向通讯,如此循环就可实现1对2双向通讯
1.流程分析:
A端:
- 设置成发送模式,先与B端通讯(TX_Mode(0))
- 发送一次数据(NRF24L01_TxPacket())
- 发送完成立马转变成接收模式(RX_Mode(0))
- 等待接收数据成功(while(READ_NRF24L01_IRQ!=0))
- 接收数据成功后立马转换发送模式,与C端通讯(TX_Mode(1))
- 发送一次数据(NRF24L01_TxPacket())
- 发送完成立马转变成接收模式(RX_Mode(1))
- 等待接收数据成功(while(READ_NRF24L01_IRQ!=0))
- 接收数据成功后立马转换发送模式,如此循环与B端、C端通讯
B端:
- 设置成接收模式(RX_Mode(0),B端地址设置要同A端一致)
- 循环判断是否接受到数据(NRF24L01_RxPacket())
- 接收到数据成功后立马转换成发送模式(TX_Mode(0))
- 发送成后立马转换成接收模式(RX_Mode(0)),方便下一次接收
C端:
- 设置成接收模式(RX_Mode(1),C端地址设置要同A端一致)
- 循环判断是否接受到数据(NRF24L01_RxPacket())
- 接收到数据成功后立马转换成发送模式(TX_Mode(1))
- 发送成后立马转换成接收模式(RX_Mode(1)),方便下一次接收
2.源码程序
A端:
//....................
uint8_t tx_buf[8];
uint8_t rx_buf[8];
void NRF_Intercommunication(uint8_t Seq_Nrf,uint8_t *Txbuf, uint8_t *Rxbuf);
//....................
int main(void)
{
//...................
NRF24L01_Init(); //NRF24L01初始化
while(NRF24L01_Check()); //检测NRF24L01模块是否在位
TX_Mode(0); //将NRF24L01模块设置为发送模式,传入参数0设置地址
//....................
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
for(int i=0;i<2;i++)
{
HAL_Delay(100);
HAL_GPIO_TogglePin(LED_GPIO_Port,LED_Pin);
NRF_Intercommunication(i,tx_buf,rx_buf); //与B端、C端各进行一次双向通讯
}
}
/* USER CODE END 3 */
}
//.........................
void NRF_Intercommunication(uint8_t Seq_Nrf,uint8_t *Txbuf, uint8_t *Rxbuf)
{
uint8_t j=1;
uint16_t cnt_01=0,cnt_02=0;
while(j--)
{
TX_Mode(Seq_Nrf); //设置为发送模式
NRF24L01_TxPacket(Txbuf);//将数据发送出去
RX_Mode(Seq_Nrf); //将数据发送出去后立马转换成接收模式
while(READ_NRF24L01_IRQ!=0) //等待接收成功
{
if(++cnt_01>0XAFFF) //如果计数值超过阈值(0XAFFF),则跳出接收等待
break;
}
if(cnt_01>0XAFFF) //若计数值超过阈值,j赋值1,再次进行一次数据收发
{
cnt_01=0;
if(++cnt_02<10) //最多重复进行十次数据收发
{
j=1;
continue;
}
}
NRF24L01_RxPacket(Rxbuf); //读取接收缓存区数据
cnt_01=0;cnt_02=0;
}
}
B端:
//....................
uint8_t tx_buf[8] = {0};
uint8_t rx_buf[8] = {0};
uint8_t Mode=0;//1代表发送模式,0代表接收模式
uint8_t Tx_cnt; //发送次数计数
//....................
int main(void)
{
//...................
NRF24L01_Init(); //NRF24L01初始化
while(NRF24L01_Check()); //检测NRF24L01模块是否在位
RX_Mode(0); //将NRF24L01模块设置为发送模式,传入参数0设置地址(同发送模块地址相同)
//....................
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
if(Mode==1)
{
Tx_cnt++;
if(NRF24L01_TxPacket(tx_buf)==0x20)//发送数据成功
{
tx_buf[0]++;
Tx_cnt=0;
Mode=0; //转变为接收模式
RX_Mode(0); //一但发送成功则变成接收模式;
}
if(Tx_cnt==3) //如果连续发送3次都失败,则转换为接收模式
{
Tx_cnt=0;
Mode=0; //转变为接收模式
RX_Mode(0); //一但达到最大发送次数则变成接收模式;
}
}
if(Mode==0)
{
if(NRF24L01_RxPacket(rx_buf)==0X00)//一旦接收成功则变成发送模式;
{
HAL_GPIO_TogglePin(LED_GPIO_Port,LED_Pin);
Mode=1;//转变为发送模式
TX_Mode(0);
}
}
}
/* USER CODE END 3 */
}
C端:
C端代码除了地址设置与B端不同外,其余均相同
//....................
//....................
int main(void)
{
//...................
NRF24L01_Init(); //NRF24L01初始化
while(NRF24L01_Check()); //检测NRF24L01模块是否在位
RX_Mode(1); //将NRF24L01模块设置为发送模式,传入参数1设置地址(同发送模块地址相同)
//....................
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
if(Mode==1)
{
//....................
RX_Mode(1);
}
if(Mode==0)
{
//....................
TX_Mode(1);
}
}
/* USER CODE END 3 */
}
3.实验结果
同样通过debug模式,可以观察到接收数据。
总结
以上内容详细介绍了,使用NRF24L01实现1对1单向通讯、1对1双向通讯、1对多双向通讯;想要程序源码的可以进我的github仓库自取:https://github.com/HaoJosephWen/Code-of-blog,或评论区留下邮箱。
参考博客
NRF24L01 的双向通信_nrf24l01怎么配对_努力学习cs的博客-CSDN博客
NRF24L01一对多通信方法_noting_to_talk的博客-CSDN博客