HAL_UART_Receive_DMA仅工作一次如何修复?STM32F103RB串口回环问题
问题分析与解决方案
核心问题原因
- UART溢出错误未处理:普通模式DMA接收完成后,若后续有新数据到来但DMA未及时重启,会触发UART的溢出错误(ORE),导致UART被锁死,无法继续接收数据,同时错误标志会引入异常字节(如0xFC)。
- 回调内阻塞操作风险:
HAL_UART_Transmit是阻塞函数,在中断回调中调用可能占用中断上下文,影响后续DMA重启逻辑。 - DMA重启前未校验UART状态:直接调用
HAL_UART_Receive_DMA前未清除UART错误标志,导致接收重启失败。
修复后的代码实现
#define BUF_SIZE 16 uint8_t RX_BUF[BUF_SIZE] = {0}; uint8_t TX_BUF[BUF_SIZE] = {0}; // UART接收完成回调 void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) { if(huart->Instance == USART2) { // 清除UART溢出错误标志(关键步骤) if(__HAL_UART_GET_FLAG(huart, UART_FLAG_ORE)) { __HAL_UART_CLEAR_OREFLAG(huart); } // 用DMA发送替代阻塞发送,避免中断上下文阻塞 HAL_UART_Transmit_DMA(&huart2, RX_BUF, BUF_SIZE); } } // UART发送完成回调 void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart) { if(huart->Instance == USART2) { // 发送完成后重启DMA接收 HAL_UART_Receive_DMA(&huart2, RX_BUF, BUF_SIZE); } } int main(void) { HAL_Init(); SystemClock_Config(); MX_GPIO_Init(); MX_DMA_Init(); MX_USART2_UART_Init(); // 启动首次DMA接收 HAL_UART_Receive_DMA(&huart2, RX_BUF, BUF_SIZE); while (1) { } }
额外优化与排查点
- CubeMX配置检查:确保USART2的中断优先级高于DMA中断,避免中断抢占导致逻辑混乱;同时确认DMA通道的数据宽度与UART配置一致(8位数据位对应DMA字节传输)。
- USB-C转接器排查:若代码修复后仍有问题,可更换转接器测试——部分廉价转接器存在信号不稳定或兼容性问题,可能导致串口丢包或错误帧。
- 数据长度匹配:若测试时发送的字节数不等于
BUF_SIZE,普通模式DMA会等待缓冲区填满才触发回调。若需支持任意长度数据,可改用DMA循环模式,配合UART空闲中断实现不定长接收。
内容的提问来源于stack exchange,提问作者Herman Shpryhau
相关产品推荐
相关产品推荐

