RYMCU 嵌入式开源https://rymcu.com
编者注:
单片机串口接收不定长数据时,必须面对的一个问题为:怎么判断这一包数据接收完成了呢?常见的方法主要有以下两种:
1.在接收数据时启动一个定时器,在指定时间间隔内没有接收到新数据,认为数据接收完成;2.在数据中加入帧头、帧尾,通过在程序中判断是否接收到帧尾来确定数据接收完毕。这两种方法的缺点为,需要主程序来判断和处理,对主程序造成不小压力。
STM32单片机空闲检测中断可以很好的解决这个问题。他的工作原理为:
当STM32的串口接收完一包数据后,会产生一个空闲中断。这个中断在串口其他任何状态都不产生,只会在接收完一包数据后才会产生,一包数据可以是1个字节或者多个字节。因此,我们可以在这个空闲中断函数中,设置一个接收完成标志位。那么,我们只需要在主程序中检测这个标志位就知道数据是否接收完成了。具体应该怎么操作呢?其他不表,直接上代码:
上述代码几乎是STM32串口的常规配置,无需赘述。增加了第47行的空闲中断使能语句,允许它中断即可:
USART_ITConfig(DEBUG_USARTx, USART_IT_IDLE, ENABLE);//空闲中断使能
下面是主程序和串口中断函数:
先来看第30-36行的中断函数内容,首先是把接收到的字节存到rx_buff中,并且数据长度rx_cnt++,接着调用库函数清除接收中断标志位,属于常规的数据接收操作。
不同的是第38-46行:
判断是不是产生了串口空闲中断(USART_IT_IDLE),然后就是置位接收完成标志位rx_done = 1,并且清除空闲中断标志位。
注意事项:
调用库函数USART_ClearITPendingBit(DEBUG_USARTx, USART_IT_IDLE);是不会清除空闲中断标志位的。应该采用42-43两条语句实现,否则会一直进入中断函数。
temp = USART1->SR; //先读SR,再读DR才能完成idle中断的清零,否则一直进入中断。
temp = USART1->DR;
第9-24行的主函数进行相应的处理便可。
GD32相关代码:
usart_interrupt_enable(USART1, USART_INT_IDLE);//空闲中断使能
if(RESET != usart_interrupt_flag_get(USART1, USART_INT_FLAG_IDLE)) //串口空闲中断标志
{
temp = USART_STAT(USART1);
temp = USART_DATA(USART1);
Uart_Data1.reflag = 1;
}