[CubeMX] 串口 DMA
使用 STM32CubeMX 配置 USART + DMA 并编写测试程序,一般分为三个部分:
- CubeMX 图形化配置
- 生成代码后的初始化确认
- 编写 DMA 收发测试代码
测试可用
一、CubeMX 配置步骤
1 配置串口
进入 Pinout & Configuration
选择一个 USART,例如:
Connectivity → USART1
Mode → Asynchronous
配置参数:
- Baud Rate:115200
- Word Length:8 Bits
- Parity:None
- Stop Bits:1
- Hardware Flow Control:Disable
启用
USART1 global interrupt
2 开启 DMA
在 USART 配置页面:
USART1 → DMA Settings
添加两个 DMA:
TX DMA
Add → USART1_TX
Direction → Memory to Peripheral
Mode → Normal
Priority → Low / Medium
RX DMA
Add → USART1_RX
Direction → Peripheral to Memory
Mode → Circular(推荐)
Priority → High
说明:
| DMA模式 | 作用 |
|---|---|
| Normal | 一次传输结束停止 |
| Circular | 自动循环接收(适合串口) |
通常:
- TX:Normal
- RX:Circular
3 NVIC 配置
CubeMX 一般会自动启用:
DMAx Streamx interrupt
USARTx global interrupt
确认以下中断开启:
DMA RX IRQ
DMA TX IRQ
USART IRQ
4 时钟配置
在 Clock Configuration
确保:
APB USART 时钟正常
例如:
USART1 → APB2
USART2 → APB1
5 生成代码
Project Manager:
Toolchain → Makefile / STM32CubeIDE / CMake
点击
GENERATE CODE
二、CubeMX生成的关键代码
生成后你会看到:
UART Handle
UART_HandleTypeDef huart1;
DMA Handle
DMA_HandleTypeDef hdma_usart1_rx;
DMA_HandleTypeDef hdma_usart1_tx;
初始化
MX_USART1_UART_Init();
MX_DMA_Init();
注意:
MX_DMA_Init() 必须在 USART 初始化之前
三、DMA 发送测试代码
发送最简单:
uint8_t tx_buf[] = "Hello DMA UART\r\n";
HAL_UART_Transmit_DMA(&huart1, tx_buf, sizeof(tx_buf)-1);
发送完成会进入回调:
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
{
if(huart->Instance == USART1)
{
// 发送完成
}
}
四、DMA 接收测试代码
定义接收缓冲区:
uint8_t rx_buf[64];
启动 DMA 接收:
HAL_UART_Receive_DMA(&huart1, rx_buf, sizeof(rx_buf));
接收完成回调:
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
if(huart->Instance == USART1)
{
// 收到一帧
}
}
但是:
⚠️ 串口长度不固定时,这种方法不好用
因为:
DMA只有接满 buffer 才触发
五、推荐:IDLE + DMA 接收(工业常用)
开启:
USART → NVIC → USART global interrupt
启动 DMA:
HAL_UART_Receive_DMA(&huart1, rx_buf, sizeof(rx_buf));
开启 IDLE 中断:
__HAL_UART_ENABLE_IT(&huart1, UART_IT_IDLE);
中断处理:
void USART1_IRQHandler(void)
{
if(__HAL_UART_GET_FLAG(&huart1, UART_FLAG_IDLE))
{
__HAL_UART_CLEAR_IDLEFLAG(&huart1);
uint16_t len = sizeof(rx_buf) - __HAL_DMA_GET_COUNTER(huart1.hdmarx);
// 处理数据
}
HAL_UART_IRQHandler(&huart1);
}
优点:
- 不需要固定长度
- 适合协议解析
- 工业常用方案
六、完整测试 main 示例
uint8_t rx_buf[64];
uint8_t tx_buf[] = "DMA UART Test\r\n";
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_DMA_Init();
MX_USART1_UART_Init();
HAL_UART_Receive_DMA(&huart1, rx_buf, sizeof(rx_buf));
while (1)
{
HAL_UART_Transmit_DMA(&huart1, tx_buf, sizeof(tx_buf)-1);
HAL_Delay(1000);
}
}
七、调试建议
常见问题:
1 DMA没进中断
检查:
DMA NVIC 是否开启
2 串口没数据
检查:
GPIO AF 配置
TX RX 引脚
3 发送只成功一次
因为:
DMA Busy
需要等待回调。
八、DMA串口性能
普通发送:
HAL_UART_Transmit
CPU占用高
DMA发送:
CPU占用几乎为0
适合高速日志
例如:
printf 重定向到 DMA
License:
CC BY 4.0