(STM32笔记)十二、DMA的基础知识与用法 第三部分
我用的是正点的
STM32F103来进行学习,板子和教程是野火的指南者。
之后的这个系列笔记开头未标明的话,用的也是这个板子和教程。
DMA的基础知识与用法
- 三、DMA程序验证
- 1、DMA 存储器到存储器模式实验
- (1)DMA结构体解释
- (2)DMA结构体初始化
- (3)程序验证
- 2、DMA 存储器到外设模式实验
- (1)串口初始化
- (2)DMA结构体初始化
- (3)程序验证
三、DMA程序验证
1、DMA 存储器到存储器模式实验
(1)DMA结构体解释
typedef struct
{uint32_t DMA_PeripheralBaseAddr; // 外设地址uint32_t DMA_MemoryBaseAddr; // 存储器地址uint32_t DMA_DIR; // 传输方向uint32_t DMA_BufferSize; // 传输数目uint32_t DMA_PeripheralInc; // 外设地址增量模式uint32_t DMA_MemoryInc; // 存储器地址增量模式uint32_t DMA_PeripheralDataSize; // 外设数据宽度uint32_t DMA_MemoryDataSize; // 存储器数据宽度uint32_t DMA_Mode; // 模式选择uint32_t DMA_Priority; // 通道优先级uint32_t DMA_M2M; // 存储器到存储器模式
} DMA_InitTypeDef;
-
DMA_PeripheralBaseAddr:
外设地址,设定DMA_CPAR寄存器的值;一般设置为外设的数据寄存器地址,如果是存储器到存储器模式则设置为其中一个存储器地址。 -
DMA_Memory0BaseAddr:
存储器地址,设定DMA_CMAR寄存器值;一般设置为我们自定义存储区的首地址。 -
DMA_DIR:
传输方向选择,可选外设到存储器、存储器到外设。它设定DMA_CCR寄存器的DIR[1:0]位的值。这里并没有存储器到存储器的方向选择,当使用存储器到存储器时,只需要把其中一个存储器当作外设使用即可。

-
DMA_BufferSize:
设定待传输数据数目,初始化设定DMA_CNDTR寄存器的值。
这个DMA_BufferSize就是要传输的次数。
这个并不是指字节大小,而是指DMA的传输次数,传输的字节大小由DMA_PeripheralDataSize设置。
DMA传输数据时,从DMA_MemoryBaseAddr+0地址开始放,直到DMA_MemoryBaseAddr+DMA_BufferSize-1,此时DMA_CNDTR变成0,传输结束。 -
DMA_PeripheralInc:
如果配置为DMA_PeripheralInc_Enable,使能外设地址自动递增功能,它设定DMA_CCR寄存器的PINC位的值;一般外设都是只有一个数据寄存器,所以一般不会使能该位。

-
DMA_MemoryInc:
如果配置为DMA_MemoryInc_Enable,使能存储器地址自动递增功能,它设定DMA_CCR寄存器的 MINC 位的值;我们自定义的存储区一般都是存放多个数据的,所以要使能存储器地址自动递增功能。

-
DMA_PeripheralDataSize:
外设数据宽度,可选字节 (8 位)、半字 (16 位) 和字 (32 位),它设定DMA_CCR寄存器的PSIZE[1:0]位的值。

-
DMA_MemoryDataSize:
存储器数据宽度,可选字节 (8 位)、半字 (16 位) 和字 (32 位),它设定DMA_CCR寄存器的MSIZE[1:0]位的值。当外设和存储器之间传数据时,两边的数据宽度应该设置为一致大小。

-
DMA_Mode:
DMA 传输模式选择,可选一次传输Normal或者循环传输Circular,它设定 DMA_CCR 寄存器的CIRC 位的值。例程我们的 ADC 采集是持续循环进行的,所以使用循环传输模式。

-
DMA_Priority:
软件设置通道的优先级,有 4 个可选优先级分别为非常高、高、中和低,它设定DMA_CCR寄存器的PL[1:0]位的值。DMA 通道优先级只有在多个 DMA 通道同时使用时才有意义,如果是单个通道,优先级可以随便设置。

-
DMA_M2M:
存储器到存储器模式,使用存储器到存储器时用到,设定DMA_CCR 的位 14 MEN2MEN即可启动存储器到存储器模式。

(2)DMA结构体初始化
DMA_InitTypeDef DMA_InitStructure;// 开启DMA时钟RCC_AHBPeriphClockCmd(DMA_CLOCK, ENABLE);// 源数据地址DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)ShuZu_YouShu; //数组有32个数,每个数都是一个字,且使用const定义(存储在FLASH)// 目标地址DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)ShuZu_MeiShu; //数组有32个数,每个数都是一个字// 方向:外设到存储器(这里的外设是内部的FLASH) DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;// 传输大小 DMA_InitStructure.DMA_BufferSize = 32; //因为数组有32个数,所以设32// 外设(内部的FLASH)地址递增 DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Enable;// 内存地址递增DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;// 外设数据单位 DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word; //因为每个数大小都是一个字,所以宽度设为Word// 内存数据单位DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Word; //因为每个数大小都是一个字,所以宽度设为Word// DMA模式,一次或者循环模式DMA_InitStructure.DMA_Mode = DMA_Mode_Normal ; //一次传输模式//DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; // 优先级:高 DMA_InitStructure.DMA_Priority = DMA_Priority_High;// 使能内存到内存的传输DMA_InitStructure.DMA_M2M = DMA_M2M_Enable; //因为本次是FLASH传输到SRAM,所以是存储器到存储器// 配置DMA通道 DMA_Init(DMA_CHANNEL, &DMA_InitStructure);//清除DMA数据流传输完成标志位DMA_ClearFlag(DMA_FLAG_TC);// 使能DMADMA_Cmd(DMA_CHANNEL,ENABLE);
其中,
- 需开启DMA时钟才能使用DMA功能:
// 开启DMA时钟
RCC_AHBPeriphClockCmd(DMA_CLOCK, ENABLE);
ShuZu_YouShu定义如下:
uint32_t ShuZu_YouShu[32]= {0x01020304,0x05060708,0x090A0B0C,0x0D0E0F10,0x11121314,0x15161718,0x191A1B1C,0x1D1E1F20,0x21222324,0x25262728,0x292A2B2C,0x2D2E2F30,0x31323334,0x35363738,0x393A3B3C,0x3D3E3F40,0x41424344,0x45464748,0x494A4B4C,0x4D4E4F50,0x51525354,0x55565758,0x595A5B5C,0x5D5E5F60,0x61626364,0x65666768,0x696A6B6C,0x6D6E6F70,0x71727374,0x75767778,0x797A7B7C,0x7D7E7F80};
- 需清除 DMA 标志位后再使用DMA功能,防止不必要的干扰:
//清除DMA数据流传输完成标志位DMA_ClearFlag(DMA_FLAG_TC);
(3)程序验证
DMA传输过后,在DEBUG界面可以看到,ShuZu_YouShu的数字传输到了ShuZu_MeiShu中

2、DMA 存储器到外设模式实验
具体实验为 将数组中的数字 传输至 串口
(1)串口初始化
代码解释均放入注释中,正文不再复述
/*** @brief USART GPIO 配置,工作参数配置* @param 无* @retval 无*/
void USART_Config(void)
{GPIO_InitTypeDef GPIO_InitStructure;USART_InitTypeDef USART_InitStructure;// 打开串口GPIO的时钟DEBUG_USART_GPIO_APBxClkCmd(DEBUG_USART_GPIO_CLK, ENABLE);// 打开串口外设的时钟DEBUG_USART_APBxClkCmd(DEBUG_USART_CLK, ENABLE);// 将USART Tx的GPIO配置为推挽复用模式GPIO_InitStructure.GPIO_Pin = DEBUG_USART_TX_GPIO_PIN;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(DEBUG_USART_TX_GPIO_PORT, &GPIO_InitStructure);// 将USART Rx的GPIO配置为浮空输入模式GPIO_InitStructure.GPIO_Pin = DEBUG_USART_RX_GPIO_PIN;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;GPIO_Init(DEBUG_USART_RX_GPIO_PORT, &GPIO_InitStructure);// 配置串口的工作参数// 配置波特率 为 115200USART_InitStructure.USART_BaudRate = 115200;// 配置 数据字长 为 8USART_InitStructure.USART_WordLength = USART_WordLength_8b;// 配置 停止位 为 1USART_InitStructure.USART_StopBits = USART_StopBits_1;// 配置 校验位 为 0USART_InitStructure.USART_Parity = USART_Parity_No ;// 配置硬件流控制USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;// 配置工作模式,收发一起USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;// 完成串口的初始化配置USART_Init(DEBUG_USARTx, &USART_InitStructure); // 使能串口USART_Cmd(DEBUG_USARTx, ENABLE);
}
(2)DMA结构体初始化
因为数据是从存储器到串口,所以设置存储器为源地址,串口的数据寄存器为目标地址。
要发送的数据有很多且都先存储在存储器中,则存储器地址指针递增;串口数据寄存器只有一个,则外设地址地址不变。
两边数据单位设置成一致,传输模式可选一次或者循环传输,只有一个 DMA 请求,优先级随便设。
最后调用 DMA_Init 函数把这些参数写到 DMA 的寄存器中,然后使能 DMA开始传输。
void USARTx_DMA_Config(void)
{DMA_InitTypeDef DMA_InitStructure;// 开启DMA时钟RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);// 设置DMA源地址:串口数据寄存器地址*/DMA_InitStructure.DMA_PeripheralBaseAddr = USART_DR_ADDRESS;// 内存地址(要传输的变量的指针)DMA_InitStructure.DMA_MemoryBaseAddr = (u32)ShuZu_YouShu;// 方向:从内存到外设 DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;// 传输数量DMA_InitStructure.DMA_BufferSize = 5000; // 传输数量 设为 5000,这个数随便设,只要不超过数组大小就可// 外设地址不增 DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;// 内存地址自增DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;// 外设数据单位 DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; //因为每次传输1bit,所以设为Byte// 内存数据单位DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; //因为每次传输1bit,所以设为Byte// DMA模式,一次或者循环模式DMA_InitStructure.DMA_Mode = DMA_Mode_Normal ; //一次传输模式//DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; // 优先级:中 DMA_InitStructure.DMA_Priority = DMA_Priority_Medium; // 禁止内存到内存的传输DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;// 配置DMA通道 DMA_Init(USART_TX_DMA_CHANNEL, &DMA_InitStructure); // 使能DMADMA_Cmd (USART_TX_DMA_CHANNEL,ENABLE);
}
其中,
- 外设地址
DMA_PeripheralBaseAddr为串口地址(需查阅开发手册),即:


// 外设寄存器地址
#define PERIPH_BASE ((uint32_t)0x40000000)
#define APB2PERIPH_BASE (PERIPH_BASE + 0x10000)
#define USART1_BASE (APB2PERIPH_BASE + 0x3800)
#define USART_DR_ADDRESS (USART1_BASE+0x04)
ShuZu_YouShu数组填充为A-Z共26个字母,再加一个回车:
/*填充将要发送的数据*/for(i=0; i < 5000; i++){ShuZu_YouShu[i] = 'A'+ i%27;if(ShuZu_YouShu[i] == '['){ShuZu_YouShu[i] = '\n';}}
(3)程序验证
使用USART_DMACmd函数打开USART 的DMA请求。
/* USART1 向 DMA发出TX请求 */USART_DMACmd(USART1, USART_DMAReq_Tx, ENABLE);
它接收三个参数:
- 第一个参数用于设置串口外设,可以是
USART1/2/3和UART4/5这 5 个参数可选。 - 第二个参数设置串口的具体 DMA 请求,有串口发送请求
USART_DMAReq_Tx和接收请求USART_DMAReq_Rx可选。 - 第三个参数用于设置启动请求
ENABLE或者关闭请求DISABLE。
运行该函数后 USART 的DMA 发送传输就开始了,根据配置存储器的数据会发送到串口。
验证结果如下:

相关文章:
(STM32笔记)十二、DMA的基础知识与用法 第三部分
我用的是正点的STM32F103来进行学习,板子和教程是野火的指南者。 之后的这个系列笔记开头未标明的话,用的也是这个板子和教程。 DMA的基础知识与用法 三、DMA程序验证1、DMA 存储器到存储器模式实验(1)DMA结构体解释(2…...
品牌账号矩阵如何打造?来抄作业
在讲究全域营销的当下,目前企业都在各自搭建品牌矩阵号,以提升自己在不同渠道上的影响力。虽然不同平台之间有诸多细节值得深究,但也不妨碍我们先了解如何搭建品牌矩阵。接下来,就让我们一同来了解下该如何搭建。 一、一个主账号 …...
基于vue的商城小程序的毕业设计与实现(源码及报告)
环境搭建 ☞☞☞ Vue入手篇(一),防踩雷(全网最详细教程)_vue force-CSDN博客 目录 一、功能介绍 二、登录注册功能 三、首页 四、项目截图 五、源码获取 一、功能介绍 用户信息展示:页面顶部设有用户头像和昵称展示区,方便用户识别…...
NineData云原生智能数据管理平台新功能发布|2024年12月版
本月发布 7 项更新,其中重点发布 2 项、功能优化 5 项。 重点发布 数据库 Devops - Oracle 非表对象支持可视化创建与管理 Oracle 非表对象,包括视图(View)、包(Package)、存储过程(Procedur…...
【Vue.js 组件化】高效组件管理与自动化实践指南
文章目录 摘要引言组件命名规范与组织结构命名规范目录组织 依赖管理工具自动化组件文档生成构建自动引入和文档生成的组件化体系代码结构自动引入组件配置使用 Storybook 展示组件文档自动生成 代码详解QA 环节总结参考资料 摘要 在现代前端开发中,组件化管理是 V…...
Clojure语言的并发编程
Clojure语言的并发编程 引言 在现代软件开发中,并发编程成为了处理多个任务、提高应用效率和响应速度的重要手段。尤其是在多核处理器逐渐成为主流的今天,如何高效利用这些计算资源是每个开发者面临的挑战。Clojure作为一种函数式编程语言,…...
RabbitMQ-SpringAMQP使用介绍
RabbitMQ 1. Spring AMQP1.1 引入依赖1.2 消息发送1.3 消息接收1.4 WorkQueue模型1.4.1 实例代码1.4.2 能者多劳1.4.3 总结 1.5交换机1.6 Fanout交换机(广播)1.7 Direct交换机(订阅)1.8 Topic交换机(通配符订阅&#x…...
ASP.NET Core 中服务生命周期详解:Scoped、Transient 和 Singleton 的业务场景分析
前言 在 ASP.NET Core 中,服务的生命周期直接影响应用的性能和行为。通过依赖注入容器 (Dependency Injection, DI),我们可以为服务定义其生命周期:Scoped、Transient 和 Singleton。本文将详细阐述这些生命周期的区别及其在实际业务中的应用…...
c语言----------小知识
1 system函数的使用 #include <stdlib.h> int system(const char *command); 功能:在已经运行的程序中执行另外一个外部程序 参数:外部可执行程序名字 返回值: 成功:0 失败:任意数字示例代码: #inc…...
React Context用法总结
1. 基本概念 1.1 什么是 Context Context 提供了一种在组件树中共享数据的方式,而不必通过 props 显式地逐层传递。它主要用于共享那些对于组件树中许多组件来说是"全局"的数据。 1.2 基本用法 // 1. 创建 Context const ThemeContext React.createC…...
[笔记] 使用 Jenkins 实现 CI/CD :从 GitLab 拉取 Java 项目并部署至 Windows Server
随着软件开发节奏的加快,持续集成(CI)和持续部署(CD)已经成为确保软件质量和加速产品发布的不可或缺的部分。Jenkins作为一款广泛使用的开源自动化服务器,为开发者提供了一个强大的平台来实施这些实践。然而…...
腾讯云AI代码助手编程挑战赛-如意
作品简介 《如意》是一款结合腾讯云AI代码助手生成的、集智能问答、知识学习和生活助手功能于一体的应用,在通过先进的AI技术提升用户的工作效率、学习效果和生活质量。无论是解答疑难问题、提供专业建议,还是帮助规划日程、提升技能,它都能…...
TAS测评倍智题库 | 益丰大药房2025年中高层测评BA商业推理测评真题考什么?
您好!您已被邀请参加360评估。您的评估与反馈将有助于被评估人更深入地了解个人情况,发现个人优势和潜在风险。请您秉持公正、开放的心态进行评估。请尽快完成评估,在此衷心感谢您的配合与支持! 相关事宜: 请您在…...
2025 First LOOK! CnosDB 新版本 2.4.3.1 发布
🔹 版本号:2.4.3.1 🔹 发布日期:2024年11月05日 功能优化 简化编解码器错误定义 #2368 删除不必要的const DEFAULT_* #2378 添加 wal 压缩检查 #2377 移除 page reader #2380 创建配额 #2367 减少内存复制和计算 #2384 构…...
PyMysql 01|(包含超详细项目实战)连接数据库、增删改查、异常捕获
目录 一、数据库操作应用场景 二、安装PyMysql 三、事务的概念 四、数据库的准备 五、PyMysql连接数据库 1、建立连接方法 2、入门案例 六、PyMysql操作数据库 1、数据库查询 1️⃣查询操作流程 2️⃣cursor游标 3️⃣查询常用方法 4️⃣案例 5️⃣异常捕获 …...
Android14上使用libgpiod[gpioinfo gpioget gpioset ...]
环境 $ cat /etc/os-release NAME="Ubuntu" VERSION="20.04.5 LTS (Focal Fossa)" ID=ubuntu ID_LIKE=debian PRETTY_NAME="Ubuntu 20.04.5 LTS" VERSION_ID="20.04" HOME_URL="https://www.ubuntu.com/" SUPPORT_URL="…...
网络安全 信息收集入门
1.信息收集定义 信息收集是指收集有关目标应用程序和系统的相关信息。这些信息可以帮助攻击者了解目标系统的架构、技术实现细节、运行环境、网络拓扑结构、安全措施等方面的信息,以便我们在后续的渗透过程更好的进行。 2.收集方式-主动和被动收集 ①收集方式不同…...
修改sshd默认配置,提升安全
对于Linux服务器,特别是暴露在公网的服务器,会经常被人扫描、探测和攻击。包括通过ssh访问登录攻击。对此,对默认的sshd配置进行调整,提升安全。 下面以CentOS 7.9为例说明: 一、常见安全措施 以root用户编辑vim /e…...
Clojure语言的面向对象编程
Clojure语言的面向对象编程 引言 Clojure是一种现代的Lisp方言,它特别强调函数式编程,Immutable数据结构和强大的并发能力。然而,很多人可能会问:Clojure支持面向对象编程吗?虽然Clojure没有像Java或C那样的传统类和…...
spring boot启动源码分析(三)之Environment准备
上一篇《spring-boot启动源码分析(二)之SpringApplicationRunListener》 环境介绍: spring boot版本:2.7.18 主要starter:spring-boot-starter-web 本篇开始讲启动过程中Environment环境准备,Environment是管理所有…...
(二)TensorRT-LLM | 模型导出(v0.20.0rc3)
0. 概述 上一节 对安装和使用有个基本介绍。根据这个 issue 的描述,后续 TensorRT-LLM 团队可能更专注于更新和维护 pytorch backend。但 tensorrt backend 作为先前一直开发的工作,其中包含了大量可以学习的地方。本文主要看看它导出模型的部分&#x…...
FastAPI 教程:从入门到实践
FastAPI 是一个现代、快速(高性能)的 Web 框架,用于构建 API,支持 Python 3.6。它基于标准 Python 类型提示,易于学习且功能强大。以下是一个完整的 FastAPI 入门教程,涵盖从环境搭建到创建并运行一个简单的…...
在Ubuntu中设置开机自动运行(sudo)指令的指南
在Ubuntu系统中,有时需要在系统启动时自动执行某些命令,特别是需要 sudo权限的指令。为了实现这一功能,可以使用多种方法,包括编写Systemd服务、配置 rc.local文件或使用 cron任务计划。本文将详细介绍这些方法,并提供…...
Java 加密常用的各种算法及其选择
在数字化时代,数据安全至关重要,Java 作为广泛应用的编程语言,提供了丰富的加密算法来保障数据的保密性、完整性和真实性。了解这些常用加密算法及其适用场景,有助于开发者在不同的业务需求中做出正确的选择。 一、对称加密算法…...
Matlab | matlab常用命令总结
常用命令 一、 基础操作与环境二、 矩阵与数组操作(核心)三、 绘图与可视化四、 编程与控制流五、 符号计算 (Symbolic Math Toolbox)六、 文件与数据 I/O七、 常用函数类别重要提示这是一份 MATLAB 常用命令和功能的总结,涵盖了基础操作、矩阵运算、绘图、编程和文件处理等…...
微信小程序云开发平台MySQL的连接方式
注:微信小程序云开发平台指的是腾讯云开发 先给结论:微信小程序云开发平台的MySQL,无法通过获取数据库连接信息的方式进行连接,连接只能通过云开发的SDK连接,具体要参考官方文档: 为什么? 因为…...
selenium学习实战【Python爬虫】
selenium学习实战【Python爬虫】 文章目录 selenium学习实战【Python爬虫】一、声明二、学习目标三、安装依赖3.1 安装selenium库3.2 安装浏览器驱动3.2.1 查看Edge版本3.2.2 驱动安装 四、代码讲解4.1 配置浏览器4.2 加载更多4.3 寻找内容4.4 完整代码 五、报告文件爬取5.1 提…...
【数据分析】R版IntelliGenes用于生物标志物发现的可解释机器学习
禁止商业或二改转载,仅供自学使用,侵权必究,如需截取部分内容请后台联系作者! 文章目录 介绍流程步骤1. 输入数据2. 特征选择3. 模型训练4. I-Genes 评分计算5. 输出结果 IntelliGenesR 安装包1. 特征选择2. 模型训练和评估3. I-Genes 评分计…...
Python ROS2【机器人中间件框架】 简介
销量过万TEEIS德国护膝夏天用薄款 优惠券冠生园 百花蜂蜜428g 挤压瓶纯蜂蜜巨奇严选 鞋子除臭剂360ml 多芬身体磨砂膏280g健70%-75%酒精消毒棉片湿巾1418cm 80片/袋3袋大包清洁食品用消毒 优惠券AIMORNY52朵红玫瑰永生香皂花同城配送非鲜花七夕情人节生日礼物送女友 热卖妙洁棉…...
STM32HAL库USART源代码解析及应用
STM32HAL库USART源代码解析 前言STM32CubeIDE配置串口USART和UART的选择使用模式参数设置GPIO配置DMA配置中断配置硬件流控制使能生成代码解析和使用方法串口初始化__UART_HandleTypeDef结构体浅析HAL库代码实际使用方法使用轮询方式发送使用轮询方式接收使用中断方式发送使用中…...
