NRF24L01发送端发送正常,接收端始终接收不到数据问题排查

发现问题

在调试NRF24L01进行无线通信过程中,一开始裸机跑没问题。当主从都加上freertos的时候,通信出现了异常。具体问题,发送端发送数据可以正常发送,接收端接收不到数据。代码使用CUBEmx生成。

排查问题

首先将主从两个模块拿出来单独调试,即不使用自动重发机制。
针对发送方,在配置为发送模式的时候,具体配置代码如下:

//该函数初始化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后启动发送
}

注意:这里的配置都配置成了失能,这样可以保证没有接收方的时候,可以调试发送方。
好了,配置好发送模式,然后就需要进行发送了,在freerots.c中开了一个任务,代码如下:

void StartTask02_IMU_Data(void const * argument)
{
  /* USER CODE BEGIN StartTask02_IMU_Data */
  /* Infinite loop */
  for(;;)
  {
//	AHRS_getYawPitchRoll(ypr); //姿态更新
//	Math_hz++; //解算次数 ++
//	BMP180_Routing(); //处理BMP018 事务 开启转换和读取结果将在这个子程序中进行 
//	BMP180_getTemperat(&Temperature); //读取最近的温度值
//	BMP180_getPress(&Pressure);	   //读取最近的气压测量值
//	BMP180_getAlt(&Altitude);	   //读取相对高度
//	Math_hz=0;
//	MPU6050_getlastMotion6(&ax, &ay, &az, &gx, &gy, &gz);
//	HMC58X3_getRaw(&hx,&hy,&hz);
	  NRF24L01_TxPacket(senddata);
		//printf("rccreg.CR is %x\r\n",RCC->CR);
		
		//printf("sysclocksource is %d\r\n",HAL_RCC_GetSysClockFreq());
			//  printf("sysclksource is %d\r\n",clkdef.SYSCLKSource);
		//printf("pllsource is %d\r\n",clktyp.PLL.PLLSource);
	//printf("data to be sent is %s\r\n",senddata);
		
	//osMessagePut(myQueue01Handle,hx,0);	
   osDelay(50);
  }
  /* USER CODE END StartTask02_IMU_Data */
}

这样就可以循环发送数据了,当然你也可以用printf打印出来,看看你发送的数据,但是,关键是要看你是否发出去了。我在发送打包函数中添加了两个检查STATUS寄存器和FIFO_STATUS寄存器的语句,并将寄存器值打印出来。

//启动NRF24L01发送一次数据
//txbuf:待发送数据首地址
//返回值:发送完成状况
u8 NRF24L01_TxPacket(u8 *txbuf)
{
	u8 sta,fifo_sta;
 	SPI1_SetSpeed(SPI_BAUDRATEPRESCALER_8);//spi速度为10.5Mhz(24L01的最大SPI时钟为10Mhz)   
	NRF24L01_CE=0;
  NRF24L01_Write_Buf(WR_TX_PLOAD,txbuf,TX_PLOAD_WIDTH);//写数据到TX BUF  32个字节
 	NRF24L01_CE=1;//启动发送	   
	while(NRF24L01_IRQ!=0);//等待发送完成  
	sta=NRF24L01_Read_Reg(STATUS);  //读取状态寄存器的值	  读配置寄存器命令是0,
  fifo_sta=	NRF24L01_Read_Reg(NRF_FIFO_STATUS);
	printf("send status is %x \r\n",sta);
	printf("send fifo_status is %x \r\n",fifo_sta);
	NRF24L01_Write_Reg(NRF_WRITE_REG+STATUS,sta); //清除TX_DS或MAX_RT中断标志
	if(sta&MAX_TX)//达到最大重发次数
	{
		NRF24L01_Write_Reg(FLUSH_TX,0xff);//清除TX FIFO寄存器 
		return MAX_TX; 
	}
	if(sta&TX_OK)//发送完成
	{
		return TX_OK;
	}
	return 0xff;//其他原因发送失败
}

好,两个printf函数就将两个寄存器值打印出来了,如果你手上已经看过了NRF的手册,那你就可以对照寄存器查看这两个值的意义了。我这边打印出来的值,STATUS寄存器的值是0x2e,FIFO_STATUS寄存器的值是0x11,通过看手册,说明我发送已经成功了!
既然可以发送,那是不是接收端有问题?同样的方法,我把接收端也配置一下,如下

//该函数初始化NRF24L01到RX模式
//设置RX地址,写RX数据宽度,选择RF频道,波特率和LNA HCURR
//当CE变高后,即进入RX模式,并可以接收数据了		   
void NRF24L01_RX_Mode(void)
{
  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_AA,0x00);    //失能通道0的自动应答    
  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+CONFIG, 0x0f);//配置基本工作模式的参数;PWR_UP,EN_CRC,16BIT_CRC,接收模式 
  NRF24L01_CE = 1; //CE为高,进入接收模式 
}	

**注意:这里配置仍然是失能。然后又配置了一下接收打包函数,和发送一样的方法,把寄存器的值打出来看看,如下:

//启动NRF24L01接收一次数据
//rxbuf:待接收数据首地址
//返回值:0,接收完成;其他,错误代码
u8 NRF24L01_RxPacket(u8 *rxbuf)
{
	u8 sta;		    							   
	SPI1_SetSpeed(SPI_BAUDRATEPRESCALER_8); //spi速度为10.5Mhz(24L01的最大SPI时钟为10Mhz)   
	sta=NRF24L01_Read_Reg(STATUS);  //读取状态寄存器的值   
  printf("status data is %x\r\n",sta);	
	NRF24L01_Write_Reg(NRF_WRITE_REG+STATUS,sta); //清除TX_DS或MAX_RT中断标志
	if(sta&RX_OK)//接收到数据
	{
		NRF24L01_Read_Buf(RD_RX_PLOAD,rxbuf,RX_PLOAD_WIDTH);//读取数据
		NRF24L01_Write_Reg(FLUSH_RX,0xff);//清除RX FIFO寄存器 
		return 0; 
	}	   
	return 1;//没收到任何数据
}		

好,我这里的printf函数打印出的STATUS寄存器的值是0x0e,意思是说我的接收FIFO为空,那就是说没接收到东西嘛,怪不得,问题貌似就发现了,那么接下来就是解决问题了。

解决问题

接收端出了问题,首先我检查了一下发送和接收端的配置,没有问题。说明你只要参考我上面的配置,就不会出大问题。然后。。。然后我就开始走偏了,我怀疑是不是我MCU有问题,因为主控是我刚焊的,元件都是从废旧板子拆下来的。我接下来又把两个主控板的时钟检查了一下,确定sysclk输出是正确的,就是把时钟的寄存器值检查了一下,没问题,那板子应该没问题。然后,我也看不出啥情况,开始把两个模块主从对调了一下,发现还是发送正常,接收有问题,那就说明不是NRF模块的问题了。
尴尬了,找到问题却解决不了问题。
忽然想到一个问题,之前裸机的程序,那个是可以的。但是cubemx生成的不行。裸机的配置都是自己手动配置的,而自动生成这个都是cubemx自动配置的,会不会是这里的问题?不知道是什么力量指引着我,我在代码里一眼看中了NRF24L01_CE=1;//CE为高,10us后启动发送这条语句,CE这个IO有问题吧?
于是我看了下GPIO部分的配置,果然,裸机和带系统的配置是有区别的,对比

	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7|GPIO_Pin_8;	//PG8 7 推挽 	
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;//普通输出模式
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//100MHz
 	GPIO_Init(GPIOC, &GPIO_InitStructure);//初始化指定IO

这个是裸机的配置

  /*Configure GPIO pin : PtPin */
  GPIO_InitStruct.Pin = SPI_CE_Pin;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_PULLUP;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
  HAL_GPIO_Init(SPI_CE_GPIO_Port, &GPIO_InitStruct);

这个是带操作系统的配置
区别就在于,cubemx生成的代码,将这个IO口上拉了!!!直觉告诉我,注释掉它!!!重新编译下载,接收端,成功接收到来自发送端的问候。
在这里插入图片描述

总结

以上贴出代码为调试代码,具体通信还是需要加上自动重发机制,即将原来的失能的地方都改成使能就可以了。

评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值