STM32 串口 DMA收发

本笔记整理 STM32 使用 DMA 进行串口收发的原理、配置要点与实际代码示例,适合快速理解 DMA 在串口通信中的应用。


一、基本概念回顾

✅ 什么是 DMA?

DMA(Direct Memory Access)允许外设和内存之间在不占用 CPU 的情况下直接进行数据传输。

✅ DMA 的特性

  • 一个 DMA 控制器包含多个通道
  • 每个通道在同一时间只能处理一个传输
  • 同一时刻,一个 DMA 控制器只处理一个通道任务,按优先级顺序执行。
  • 可以设置为:
    • 内存地址自增(常见)
    • 外设地址固定(例如 USART 数据寄存器)
    • 数据宽度:字节、半字、字
    • 普通模式或循环模式(用于连续接收)

✅ 串口 DMA 的方向

  • 发送:内存 ➝ 外设(USARTx->TDR
  • 接收:外设 ➝ 内存(USARTx->RDR

二、串口 DMA 发送流程

  1. 配置并启动 DMA,设置源地址为内存,目标地址为串口发送寄存器(TDR)。
  2. 启动 DMA 传输,DMA 自动将数据一字节一字节写入 TDR。
  3. 传输完成后会触发 DMA 中断,间接触发 HAL_UART_TxCpltCallback 回调函数。

✅ 示例代码:使用 DMA 发送

uint8_t txData[] = "DMA Send Test";
HAL_UART_Transmit_DMA(&huart1, txData, sizeof(txData) - 1);

✅ 回调函数处理:

void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart) {
    if (huart->Instance == USART1) {
        // DMA 发送完成后的处理逻辑
    }
}

三、串口 DMA 接收流程

  1. 配置 DMA,从 USART 的 RDR 寄存器读取数据写入内存。
  2. 设置内存自增,外设地址固定。
  3. 当接收设定数量数据后触发 DMA 中断,调用 RxCpltCallback()

✅ 示例代码:使用 DMA 接收

uint8_t rxBuffer[64];
HAL_UART_Receive_DMA(&huart1, rxBuffer, sizeof(rxBuffer));

✅ 回调函数处理:

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) {
    if (huart->Instance == USART1) {
        // 处理 rxBuffer 中接收到的数据
    }
}

四、模式说明

模式 含义 应用场景
普通模式 一次性接收指定长度 短报文通信
循环模式 接收缓冲区满后自动回到开头继续写入 长时间监听串口,如日志或传感器

💡 循环模式常结合 IDLE 中断判断一次传输结束。


五、注意事项

  • DMA 使用中 CPU 不干预数据搬运,效率高。
  • DMA 通道冲突可能导致传输失败,需在 .ioc 或代码中妥善配置。
  • 使用 DMA 依然存在中断(传输完成)!RxCpltCallback()TxCpltCallback() 依然是由中断触发的!
  • 若使用循环模式接收,需结合 USART 的 IDLE 中断 辨别帧尾。

六、总结

  • DMA 大幅度降低 CPU 开销,适合高速、大批量数据收发;
  • 使用 HAL 库时,传输完成的回调函数依然需要正确书写;
  • DMA 配置时需注意内存自增、传输宽度、模式等细节;
  • 可与中断方式互补使用,提升系统效率。

❤️ 你的点赞与评论是我持续更新的最大动力!

Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐