【STM32】串口DMA收发
DMA(Direct Memory Access)允许外设和内存之间在不占用 CPU 的情况下直接进行数据传输。DMA 大幅度降低 CPU 开销,适合高速、大批量数据收发;使用 HAL 库时,传输完成的回调函数依然需要正确书写;DMA 配置时需注意内存自增、传输宽度、模式等细节;可与中断方式互补使用,提升系统效率。
·
STM32 串口 DMA收发
本笔记整理 STM32 使用 DMA 进行串口收发的原理、配置要点与实际代码示例,适合快速理解 DMA 在串口通信中的应用。
一、基本概念回顾
✅ 什么是 DMA?
DMA(Direct Memory Access)允许外设和内存之间在不占用 CPU 的情况下直接进行数据传输。
✅ DMA 的特性
- 一个 DMA 控制器包含多个通道或流。
- 每个通道在同一时间只能处理一个传输。
- 同一时刻,一个 DMA 控制器只处理一个通道任务,按优先级顺序执行。
- 可以设置为:
- 内存地址自增(常见)
- 外设地址固定(例如 USART 数据寄存器)
- 数据宽度:字节、半字、字
- 普通模式或循环模式(用于连续接收)
✅ 串口 DMA 的方向
- 发送:内存 ➝ 外设(
USARTx->TDR) - 接收:外设 ➝ 内存(
USARTx->RDR)
二、串口 DMA 发送流程
- 配置并启动 DMA,设置源地址为内存,目标地址为串口发送寄存器(TDR)。
- 启动 DMA 传输,DMA 自动将数据一字节一字节写入 TDR。
- 传输完成后会触发 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 接收流程
- 配置 DMA,从 USART 的
RDR寄存器读取数据写入内存。 - 设置内存自增,外设地址固定。
- 当接收设定数量数据后触发 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 配置时需注意内存自增、传输宽度、模式等细节;
- 可与中断方式互补使用,提升系统效率。
❤️ 你的点赞与评论是我持续更新的最大动力!
更多推荐



所有评论(0)