NRF24L01实现一对一和一对多通讯的学习操作教程(二)

上篇博客链接:https://blog.csdn.net/DIVIDADA/article/details/130599974?spm=1001.2014.3001.5501


以下单片机例程都是基于STM32 HAL库,在文档末尾,我会提供参考博客和源码程序的链接。

文章目录

  • 通讯实例与代码实现
  • nrf24l01实现一对一单向通讯
  • nrf24l01实现一对一双向通讯
  • nrf24l01实现一对多双向通讯
  • 总结
  • 参考博客
  • 通讯实例与代码实现

    在CubeMx中配置单片机时钟、SPI通讯接口、NRF24L01接口等,并生成Keil工程

    image-20230514000842277

    将NRF24L01的驱动程序的.c文件和.h文件添加到工程目录下,重新编译程序

    image-20230514001231068

    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]值不断增加

    image-20230514012007998

    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]值不断增加

    image-20230514025835277

    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博客

    nrf24l01中文资料_工作原理_教程_程序 – 瑞生网 (rationmcu.com)

    新手如何快速搞通NRF24L01通信 – 瑞生网 (rationmcu.com)

    物联沃分享整理
    物联沃-IOTWORD物联网 » NRF24L01实现一对一和一对多通讯的学习操作教程(二)

    发表评论