回顾
之前有一篇文章讲过用定时器超时的方式接收不定长数据 定时器超时的方式,串口接收不定长数据 ,但需要占用一个定时器资源,本文采用了另一种方式,即通过IDLE中断的方式来接收,更简单,也更省资源。
原理
IDLE顾名思义,就是空闲的意思,即当监测到串口空闲超过1个数据帧时,会使状态寄存器(SR或ISR)的IDLE位置位,如果此时控制寄存器(CR或CR1)的IDLEIE为1,则会触发IDLE中断。知道原理了,就好操作了。
CubeMX常规操作
1 启动usart1,并开启中断,其他默认
2 开启调试接口SWD
3 设置好时钟
4 代码选项,生成KEIL代码
手动修改代码
1 在main函数中增加一行,以启动RXNEIE中断,即串口接收中断
main()
...
HAL_UART_Receive_IT(&huart2, uart2_receive_buf, 1);
__HAL_UART_ENABLE_IT(&huart2, UART_IT_RXNE); //启动RXNE中断
__HAL_UART_ENABLE_IT(&huart2, UART_IT_IDLE); //启动IDLE中断
...
while (1)
2 在stm32h7xx_it.c,这个中断文件中,修改串口中断函数
u8 uart2_receive_point = 0;
u8 uart2_receive_buf[100];
u8 uart2_receive_over = 0;
u8 uart2_temp;
void USART2_IRQHandler(void)
{
/* USER CODE BEGIN USART2_IRQn 0 */
/* USER CODE END USART2_IRQn 0 */
HAL_UART_IRQHandler(&huart2);
/* USER CODE BEGIN USART2_IRQn 1 */
//收到1个字节的数据
if(__HAL_UART_GET_FLAG(&huart2, UART_FLAG_RXNE))
{
__HAL_UART_ENABLE_IT(&huart2, UART_IT_RXNE); //启动RXNE中断
uart2_receive_buf[uart2_receive_point] = huart2.Instance->RDR;
uart2_receive_point ++;
}
//长时间未接收到数据时,会发生IDLE中断,此时意味着数据接收完成
//不同的内核,清除IDLEIE的方式不同,请查阅手册
if(__HAL_UART_GET_FLAG(&huart2, UART_FLAG_IDLE))
{
huart2.Instance->ICR += USART_ICR_IDLECF; //向USART_CR1的IDLECF位写1,以清除IDLEIF标志,否则会一直进IDLEIE中断
uart2_receive_over = UART_RECEIVE_OK;
}
/* USER CODE END USART2_IRQn 1 */
}
兼容性
这个空闲中断,对STM32是OK的,但是对于兼容产品不一定适用,比如航顺HK32F103就亲测不行,需要修改代码。开发人员需要注意这个问题
对于STM32来说,不同的内核,清除IDLEIE标志的方法是不同的,这个需要查阅参考手册。如果不清除该位,会一直进IDLE中断。