stm32的USART使用DMA配置成循环模式时发送和接收有着本质区别,不要被网上误导了。发送数据时会不停的发送数据,而接收只有有数据时才会接收,没有数据时就会挂起等待。
一、触发机制的差异
发送方向(TX)——状态驱动型
- 触发源:USART的TXE标志(发送数据寄存器空)。
- 工作流程:
- 当发送数据寄存器为空时,TXE标志置位。
- DMA立即响应TXE事件,从内存读取数据填充寄存器,形成不间断传输循环。
- 关键特性:
- 无数据时仍持续搬运:即使总线空闲,只要DMA通道开启且源地址有数据,会反复发送旧数据(可能无效)。
- 主动推送:表现为“永动机”模式,需手动关闭DMA通道才能停止。
接收方向(RX)——事件驱动型
- 触发源:起始位(Start Bit)检测23。
- 工作流程:
- 串口线路检测到起始位(下降沿),激活接收逻辑。
- 每接收一字节数据后,RXNE标志(接收寄存器非空)触发DMA搬运至内存。
- 关键特性:
- 严格依赖物理信号:无数据时,DMA挂起等待,不消耗总线资源。
- 按需响应:仅当实际数据到达时触发传输,避免无效操作。
🔧 二、硬件行为对比
特性 | 发送(TX) | 接收(RX) |
---|---|---|
触发条件 | TXE寄存器空(持续存在)12 | 起始位下降沿(瞬态事件)24 |
无数据时行为 | 持续填充旧数据56 | 完全挂起等待37 |
数据有效性 | 可能无效(需主动更新)5 | 仅搬运有效物理信号48 |
节能特性 | 高功耗(持续占用总线)1 | 低功耗(事件唤醒)78 |
⚠️ 三、循环模式下的设计风险
发送方向的风险
- 总线干扰:循环发送旧数据可能破坏协议(如RS-485半双工冲突)。
- 解决方案:
- 发送完成后立即关闭DMA通道(
HAL_DMA_Abort()
)。 - 使用双缓冲机制更新发送数据,避免覆盖未发送完成的数据5。
- 发送完成后立即关闭DMA通道(
接收方向的风险
- 数据覆盖:循环缓冲区未及时处理时,新数据覆盖旧帧。
- 解决方案:
启用IDLE中断检测帧结束,配合DMA传输计数计算帧长。
使用双缓冲区切换:一组缓冲区满时自动切换至备用区。
✅ 四、本质差异总结
- 触发逻辑不同:
- 发送由内部状态标志(TXE)驱动,无需外部事件12。
- 接收由物理信号(起始位)触发,严格依赖线路活动34。
- 硬件协作机制:
- 发送是CPU/DMA主动推送,接收是DMA被动响应27。
- 应用场景设计:
- 发送循环模式仅适用于心跳包、周期性数据流(需手动刷新数据)56。
- 接收循环模式适合连续数据流监听(如传感器实时采集)48。
💡 扩展说明:为何硬件如此设计?
- 发送的“主动性”:确保通信时序可控(如波特率精度要求),需持续维持数据流12。
- 接收的“被动性”:避免总线冲突(多设备共享线路时),仅响应有效信号37。
- 能效优化:接收挂起显著降低功耗,适用于电池供电场景48。
通过理解这一差异,可优化通信协议设计:发送方向需主动管理数据生命周期,接收方向则依赖事件中断同步帧边界。
理解接收的本质区别后,只要串口的接收DMA配置成循环模式时,需要启动一次接收即可,在HAL库变现为下面一句代码只需要调用一次即可。
HAL_UARTEx_ReceiveToIdle_DMA(&huart1,gRxBuf,sizeof(gRxBuf));