当前位置: 首页 > news >正文

STM32F407 HAL库使用 DMA_Normal 模式实现 UART 循环发送(无需中断)

在 STM32 开发中,很多人喜欢使用 DMA 来加速串口发送数据。然而,默认的 DMA 往往配合中断或使用循环模式(DMA_CIRCULAR)使用。但在某些特定需求下,我们希望:

  • 使用 DMA_NORMAL 模式,确保 DMA 每次只发送固定长度数据;

  • 不启用任何中断,完全通过轮询实现“自动重发”机制;

  • 实现串口缓冲区数据循环发送;

本文将以 STM32F407 + USART1 + DMA2_Stream7 为例,展示如何实现这个功能。


一、基本原理

  • DMA_NORMAL 模式下,每次发送完成后 EN 位会自动清除;

  • 通过轮询 EN 位是否为 0,可以判断是否传输完成;

  • 判断完成后,手动重新配置 DMA 参数,并重新启动;

  • 整个过程不依赖中断,逻辑清晰、稳定可靠。


二、DMA 和串口初始化

void MX_USART1_UART_Init(void)
{huart1.Instance = USART1;huart1.Init.BaudRate = 115200;huart1.Init.WordLength = UART_WORDLENGTH_8B;huart1.Init.StopBits = UART_STOPBITS_1;huart1.Init.Parity = UART_PARITY_NONE;huart1.Init.Mode = UART_MODE_TX_RX;huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;huart1.Init.OverSampling = UART_OVERSAMPLING_16;HAL_UART_Init(&huart1);
}void HAL_UART_MspInit(UART_HandleTypeDef* huart)
{GPIO_InitTypeDef GPIO_InitStruct = { 0 };if(huart->Instance == USART1){/* USER CODE BEGIN USART1_MspInit 0 *//* USER CODE END USART1_MspInit 0 *//* Peripheral clock enable */__HAL_RCC_USART1_CLK_ENABLE();__HAL_RCC_GPIOA_CLK_ENABLE();/**USART1 GPIO ConfigurationPA9     ------> USART1_TXPA10     ------> USART1_RX*/GPIO_InitStruct.Pin = GPIO_PIN_9 | GPIO_PIN_10;GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;GPIO_InitStruct.Pull = GPIO_NOPULL;GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;GPIO_InitStruct.Alternate = GPIO_AF7_USART1;HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);/* USART1 DMA Init *//* USART1_RX Init */hdma_usart1_rx.Instance = DMA2_Stream2;hdma_usart1_rx.Init.Channel = DMA_CHANNEL_4;hdma_usart1_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;hdma_usart1_rx.Init.PeriphInc = DMA_PINC_DISABLE;hdma_usart1_rx.Init.MemInc = DMA_MINC_ENABLE;hdma_usart1_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;hdma_usart1_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;hdma_usart1_rx.Init.Mode = DMA_NORMAL;hdma_usart1_rx.Init.Priority = DMA_PRIORITY_MEDIUM;hdma_usart1_rx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;if(HAL_DMA_Init(&hdma_usart1_rx) != HAL_OK){Error_Handler();}__HAL_LINKDMA(huart, hdmarx, hdma_usart1_rx);/* USART1_TX Init */hdma_usart1_tx.Instance = DMA2_Stream7;hdma_usart1_tx.Init.Channel = DMA_CHANNEL_4;hdma_usart1_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;hdma_usart1_tx.Init.PeriphInc = DMA_PINC_DISABLE;hdma_usart1_tx.Init.MemInc = DMA_MINC_ENABLE;hdma_usart1_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;hdma_usart1_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;hdma_usart1_tx.Init.Mode = DMA_NORMAL;hdma_usart1_tx.Init.Priority = DMA_PRIORITY_MEDIUM;hdma_usart1_tx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;if(HAL_DMA_Init(&hdma_usart1_tx) != HAL_OK){Error_Handler();}__HAL_LINKDMA(huart, hdmatx, hdma_usart1_tx);}}

三、首次启动 DMA

#define TX_LEN 10
uint8_t uart_send_buffer[TX_LEN] = "Hello DMA";void DMA_UART1_SendStart(void)
{__HAL_DMA_DISABLE(&hdma_usart1_tx);while ((hdma_usart1_tx.Instance->CR & DMA_SxCR_EN) != 0);hdma_usart1_tx.Instance->NDTR = TX_LEN;hdma_usart1_tx.Instance->PAR  = (uint32_t)&USART1->DR;hdma_usart1_tx.Instance->M0AR = (uint32_t)uart_send_buffer;__HAL_DMA_CLEAR_FLAG(&hdma_usart1_tx, DMA_FLAG_TCIF3_7);__HAL_DMA_ENABLE(&hdma_usart1_tx);huart1.Instance->CR3 |= USART_CR3_DMAT;  // 启用 DMA 发送功能
}

四、主循环中实现自动重发

void main(void)
{while (1){if ((hdma_usart1_tx.Instance->CR & DMA_SxCR_EN) == 0){// 修改内容(模拟数据更新)uart_send_buffer[0]++;// 重启 DMAhdma_usart1_tx.Instance->NDTR = TX_LEN;__HAL_DMA_CLEAR_FLAG(&hdma_usart1_tx, DMA_FLAG_TCIF3_7);__HAL_DMA_ENABLE(&hdma_usart1_tx);}}
}

五、总结

这种轮询 + DMA_NORMAL 模式非常适合:

  • 周期性发送固定格式数据;

  • 不想被中断打断主循环的逻辑;

  • 希望更强控制发送时机、避免 DMA 无限循环死锁。

http://www.xdnf.cn/news/114301.html

相关文章:

  • Postman设置环境变量与Token
  • idea连接远程服务器kafka
  • 学习海康VisionMaster之顶点检测
  • Rust 数据类型
  • 【“星睿O6”AI PC开发套件评测】开箱+刷机+基础环境配置
  • wordpress学习笔记
  • Trae+DeepSeek学习Python开发MVC框架程序笔记(二):使用4个文件实现MVC框架
  • 决策树在金融分析中有诸多应用场景
  • C语言——函数
  • 32BIT的SPI主机控制
  • 架构-系统工程与信息系统基础
  • 【Spring Boot】深入解析:#{} 和 ${}
  • java Springboot使用扣子Coze实现实时音频对话智能客服
  • 低空AI系统的合规化与标准化演进路径
  • 考研英一学习笔记
  • 数据结构——二叉树,堆
  • 【农气项目】基于适宜度的产量预报
  • Unity性能优化实战:用Profiler揪出卡顿元凶 (CPU/GPU/内存/GC全面解析) (Day 37)
  • http协议、全站https
  • 特征存储的好处:特征存储在机器学习开发中的优势
  • 【Linux】基于阻塞队列的生产消费者模型
  • 水上与水下遥控技术要点对比
  • 利用软件I2C驱动OLED,点亮、熄灭OLED屏幕以及获取当前OLED屏幕开启状态
  • 水域陆地两相宜,便携漏电探测仪
  • 【数据分析】酵母实验多指标数据的 R 语言分析与可视化
  • YOLOv11改进-双Backbone架构:利用双backbone提高yolo11目标检测的精度
  • 26考研 | 王道 | 数据结构 | 第七章 查找
  • SpringBoot | 构建客户树及其关联关系的设计思路和实践Demo
  • WHAT - 区分 Git PR 和 MR
  • UML 活动图详解:以机票预订系统用户注册为例