NRF24L01+实现一对一数据双向传输

目录

说明

最近在diy四轴飞行器的时候,需要实现四轴和遥控器之间的双向通信。手头上用的模块是NRF24L01+和SI24R1,这两个芯片的引脚功能相同,不仅硬件上可以直接进行替换使用,程序往往还可以互用(因为还是有点差别),两个芯片的差别很小,其中一个是SI24R1的功率最大达到7dB,而NRF24L01+最大是0dB,这个在配置参数的时候要注意。
NRF24L01+和SI24R1都可以配置为发送或接收模式,为了减少打字的麻烦,下文全都以NRF24L01+来写。实现四轴和遥控器的双向通信,可以让NRF24L01+不断在收/发模式之间直接进行切换,小马哥的四轴用的就是这种方式,但我用HAL库实现这种方式的时候,会出现这种问题:两者可以进行双向的数据传输,但一会儿之后就不能传输了,我也不清楚是怎么回事。
后来查询芯片数据手册,仔细研究NRF24L01+的工作方式之后,发现NRF24L01+工作在ACK模式时,发送端发送数据给接收端时,接收端收到并检验数据无误后,会回复一个ACK信号给发送端,收到ACK的发送端就认为数据发送完成,并产生TX_DS中断,这就是一个应答机制。而接收端回复的ACK信号可以是选择带负载数据的,利用这一点,就可以把接收端要回传的数据发送回发送端,以此来实现双向数据传输。

带负载数据ACK的双向通信

带负载数据的ACK通信模式
要使用带负载数据的ACK信号(ACKPAYLOAD)需要配置FEATURE寄存器中的EN_ACK_PAY位,同时收发双方要开启动态负载长度(通过配置DYNPD和FEATURE寄存器来实现)。

配置NRF24L01+的收发程序

程序改自正点原子的实验例程。
接收方

	NRF24L01_CE=0;	
    NRF24L01_Write_Buf(NRF_WRITE_REG+RX_ADDR_P0,(u8*)RX_ADDRESS,RX_ADR_WIDTH);//写RX节点地址
	
  	NRF24L01_Write_Reg(NRF_WRITE_REG+EN_RXADDR,0x01);   //使能通道0的接收地址  	 
  	NRF24L01_Write_Reg(NRF_WRITE_REG+RF_CH,40);	        //设置RF通信频率		  
  	NRF24L01_Write_Reg(NRF_WRITE_REG+RX_PW_P0,RX_PLOAD_WIDTH);//选择通道0的有效数据宽度 	    
  	NRF24L01_Write_Reg(NRF_WRITE_REG+RF_SETUP,0x0f);    //设置TX发射参数,0db增益,2Mbps,低噪声增益开启   
    
    NRF24L01_Write_Reg(NRF_WRITE_REG+EN_AA,0x01);       //使能通道0的自动应答  
    NRF24L01_Write_Reg(NRF_WRITE_REG+FEATURE,0x06);     //使能动态负载(收发数据)长度
    NRF24L01_Write_Reg(NRF_WRITE_REG+DYNPD,0x01);       //使能通道0动态负载长度
  	NRF24L01_Write_Reg(NRF_WRITE_REG+CONFIG, 0x0f);     //配置基本工作模式的参数;PWR_UP,EN_CRC,16BIT_CRC,接收模式
    
    NRF24L01_CE=1;	

发送方

	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_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+FEATURE,0x07); //使能动态负载(收发数据)长度
    NRF24L01_Write_Reg(NRF_WRITE_REG+DYNPD,0x01);   //使能通道0动态负载长度
    NRF24L01_Write_Reg(NRF_WRITE_REG+EN_AA,0x01);   //使能通道0的自动应答    
    NRF24L01_Write_Reg(NRF_WRITE_REG+CONFIG,0x0e);  //配置基本工作模式的参数;PWR_UP,EN_CRC,16BIT_CRC,接收模式,开启所有中断
    
    NRF24L01_CE=1;//CE为高,10us后启动发送

以上配置经过测试是可以使用的,在NRF24L01+之间,SI24R1之间,NRF24L01和SI24R1之间都可以进行双向通信。

收发双方数据的处理

首先是写两个发送数据的函数(其实这两个函数是把数据写入到发送缓冲区,而不是实现数据的发送)
一个是发送端主动发送数据给接收端:

void nrf_txPacket(u8 *txbuf,u8 len)
{
    NRF24L01_CE=0;
  	NRF24L01_Write_Buf(WR_TX_PLOAD,txbuf,len);//写数据到TX BUF
 	NRF24L01_CE=1;  
}

另一个是接收端回复带负载数据的ACK信号(把要回传的数据写入到发送缓冲区,等待接收端自动发送应答信号)

void nrf_txPacket_AP(u8 *txbuf,u8 len)
{
    NRF24L01_CE=0;
  	NRF24L01_Write_Buf(W_ACK_PAYLOAD(0),txbuf,len);//写数据到TX BUF
 	NRF24L01_CE=1;  
}

然后是处理数据的函数,我是在中断回调函数里处理的

		u8 sta = NRF24L01_Read_Reg(NRF_READ_REG + STATUS);
        if(sta & TX_OK)
		{
            NRF24L01_CE = 0;
			NRF24L01_Write_Reg(NRF_WRITE_REG + STATUS,TX_OK); //清除发送完成标志·
			NRF24L01_Write_Reg(FLUSH_TX,0xff); //清除TX_FIFO
			//在这里对发送完的数据进行数据处理
			NRF_TX_DATA[0]++;
            NRF24L01_CE = 1;
        }
        if(sta & RX_OK)
        {
            NRF24L01_CE=0;
            u8 len = NRF24L01_Read_Reg(R_RX_PL_WID);
            if(len>0 && len<33)//数据长度有效
            {
                NRF24L01_Read_Buf(RD_RX_PLOAD,NRF_RX_DATA,len);
            }
            nrf_txPacket_AP(NRF_TX_DATA,1);//发送ACK Payload,数据长度为1
			NRF24L01_Write_Reg(NRF_WRITE_REG + STATUS,RX_OK);//清除发送完成标志
			NRF24L01_Write_Reg(FLUSH_RX,0xff); //清除RX_FIFO
            NRF24L01_CE=1;
        }
        if(sta & MAX_TX)
		{
            NRF24L01_CE = 0;
			NRF24L01_Write_Reg(NRF_WRITE_REG+STATUS,MAX_TX);//清除达到最大重发标志
			NRF24L01_Write_Reg(FLUSH_TX,0xff); //清除TX_FIFO
            NRF24L01_CE = 1;
        }

测试代码和结果

接收端的代码:显示接收端接收到的和发送出去的数据

	while(1)
    {
        LCD_ShowxNum(30+14*8,170,NRF_RX_DATA[0],3,16,0);
        LCD_ShowxNum(30+14*8,190,NRF_TX_DATA[0],3,16,0);
        delay_ms(1);	   
        t++;
        if(t==1000)//大约1s钟改变一次状态
        {
            t=0;
            LED0=!LED0;
        } 
    }

发送端的代码:显示发送端发送的数据和接收到的数据

	while(1)
	{
        LCD_ShowxNum(30+14*8,170,NRF_RX_DATA[0],3,16,0);
		LCD_ShowxNum(30+14*8,190,NRF_TX_DATA[0]++,3,16,0);
        delay_ms(1);	   
        t++;
        if(t==1000)//大约1s钟改变一次状态
        {
            t=0;
            LED0=!LED0;
            nrf_txPacket(NRF_TX_DATA,1);
        }
    } 

测试效果
在这里插入图片描述
在这里插入图片描述
最后,本人没什么写博客的经验,表达不够清晰,写的也比较水,为的是记录一下调试的经历,如果表述中有什么错误的地方欢迎各位大佬批评指正。想知道更详细的内容需要查阅一下数据手册,了解一下NRF24L01+/SI24R1的工作流程。

  • 12
    点赞
  • 77
    收藏
    觉得还不错? 一键收藏
  • 14
    评论
评论 14
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值