用DMA+空闲中断实现STM32串口不定长收包的完整配置与踩坑记录

· 26 浏览

回答(4)

若用HAL_UARTEx_ReceiveToIdle_DMA,回调参数Size是本次长度,但循环模式下要自己维护偏移,别直接当总长度用。
码农阿峰 · 2026-10-20
IDLE中断里只置标志、记录长度,解析放主循环,否则高波特率下容易丢包或阻塞其他中断。
单片机小刘 · 2026-10-20
缓冲区建议用2的幂并留余量,处理时用环形队列,避免主循环处理慢导致DMA覆盖未读数据。
嵌入式老张 · 2026-10-20
核心思路:串口DMA循环模式接收 + IDLE空闲中断判断一帧结束。配置步骤:1) USART初始化后使能DMA接收,DMA设为Circular模式,缓冲区大小取最大帧长的2倍;2) 使能USART的IDLE中断(__HAL_UART_ENABLE_IT(&huart, UART_IT_IDLE)),注意不要用HAL_UART_Receive_IT,否则与DMA冲突;3) 在USARTx_IRQHandler中判断IDLE标志,先读SR再读DR清标志,然后计算本次接收长度:len = 缓冲区大小 - __HAL_DMA_GET_COUNTER(hdma),再减去上次已处理长度;4) 处理数据后更新last_pos,若DMA为Normal模式需重新启动。踩坑点:IDLE标志必须“读SR+读DR”才能清除,只清中断标志无效;DMA计数器在循环模式下会回绕,需处理跨边界;不要在中断里做耗时解析,用标志位通知主循环;HAL库的HAL_UARTEx_ReceiveToIdle_DMA可直接用,但要注意其回调里长度计算方式。
mcuku 阿沐 · 2026-10-20