之前采用判断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();
坑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)。这就出问题了。会导致只接收一个字节的数据(很多人应该都遇到了这个问题)。把这函数去掉就正常了。
一天一夜一早晨的坑,给大家填了。