项目场景:
使用STM32F401的HAL库,编写串口中断收发数据。
问题描述
每次调用HAL_UART_Receive_IT()
函数启动中断模式接收数据后,只能正常接收到第1批数据(数据包长为函数中定义的RXBUFFERSIZE
值)。例如RXBUFFERSIZE=1
时,只能收到1个数据;RXBUFFERSIZE=5
时,只能收到5个数据。HAL_UART_Receive_IT(&UartHandle, (uint8_t *)aRxBuffer, RXBUFFERSIZE);
原因分析:
查阅资料了解到HAL库对于USART的接收中断的处理,划分了好几层。
首先,串口接收中断触发后的入口程序在启动文件startup_stm32f401xc.s中定义为USART1_IRQHandler()和USART2_IRQHandler();
然后,USARTx_IRQHandler()的内容就一句:调用HAL_UART_IRQHandler();
接着,HAL_UART_IRQHandler()对一系列的异常场景进行处理后,再调用UART_Receive_IT();
而在UART_Receive_IT()中,会判断RxXfeiCount值是否为0,当为0时就关断了串口接收中断!RxXfeiCount是UART结构体中“剩余待接收的数据计数值”。——也就是说,每当接收完HAL_UART_Receive_IT()
函数中规定的RXBUFFERSIZE个
数据就关闭接收中断。这也解释了为什么会出现只收到第1批数据后,再也无法接收数据的现象了。
HAL库对于串口接收中断处理的几层调用关系如下:
USARTx_IRQHandler()
┗━ HAL_UART_IRQHandler()
┗━ UART_Receive_IT()
{
if (--huart->RxXferCount == 0U){
/* Disable the UART Data Register not empty Interrupt */__HAL_UART_DISABLE_IT(huart, UART_IT_RXNE);
.......
.......
HAL_UART_RxCpltCallback();
.......
}
解决方案:
显然,在Main()中每次调用HAL_UART_Receive_IT()后,都能收到一批数据,那么采用循环的方式也可以持续接收到串口数据。但是这样做和“查询接收”没啥区别了吧。另一种更好的思路是:每完成一批数据接收后,自动使能接收中断。
而在UART_Receive_IT()函数中调用了接收回调函数HAL_UART_RxCpltCallback()。只要在这个回调函数中末尾再添加HAL_UART_Receive_IT(),重新打开串口接收中断、并设定接收的数据量就解决了。
提示:这里填写该问题的具体解决方案:
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *UartHandle)
{.............
.............
HAL_UART_Receive_IT(UartHandle, (uint8_t *)aRxBuffer, RXBUFFERSIZE);
}