使用cubemx 接收一帧数据的坑

之前采用判断0X0D+0X0A是完成接受一帧数据(不定长度),但是必须加回车(0x0d,0x0a)。做为通信协议会显得臃肿。然后就百度了一下发现真有发送一帧数据的功能。即使用IDLE中断进行判断。这里我参考了许多帖子,就不一一引用,感谢他们的贡献。https://blog.csdn.net/qq_29413829/article/details/63262321?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-3&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-3

主要有两种:1、空闲中断IDLE配合DMA接收。2、RXNE配合IDLE中断。

第一种方式,我也试过没用成功,现在猜测跟第二中方式的坑差不多。这里我只说下第二种方式自己遇到的坑。由于使用cubemx及同时参考了两种方式,问题主要是一些库函数的错误使用。

cube配置就不说了。主要配置串口的中断波特率等参数,可以参考其他文章https://blog.csdn.net/CSDN_Xu_xue/article/details/104403532?utm_medium=distribute.pc_relevant.none-task-blog-OPENSEARCH-4&depth_1-utm_source=distribute.pc_relevant.none-task-blog-OPENSEARCH-4。这里附上主要修改代码。

/*1初始化开启RXNE和IDLE中断,如果开启了其他的该串口的中断的函数一定要注意!!这里有坑。*/
__HAL_UART_ENABLE_IT(&huart2, UART_IT_RXNE); 
__HAL_UART_ENABLE_IT(&huart2, UART_IT_IDLE); 


/*2中断回调服务函数,这里新建一个服务函数USAR_UART_IDLECallback();。并在中断文件stm32f4xx_it中引用。*/
void USAR_UART_IDLECallback(void) //要在stm32f4xx_it引用,见下个函数
{
	if(__HAL_UART_GET_FLAG(&huart2, UART_FLAG_RXNE) != RESET)//接收到一个字节
	{ 	
//		LED_RED_T;//验证是否进入
		Uart2_RxBuff[Rx_Count_UART2++] = USART2->DR;
//		HAL_UART_Receive_IT(&huart2,Uart2_RxBuffer,1);//一定不要再开启!!!(坑)
	} 
	else if(__HAL_UART_GET_FLAG(&huart2,UART_FLAG_IDLE) != RESET)//接收到一帧数据
	{
		Rx_End_Flag = 1;  // 接受完成标志位置1 
		__HAL_UART_CLEAR_IDLEFLAG(&huart2); //等同于读SR、DR两个寄存器,清除IDLE中断

		LED_GREEN_T;//验证是否进入
		Rx_Num_UART2 = Rx_Count_UART2;//读了多少个数据,我的发送函数要用。
		Rx_Count_UART2 = 0;
	}
}

void USART2_IRQHandler(void)//stm32f4xx_it.c中的
{
  /* USER CODE BEGIN USART2_IRQn 0 */

  /* USER CODE END USART2_IRQn 0 */
  HAL_UART_IRQHandler(&huart2);
  /* USER CODE BEGIN USART2_IRQn 1 */
//	RS232putbuff(Uart2_RxBuff,Rx_Num_UART2);
	
  USAR_UART_IDLECallback(); //新建的中断服务函数
  /* USER CODE END USART2_IRQn 1 */
}
/*3 验证。在主函数中加入发送函数*/
if(Rx_End_Flag == 1)
{
//					LED_BLUE_T;
	RS232putbuff(Uart2_RxBuff,Rx_Num_UART2);//你可以用printf验证
//	printf("%s",Uart2_RxBuff);
	Rx_End_Flag = 0;//清除接收结束标志位
    memset(Uart2_RxBuff,0,sizeof(Uart2_RxBuff));//清空数组。
}

坑1:

之前写接受中断会使用HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)函数进行回调。

即:(传统方式(0x0d,0x0a),不要引用)

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
    if(huart->Instance==USART2)//用于与CT机通信。
	{
		Uart2_RxBuff[Rx_Count_UART2] =  USART2->DR; //每次读取一个字节。并会清除标记
		if((Uart2_RxBuff[Rx_Count_UART2-1] == 0x0D)&&(Uart2_RxBuff[Rx_Count_UART2] == 0x0A))
		{
			LED_RED_T;
			Rx_Num_UART2 = ++Rx_Count_UART2;//
			Rx_End_Flag = 1;  // 接受完成标志位置1 
			Rx_Count_UART2 = 0;//

		}
		else
			Rx_Count_UART2++;//
		  HAL_UART_Receive_IT(&huart2,Uart2_RxBuffer,1);//重新开启中断
    }

}

但是后来测试发现,使用    __HAL_UART_ENABLE_IT(&huart2, UART_IT_RXNE); 
__HAL_UART_ENABLE_IT(&huart2, UART_IT_IDLE);

开这两个中断不能进入HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)回调函数。所以自己再原来基础上改回调函数并不成功。从新建一个回调函数放入中断服务函数就可以调用。即在stm32fxx_it.c(中断函数文件)加入新的回调函数USAR_UART_IDLECallback();

使用cubemx 接收一帧数据的坑_第1张图片

坑2:同时使用了    if(HAL_UART_Receive_IT(&huart2, Uart2_RxBuffer, 1) != HAL_OK) Error_Handler();

__HAL_UART_ENABLE_IT(&huart2, UART_IT_RXNE); 
__HAL_UART_ENABLE_IT(&huart2, UART_IT_IDLE); 开启中断。这里

 if(HAL_UART_Receive_IT(&huart2, Uart2_RxBuffer, 1) != HAL_OK) Error_Handler();(以前使用的开启中断方式)

和__HAL_UART_ENABLE_IT(&huart2, UART_IT_RXNE); 会产生冲突。而我在中断中再次开启了HAL_UART_Receive_IT(&huart2, Uart2_RxBuffer, 1)。这就出问题了。会导致只接收一个字节的数据(很多人应该都遇到了这个问题)。把这函数去掉就正常了。

一天一夜一早晨的坑,给大家填了。

你可能感兴趣的:(使用cubemx 接收一帧数据的坑)