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

STM32的DMA入门指南:让单片机学会“自动搬运“数据

STM32的DMA入门指南:让单片机学会"自动搬运"数据

引言:CPU的烦恼

想象你是一个快递分拣员,每天要手动把成千上万的包裹从卡车搬到仓库。这时候如果有个自动传送带能帮你完成搬运工作,你就可以专心处理更重要的订单核对和异常件处理。在单片机世界里,CPU就扮演着这个"分拣员"的角色,而DMA(直接存储器访问)就是那条神奇的传送带。

一、DMA是什么?

DMA全称Direct Memory Access,中文名"直接存储器访问"。它就像单片机内部的"物流系统",能让外设(比如ADC、SPI、UART)和内存之间直接传输数据,全程不需要CPU参与搬运工作。

为什么需要DMA?

  • 解放CPU:传统方式传输1KB数据需要CPU执行上万条指令,DMA只需配置一次就能自动完成
  • 提升效率:传输数据时CPU可以处理其他任务(比如同时控制电机和读取传感器)
  • 降低功耗:CPU不用频繁唤醒处理数据搬运,特别适合低功耗场景

二、工作原理三步走

  1. 配置阶段:告诉DMA要搬运什么数据(源地址、目标地址、数据量)
  2. 启动传输:CPU发出开始指令后就可以去"摸鱼"了
  3. 自动搬运:DMA控制器按照预设规则自动完成数据传输,传输完成后可以触发中断通知CPU

三、STM32配置实战(以串口发送为例)

硬件准备

  • STM32开发板(以F1系列为例)
  • USB转TTL模块
  • 杜邦线若干

配置步骤(使用HAL库)

// 1. 定义DMA句柄
DMA_HandleTypeDef hdma_usart1_tx;// 2. 初始化DMA参数
void DMA_Init(void) {hdma_usart1_tx.Instance = DMA1_Channel4;  // 对应USART1_TXhdma_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_usmart1_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;    // 内存数据宽度hdma_usart1_tx.Init.Mode = DMA_NORMAL;                 // 普通模式(单次传输)hdma_usart1_tx.Init.Priority = DMA_PRIORITY_LOW;       // 优先级设置HAL_DMA_Init(&hdma_usart1_tx);// 3. 关联DMA到串口__HAL_LINKDMA(&huart1, hdmatx, hdma_usart1_tx);
}// 4. 启动DMA传输
void Send_With_DMA(uint8_t *pData, uint16_t Size) {HAL_UART_Transmit_DMA(&huart1, pData, Size);
}

关键配置项解析

配置项作用说明典型值选择
Direction数据传输方向MEM→PERIPH/PERIPH→MEM
Memory/Periph Inc地址是否自动递增ENABLE/DISABLE
Data Alignment数据宽度对齐BYTE/HALFWORD/WORD
Mode传输模式NORMAL(单次)/CIRCULAR(循环)
Priority通道优先级LOW/MEDIUM/HIGH/VERY_HIGH

四、实际应用场景

场景1:串口持续发送数据

uint8_t big_data[1024] = {0};  // 假设要发送1KB数据// 初始化时配置DMA为循环模式
hdma_usart1_tx.Init.Mode = DMA_CIRCULAR;// 主循环中只需更新数据
while(1) {update_data(big_data);      // 更新要发送的内容// DMA会自动持续发送,无需CPU干预
}

场景2:ADC连续采样

// 配置ADC为DMA连续转换模式
hadc1.Instance->CR2 |= ADC_CR2_DMA;
hadc1.DMA_Handle = &hdma_adc;// 启动ADC+DMA
HAL_ADC_Start_DMA(&hadc1, adc_buffer, BUFFER_SIZE);// 现在CPU可以:
// - 处理按键输入
// - 控制LED显示
// - 进行数学计算
// 而ADC会持续采样并存入缓冲区

五、新手常见问题

Q1:DMA和中断可以同时用吗?
A:完全可以!可以在DMA传输完成后触发中断,实现"传输完成通知"功能。

Q2:使用DMA会占用CPU资源吗?
A:传输过程中CPU完全空闲,只有在配置DMA和响应中断时才会短暂占用。

Q3:数据量有限制吗?
A:单个传输最大支持65535个数据(16位计数器),超过需要分段传输。

Q4:调试技巧

  • 使用CubeMX生成初始化代码
  • 通过内存窗口观察数据传输情况
  • 用逻辑分析仪抓取总线信号

六、进阶技巧

  1. 双缓冲机制:准备两个缓冲区,交替进行数据采集和处理
  2. 通道优先级:为关键任务分配高优先级DMA通道
  3. 错误处理:配置DMA错误中断(传输超时、FIFO错误等)
  4. 结合其他外设:用DMA实现SPI+FLASH的自动读写

结语

DMA就像给单片机装上了智能传送带,让数据搬运这种体力活完全自动化。刚开始配置时可能会觉得参数复杂,但只要记住"三要素":

  1. 数据方向(从哪里搬到哪里)
  2. 地址变化(地址是否自动递增)
  3. 传输模式(单次还是循环)

就能轻松玩转DMA。实际开发中建议先用CubeMX生成基础代码,再逐步理解每个参数的作用。记住:好的DMA配置,应该像设置自动咖啡机一样——设置一次,享受一整天的便利。

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

相关文章:

  • 【Day38】
  • C语言_文件操作
  • 【深度学习-Day 18】从SGD到Adam:深度学习优化器进阶指南与实战选择
  • 【JavaSE】枚举和注解学习笔记
  • 高考加油(Python+HTML)
  • 青少年编程与数学 02-020 C#程序设计基础 07课题、控制结构
  • Android设置界面层级为最上层实现
  • 【数据集】EarthExplore下载Landsat LST 数据
  • Java网络编程性能优化
  • 【Vue Vapor Mode :技术突破与性能优化的可能性】
  • 嵌入式学习--江协stm32day1
  • 第9章:网络协议栈与 IoT 通信
  • React 第四十七节 Router 中useLinkClickHandler使用详解及开发注意事项案例
  • React 第四十八节 Router中 useMatch 的使用详细介绍及案例分析
  • React---day2
  • 微服务及容器化设计--可扩展的架构设计
  • Python 中的 for 循环:从基础到高级应用的全面解析
  • WPF【09】WPF基础入门 (三层架构与MVC架构)
  • 沈阳城市空气质量综合评价系统/答辩以及详细讲解
  • 基于cornerstone3D的dicom影像浏览器 第二十四章 显示方位、坐标系、vr轮廓线
  • Python requests
  • App Runner和Task Pipeline中的数据库连接管理指南
  • 【数据结构】树形结构--二叉树
  • U-Boot ARMv8 平台异常处理机制解析
  • Android studio 查看aar源码出现/* compiled code */
  • 基于 MindQuantum 记录线路作用下基底态的变化过程
  • 让jupyter notebook显示目录
  • 大模型应用:开发移动端页面个人中心页面提示词
  • 基于大模型预测视神经脊髓炎的技术方案大纲
  • Ubuntu 20.04 下 OpenCV 4.5.4 编译安装与系统默认 OpenCV 4.2 共存切换指南【2025最新版!!!】