单片机STM32F103:DMA的原理以及应用

STM32F103系列微控制器(基于ARM Cortex-M3内核)集成了**DMA(Direct Memory Access,直接内存访问)**控制器,用于在存储器与外设、存储器与存储器之间高效传输数据,减少CPU的干预,从而提升系统性能。本文将详细介绍STM32F103的DMA原理、架构、功能特性及使用方法,结合实际代码示例说明如何在开发中应用DMA,特别以STM32CubeMX和HAL库为工具。


1. DMA原理

DMA是一种硬件机制,允许数据在存储器(Flash、SRAM)或外设(UART、SPI、ADC等)之间直接传输,而无需CPU逐字节处理。其核心思想是将数据搬运任务交给DMA控制器,CPU只需配置DMA通道并启动传输,传输完成后通过中断或查询方式获取结果。

1.1 工作原理
  • DMA控制器:STM32F103的DMA控制器管理多个通道,每个通道负责特定的数据传输任务。
  • 数据流
    • 存储器到存储器:如SRAM到SRAM。
    • 外设到存储器:如ADC数据到SRAM。
    • 存储器到外设:如SRAM数据到UART发送缓冲区。
  • 触发机制
    • DMA传输可由软件触发(手动启动)或硬件触发(外设请求,如UART发送完成)。
  • 中断支持
    • 传输完成(TC)、半传输(HT)或传输错误(TE)时可触发中断。
  • 优势
    • 降低CPU负载,适合高吞吐量任务(如ADC采样、音频流)。
    • 提高实时性,适合多任务系统。
1.2 STM32F103的DMA架构

STM32F103的DMA控制器分为DMA1DMA2(部分高密度型号支持DMA2),具体特性如下:

  • DMA1
    • 7个通道(Channel 1-7)。
    • 连接到APB1/APB2外设(如UART、SPI、ADC)及存储器。
  • DMA2(仅高密度型号,如STM32F103ZET6):
    • 5个通道(Channel 1-5)。
    • 通常用于高级外设或额外存储器访问。
  • 通道优先级
    • 每个通道可配置高、中、低优先级,解决多通道冲突。
  • 数据宽度
    • 支持8位、16位、32位数据传输。
  • 传输模式
    • 单次传输:传输固定长度数据后停止。
    • 循环模式:传输完成后自动重新开始,适合连续数据流。
    • 增量模式:支持源/目标地址自动递增或固定。
  • FIFO:STM32F103的DMA无独立FIFO,依赖外设缓冲区或直接传输。
1.3 DMA工作流程
  1. 配置DMA通道
    • 设置源地址、目标地址、数据长度。
    • 配置传输方向(存储器到外设、外设到存储器、存储器到存储器)。
    • 设置数据宽度、优先级、增量模式等。
  2. 启动传输
    • 软件触发(设置ENABLE位)或硬件触发(外设信号)。
  3. 数据传输
    • DMA控制器从源地址读取数据,写入目标地址。
  4. 完成处理
    • 传输完成后,触发中断或置位标志,通知CPU处理结果。

2. STM32F103 DMA功能特性

  • 通道数量
    • DMA1:7通道,支持ADC1/2、SPI1/2、UART1-3、I2C1/2、TIM1-4等。
    • DMA2(若有):5通道,支持高级外设或额外存储器。
  • 传输方向
    • 存储器到存储器(仅DMA1支持)。
    • 外设到存储器(如ADC采样到SRAM)。
    • 存储器到外设(如SRAM数据到UART)。
  • 中断支持
    • 传输完成中断(TCIF)。
    • 半传输中断(HTIF)。
    • 传输错误中断(TEIF)。
  • 数据对齐
    • 支持字节(8位)、半字(16位)、字(32位)传输。
    • 源和目标数据宽度可不同(如8位外设到16位SRAM)。
  • 循环模式
    • 启用后,传输完成后自动重新加载计数器,适合连续数据流。
  • 优先级管理
    • 软件配置通道优先级(Very High, High, Medium, Low)。
    • 硬件仲裁确保高优先级通道优先访问总线。

3. DMA使用方法

以下以STM32F103C8T6为例,结合STM32CubeMX和HAL库,介绍如何实现DMA传输,重点以ADC DMA(外设到存储器)和UART DMA(存储器到外设)为例。

3.1 开发环境准备
  • 硬件
    • STM32F103C8T6开发板(如“蓝板”)。
    • ST-Link V2调试器。
    • USB-TTL模块(如CH340)用于串口调试。
  • 软件
    • STM32CubeMX:配置外设和DMA。
    • STM32CubeIDE:编写和调试代码。
    • STM32CubeProgrammer:烧录程序。
    • 串口终端(如PuTTY):查看输出。
3.2 示例1:ADC DMA(外设到存储器)

目标:使用ADC1连续采样多个通道的数据,通过DMA传输到SRAM缓冲区。

3.2.1 STM32CubeMX配置
  1. 创建项目
    • 打开STM32CubeMX,选择STM32F103C8T6。
  2. 配置ADC
    • 在“Analog”中启用ADC1。
    • 配置通道(如IN0、IN1,连接到PA0、PA1)。
    • 设置为“Continuous Conversion Mode”(连续转换)。
    • 启用“DMA Continuous Requests”。
  3. 配置DMA
    • 在ADC1的“DMA Settings”中,添加DMA请求:
      • 选择DMA1 Channel 1(ADC1默认通道)。
      • 设置:
        • Mode:Circular(循环模式)。
        • Data Width:Half Word(16位,ADC为12位数据)。
        • Increment Address:Memory(目标地址递增)。
        • Priority:Medium。
  4. 配置时钟
    • 设置HSE(8MHz晶振),PLL倍频到72MHz,APB2为72MHz,ADC时钟分频到12MHz(最大14MHz)。
  5. 生成代码
    • 在“Project Manager”中设置项目名称、路径,选择“STM32CubeIDE”。
    • 生成代码。
3.2.2 代码实现

在STM32CubeIDE中,修改main.c实现ADC DMA采样:

#include "main.h"
#include "adc.h"
#include "dma.h"
#include "usart.h"
#include "stdio.h"#define ADC_CHANNEL_COUNT 2
uint16_t adcData[ADC_CHANNEL_COUNT]; // 存储ADC采样数据void SystemClock_Config(void);int main(void) {HAL_Init();SystemClock_Config();MX_DMA_Init();MX_ADC1_Init();MX_USART1_UART_Init(); // 串口用于调试// 启动ADC DMAHAL_ADC_Start_DMA(&hadc1, (uint32_t*)adcData, ADC_CHANNEL_COUNT);while (1) {// 在循环模式下,DMA自动更新adcDatachar msg[50];sprintf(msg, "ADC1: %u, ADC2: %u\r\n", adcData[0], adcData[1]);HAL_UART_Transmit(&huart1, (uint8_t*)msg, strlen(msg), 100);HAL_Delay(1000); // 每秒打印一次}
}// DMA传输完成回调(可选)
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc) {// 可在此处理传输完成后的逻辑
}

说明

  • HAL_ADC_Start_DMA启动ADC和DMA,数据自动传输到adcData数组。
  • 循环模式下,DMA自动更新缓冲区,CPU无需干预。
  • 串口(UART1)打印ADC采样值,用于调试。
3.2.3 测试
  • 烧录程序到STM32F103。
  • 连接PA0/PA1到模拟信号(如电位器)。
  • 在串口终端(如PuTTY,115200波特率)查看ADC采样值。
3.3 示例2:UART DMA(存储器到外设)

目标:通过DMA将SRAM中的数据发送到UART1。

3.3.1 STM32CubeMX配置
  1. 配置UART
    • 启用USART1(PA9-TX,PA10-RX)。
    • 设置波特率(如115200),模式为异步。
    • 在“DMA Settings”中,添加DMA请求:
      • 选择DMA1 Channel 4(USART1_TX默认通道)。
      • 设置:
        • Mode:Normal(单次传输)。
        • Data Width:Byte(8位,UART数据)。
        • Increment Address:Memory。
        • Priority:Medium。
  2. 生成代码
    • 同ADC示例,生成STM32CubeIDE项目。
3.3.2 kazhuCode实现

修改main.c实现UART DMA发送:

#include "main.h"
#include "dma.h"
#include "usart.h"
#include "string.h"uint8_t txData[] = "Hello, STM32 DMA!\r\n";void SystemClock_Config(void);void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart) {// 传输完成回调HAL_UART_Transmit(&huart1, (uint8_t*)"TX Complete\r\n", 13, 100);
}int main(void) {HAL_Init();SystemClock_Config();MX_DMA_Init();MX_USART1_UART_Init();// 启动UART DMA发送HAL_UART_Transmit_DMA(&huart1, txData, strlen((char*)txData));while (1) {HAL_Delay(1000); // 每秒发送一次HAL_UART_Transmit_DMA(&huart1, txData, strlen((char*)txData));}
}

说明

  • HAL_UART_Transmit_DMA启动DMA传输,将txData发送到UART1。
  • 传输完成后,触发HAL_UART_TxCpltCallback中断。
  • 单次模式下,需手动重新启动传输。
3.3.3 测试
  • 烧录程序。
  • 连接USB-TTL模块(PA9->RX,PA10->TX)。
  • 在串口终端查看输出“Hello, STM32 DMA!”。

4. 关键配置注意事项

  • DMA初始化顺序
    • main.c中,MX_DMA_Init必须在其他外设初始化(如MX_ADC1_InitMX_USART1_Init)之前调用,确保DMA时钟启用。
  • 通道选择
    • 每个外设有固定DMA通道(如ADC1->DMA1 Channel 1,USART1_TX->DMA1 Channel 4)。参考STM32F103参考手册。
  • 数据对齐
    • 源和目标数据宽度需匹配(如ADC为16位,缓冲区应为uint16_t)。
  • 中断管理
    • 启用DMA中断(如HAL_NVIC_EnableIRQ(DMA1_Channel1_IRQn))。
    • 在中断回调中处理传输完成或错误。
  • 循环模式 vs 单次模式
    • 循环模式适合连续数据流(如ADC采样)。
    • 单次模式适合一次性传输(如UART发送固定字符串)。
  • 优先级冲突
    • 多通道同时传输时,设置高优先级给关键任务(如ADC优于UART)。

5. 常见问题及解决

  • DMA不工作
    • 检查DMA通道是否与外设匹配。
    • 确保MX_DMA_Init在其他外设初始化前调用。
    • 验证源/目标地址正确,数据长度非零。
  • 数据错误
    • 检查数据宽度(Byte/Half Word/Word)是否与外设匹配。
    • 确保目标缓冲区有足够空间。
  • 中断未触发
    • 确认中断使能(HAL_DMA_Start_IT或外设API)。
    • 检查NVIC配置(优先级、使能)。
  • 总线冲突
    • 避免多个DMA通道同时访问同一存储器区域。
    • 调整通道优先级或降低传输速率。

6. 扩展应用

  • 多通道ADC:使用DMA采集多个ADC通道数据,存储到数组,适合信号处理。
  • SPI DMA:实现高速SPI数据传输(如与LCD或Flash通信)。
  • FreeRTOS集成:结合DMA中断和信号量,优化实时任务调度。
  • 双缓冲技术:在循环模式下使用两个缓冲区交替存储数据,避免数据覆盖。

7. 学习资源

  • 官方文档
    • STM32F103参考手册(DMA章节)。
    • STM32CubeMX用户手册。
  • 教程
    • 正点原子/野火的STM32 DMA教程。
    • ST社区论坛的DMA应用笔记(如AN2548)。
  • 工具
    • STM32CubeMonitor:监控DMA传输数据。
    • 逻辑分析仪:调试外设信号。

8. 总结

STM32F103的DMA控制器通过高效的数据传输,显著降低CPU负载,适合高吞吐量场景。DMA1支持7通道,DMA2(部分型号)支持5通道,覆盖ADC、UART、SPI等外设。使用STM32CubeMX配置DMA参数,结合HAL库(如HAL_ADC_Start_DMAHAL_UART_Transmit_DMA)可快速实现传输。关键注意初始化顺序、通道选择和数据对齐,通过中断和循环模式优化性能。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/bicheng/88598.shtml
繁体地址,请注明出处:http://hk.pswp.cn/bicheng/88598.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Webview 中可用的 VS Code 方法

在 VS Code Webview 的 HTML 中,不能直接调用 VS Code 的 API(如 vscode.window.showInformationMessage),但可以通过 acquireVsCodeApi() 获取一个受限的 vscode 对象,用于与插件主程序通信。以下是详细说明和示例&am…

Qt:布局管理器Layout

目录 布局管理器 QVBoxLayout QHBoxLayout QGirdLayout QFormLayout Spacer 布局管理器 在以往的界面操作上,都是程序员手动拖动控件来布局,这种方式有一些不足之处,比如不能很好的把握控件之间的距离,以及控件的大小&…

【Java编程动手学】深入剖析Java网络编程:原理、协议与应用

文章目录一、引言二、计算机网络基础1、计算机网络的概念2、网络地址的重要性三、套接字编程:网络通信的基石1、套接字的概念2、TCP通信编程示例四、TCP通信编程:可靠的数据传输1、TCP协议的特点2、实际应用中的TCP通信五、UDP通信编程:高效的…

vue3.2 前端动态分页算法

文章目录背景思路页面情况核心代码小结效果背景 1. 后台接口只是动态返回一个数组的数据,前端需要根据数据量的大小判断是否需要分页,页面高度固定2. 页面根据页数大小有不同的展示a. 只有一页 头部 内容 统计 尾部b. 多页i. 第一页 头部 内容 尾…

UC浏览器PC版自2016年后未再更新不支持vue3

win uc浏览器,点击页面触发异常。UC浏览器PC版自2016年后未再更新(最新版本停留在Chromium 50内核)。其内置内核版本较低(如Trident/Blink旧版),无法支持Vue 3等现代前端框架的语法特性(如ES6、…

亚古数据:澳大利亚公司的ABN和ACN号码是什么?

在跨国商业的迷宫中,了解目标市场的公司注册细节是一项不可或缺的技能。对于与中国企业有业务往来的朋友们来说,澳大利亚这片充满机遇的土地上,两个缩写——ABN与ACN,如同解锁合作之门的密钥,显得尤为重要。今天&#…

LangChain框架 Prompts、Agents 应用

目录 (Prompts)提示作用 Prompts 常见操作 基础 PromptTemplate 使用 Few-shot 提示模板 ChatPromptTemplate (对话提示模板) (Agents)代理作用 Agents 常见操作 基础 Agent 使用 自定义工具 Agent 高级应用示例 带记忆的对话代理 使用本地模型的代理 结构化输出代…

模拟实现unordered_map

1.定义unordered_map 是 C 标准库中的哈希表容器,特点是无序存储、平均 O (1) 时间复杂度的插入 / 查找 / 删除操作。其核心原理是通过哈希函数将关键字映射到哈希桶(bucket),再通过链表或红黑树处理哈希冲突。2.实现原理1. 哈希表…

史上最详细Java并发多线程(面试必备,一篇足矣)

第一章:线程基础 1.1 线程与进程 进程:系统资源分配的基本单位,拥有独立的内存空间 线程:CPU调度的基本单位,共享进程内存空间 关系:一个进程可包含多个线程,线程切换成本远低于进程 1.2 线程的…

【DataFlow】数据合成流水线工具

1.整体解读 核心思想:以数据为中心的AI(Data-Centric AI) DataFlow 的核心目标是通过一系列自动化“流水线”(Pipelines)来处理和生成高质量的数据,从而提升大语言模型(LLM)在特定领…

Hangfire 调用报错解决方案总结

System.ArgumentNullException: 值不能为 null 错误在使用 Hangfire 时确实是一个常见问题,特别是在配置 Hangfire 服务器时。问题分析这个错误通常发生在以下情况:没有正确配置 Hangfire 服务器队列配置缺失或不正确连接字符串配置问题解决方案要点正确…

MySQL的使用

MySQL的使用一、mysql中的周边命令1. 检查版本2. 查看字符集3. 查看客户端连接4. 查看最后一条警告消息二、数据库、数据表的管理1. 语法规则2. 数据库2.1 查看数据库2.2 创建数据库2.3 选择数据库2.4 查看创建数据库命令2.5 创建库时添加字符集2.6 修改数据库字符集2.7 删除数…

2025Nginx最新版讲解/面试

维护系统多服务器部署,将我们请求代理到各个服务器。代理正向代理,代理对象是我们的客户端,目标对象不知道我们用户。VPN就是典型的正向代理。反向代理,代理对象是服务端,用户不知道服务端具体信息。而这正是Nginx所做…

JAVASCRIPT 前端数据库-V8--仙盟数据库架构-—-—仙盟创梦IDE

老版本 在v1 版本中我们讲述了 基础版的应用 JAVASCRIPT 前端数据库-V1--仙盟数据库架构-—-—仙盟创梦IDE-CSDN博客 接下载我们做一个更复杂的的其他场景 由于,V1查询字段必须 id 接下来我们修改了了代码 JAVASCRIPT 前端数据库-V2--仙盟数据库架构-—-—仙盟创…

UNIX 域套接字实现本地进程间通信

🚀 使用 UNIX 域套接字 (AF_UNIX) 实现高效进程通信 在 Linux 和其他类 UNIX 系统中,进程间通信 (IPC) 的方法有很多种,例如管道、消息队列、共享内存等。然而,当你的应用程序需要在 同一台机器上的不同进程间进行高效、低延迟的数…

【Axure教程】中继器间图片的传递

中继器在Axure中可以作为图片保存的数据库,在实际系统中,我们经常需要将选择数据库的图片添加到其他图片列表中,所以今天就教大家,怎么在Axure中实现中继器之间的图片传递,包含将一个中继器中的图片列表传递到另一个中…

专题:2025云计算与AI技术研究趋势报告|附200+份报告PDF、原数据表汇总下载

原文链接:https://tecdat.cn/?p42935 关键词:2025, 云计算,AI 技术,市场趋势,深度学习,公有云,研究报告 云计算和 AI 技术正以肉眼可见的速度重塑商业世界。过去十年,全球云服务收…

从代码学习深度强化学习 - PPO PyTorch版

文章目录 前言PPO 算法简介从 TRPO 到 PPOPPO 的两种形式:惩罚与截断代码实践:PPO 解决离散动作空间问题 (CartPole)环境与工具函数定义策略与价值网络PPO 智能体核心实现训练与结果代码实践:PPO 解决连续动作空间问题 (Pendulum)环境准备适用于连续动作的网络PPO 智能体 (连…

PortsWiggerLab: Blind OS command injection with output redirection

实验目的This lab contains a blind OS command injection vulnerability in the feedback function.The application executes a shell command containing the user-supplied details. The output from the command is not returned in the response. However, you can use o…

星云穿越与超光速飞行特效的前端实现原理与实践

文章目录 1,引言2,特效设计思路3,技术原理解析1. 星点的三维分布2. 视角推进与星点运动3. 三维到二维的投影4. 星点的视觉表现5. 色彩与模糊处理4,关键实现流程图5,应用场景与优化建议6,总结1,引言 在现代网页开发中,炫酷的视觉特效不仅能提升用户体验,还能为产品增添…