📘 STM32 串口中断接收方式笔记:HAL_UART_Receive_IT
vs __HAL_UART_ENABLE_IT
🧠 1. 两者作用简述
函数/宏 |
作用 |
是否配置HAL状态 |
是否调用Rx回调 |
HAL_UART_Receive_IT() |
启动一次基于中断的串口接收任务 |
✅ 是 |
✅ 是 |
__HAL_UART_ENABLE_IT() |
手动使能某个串口中断(如RXNE) |
❌ 否 |
❌ 否(除非配合HAL函数) |
🔧 2. HAL_UART_Receive_IT()
的工作机制
HAL_UART_Receive_IT(&huart1, rx_buf, 10);
注意:接收完成后,不会自动重新启动接收,需要你手动再次调用 HAL_UART_Receive_IT()
。
⚠️ 3. 使用 __HAL_UART_ENABLE_IT()
的注意事项
__HAL_UART_ENABLE_IT(&huart1, UART_IT_RXNE);
- 只是打开了
USART1
的接收中断 RXNE
。
- 并不会设置 HAL 的接收状态、缓冲区等内部变量。
- 如果你还调用了
HAL_UART_IRQHandler()
,会因 HAL 状态未准备好,导致:
- 中断进来了
RXNE
置位
- HAL 不消费数据
RXNE
不会被清除
- 中断一直触发 → 卡死!
✅ 正确用法对比
✅ 【方式1】HAL自动管理方式(推荐新手/结构清晰)
HAL_UART_Receive_IT(&huart1, rx_buf, 1);
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
if (huart->Instance == USART1) {
HAL_UART_Receive_IT(&huart1, rx_buf, 1);
}
}
✅ 【方式2】裸中断方式(适合自定义接收流程)
__HAL_UART_ENABLE_IT(&huart1, UART_IT_RXNE);
void USART1_IRQHandler(void)
{
if (__HAL_UART_GET_FLAG(&huart1, UART_FLAG_RXNE)) {
uint8_t ch = (uint8_t)(huart1.Instance->RDR);
}
}
🔄 4. 总结对比表
项目 |
HAL_UART_Receive_IT() |
__HAL_UART_ENABLE_IT() + 手动处理 |
接收管理 |
HAL帮你管理接收缓冲 |
你自己处理 |
接收长度 |
固定长度 |
可灵活按字节 |
回调机制 |
自动调用 RxCpltCallback |
你自己写中断函数 |
中断使能 |
内部自动配置 |
你自己配置 |
出错风险 |
小 |
大(忘记清标志位或缓冲区会卡死) |
场景推荐 |
简单数据帧、串口透传 |
协议解析、环形缓冲、实时性要求高 |
🧪 5. 常见问题
问题 |
原因 |
程序卡在中断里出不来 |
只使能了 RXNE 中断,没有初始化接收任务,RXNE 一直为 1 |
接收不到数据 |
没有调用 HAL_UART_Receive_IT() ,或中断未使能 |
回调函数不触发 |
没有使用 HAL 接收函数,或 HAL 状态机异常 |
中断乱跳、多次进中断 |
收数据没及时读 RDR ,或 RXNE 没清除 |