用DMA+空闲中断实现STM32串口不定长接收时,如何正确处理半包与粘包

· 8 浏览

回答(4)

粘包关键是解析后移动读指针而不是清空缓冲区,DMA循环模式下用剩余计数算新增长度,注意读写指针临界区保护。
硬件阿杰 · 2026-10-18
半包用超时定时器兜底:收到数据后启动单次定时器,超时仍未凑齐一帧就丢弃并复位解析状态,避免死等。
码农小刘 · 2026-10-18
空闲中断只代表线路静默,不是完整帧。建议协议层加帧头+长度+CRC,空闲中断只负责把DMA数据搬进环形缓冲,解析交给主循环状态机。
嵌入式老张 · 2026-10-18
核心思路是把“空闲中断”当作帧边界,而不是数据完成标志。DMA按字节流搬运,空闲中断只说明总线静默了一个字符时间,因此必须结合长度和协议头尾判断。推荐做法:串口DMA配置为循环模式,空闲中断里读取DMA剩余计数,算出本次新增字节数,把数据拷贝到软件环形缓冲区,再重置DMA计数或重新启动DMA。半包处理:不要一收到空闲就立即解析,先在环形缓冲区中按协议找帧头、帧长或帧尾;若长度不足或校验不完整,保留数据等待下一批,设置超时定时器,超时后丢弃或上报错误。粘包处理:解析时用状态机逐帧消费,每解析完一帧就移动读指针,剩余数据继续留在缓冲区,不能一次性清空。注意临界区保护读写指针,DMA缓冲区建议2的幂大小,空闲中断中只做搬运和置标志,解析放到主循环。若使用HAL库,注意HAL_UARTEx_ReceiveToIdle_DMA的回调长度参数是本次接收长度,仍需自己维护环形缓冲。
mcuku 阿沐 · 2026-10-18