1. 初识HAL库串口中断的"一次性"陷阱
第一次用STM32的HAL库做串口通信时,我遇到了一个诡异现象:从机只能收到一次数据,之后就像睡着了一样。调试了整整两天,最后发现是HAL_UART_Receive_IT这个函数在搞鬼。相信很多新手都踩过这个坑——你以为开启了中断接收,实际上它是个"一次性用品"。
HAL库的设计理念是"开箱即用",但这也意味着它隐藏了很多底层细节。比如串口中断接收,官方例程通常只展示基本用法,却不会告诉你:默认配置下,这个中断只能触发一次。就像你去餐厅点了一份自助餐,结果服务员告诉你"只能取餐一次",这谁受得了?
这里有个生动的类比:HAL库的中断接收就像自动售货机。你投币(调用HAL_UART_Receive_IT)后,它吐出一瓶饮料(触发一次中断)。但如果你还想再买,必须重新投币(重新调用接收函数)。而很多开发者误以为这是"无限畅饮"模式。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 深入源码:揭开单次触发的秘密
2.1 HAL_UART_Receive_IT的工作机制
让我们打开stm32f1xx_hal_uart.c,看看这个函数到底做了什么:
c复制HAL_StatusTypeDef HAL_UART_Receive_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)
{
if(huart->RxState == HAL_UART_STATE_READY) {
huart->pRxBuffPtr = pData;
huart->RxXferSize = Size;
huart->RxXferCount = Size;
huart->RxState = HAL_UART_STATE_BUSY_RX;
/* Enable the UART Error Interrupt */
__HAL_UART_ENABLE_IT(huart, UART_IT_ERR);
/* Enable the UART Data Register not empty Interrupt */
__HAL_UART_ENABLE_IT(huart, UART_IT_RXNE);
return HAL_OK;
}
return HAL_BUSY;
}
关键点在于它只做了三件事:
- 设置接收缓冲区和长度
- 标记状态为"忙"
- 使能RXNE(接收寄存器非空)中断
2.2 中断服务函数的"自杀"行为
问题出在中断服务函数里。当数据到来时,HAL库的处理流程是这样的:
c复制void HAL_UART_IRQHandler(UART_HandleTypeDef *huart)
{
/* 接收中断处理 */
if((__HAL_UART_GET_IT(huart, UART_IT_RXNE) != RESET) &&
(__HAL_UART_G
