(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是管理所有…...

XML Group端口详解
在XML数据映射过程中,经常需要对数据进行分组聚合操作。例如,当处理包含多个物料明细的XML文件时,可能需要将相同物料号的明细归为一组,或对相同物料号的数量进行求和计算。传统实现方式通常需要编写脚本代码,增加了开…...

循环冗余码校验CRC码 算法步骤+详细实例计算
通信过程:(白话解释) 我们将原始待发送的消息称为 M M M,依据发送接收消息双方约定的生成多项式 G ( x ) G(x) G(x)(意思就是 G ( x ) G(x) G(x) 是已知的)࿰…...
大语言模型如何处理长文本?常用文本分割技术详解
为什么需要文本分割? 引言:为什么需要文本分割?一、基础文本分割方法1. 按段落分割(Paragraph Splitting)2. 按句子分割(Sentence Splitting)二、高级文本分割策略3. 重叠分割(Sliding Window)4. 递归分割(Recursive Splitting)三、生产级工具推荐5. 使用LangChain的…...

376. Wiggle Subsequence
376. Wiggle Subsequence 代码 class Solution { public:int wiggleMaxLength(vector<int>& nums) {int n nums.size();int res 1;int prediff 0;int curdiff 0;for(int i 0;i < n-1;i){curdiff nums[i1] - nums[i];if( (prediff > 0 && curdif…...
vue3 字体颜色设置的多种方式
在Vue 3中设置字体颜色可以通过多种方式实现,这取决于你是想在组件内部直接设置,还是在CSS/SCSS/LESS等样式文件中定义。以下是几种常见的方法: 1. 内联样式 你可以直接在模板中使用style绑定来设置字体颜色。 <template><div :s…...
【C语言练习】080. 使用C语言实现简单的数据库操作
080. 使用C语言实现简单的数据库操作 080. 使用C语言实现简单的数据库操作使用原生APIODBC接口第三方库ORM框架文件模拟1. 安装SQLite2. 示例代码:使用SQLite创建数据库、表和插入数据3. 编译和运行4. 示例运行输出:5. 注意事项6. 总结080. 使用C语言实现简单的数据库操作 在…...
爬虫基础学习day2
# 爬虫设计领域 工商:企查查、天眼查短视频:抖音、快手、西瓜 ---> 飞瓜电商:京东、淘宝、聚美优品、亚马逊 ---> 分析店铺经营决策标题、排名航空:抓取所有航空公司价格 ---> 去哪儿自媒体:采集自媒体数据进…...

自然语言处理——循环神经网络
自然语言处理——循环神经网络 循环神经网络应用到基于机器学习的自然语言处理任务序列到类别同步的序列到序列模式异步的序列到序列模式 参数学习和长程依赖问题基于门控的循环神经网络门控循环单元(GRU)长短期记忆神经网络(LSTM)…...
QT3D学习笔记——圆台、圆锥
类名作用Qt3DWindow3D渲染窗口容器QEntity场景中的实体(对象或容器)QCamera控制观察视角QPointLight点光源QConeMesh圆锥几何网格QTransform控制实体的位置/旋转/缩放QPhongMaterialPhong光照材质(定义颜色、反光等)QFirstPersonC…...
作为测试我们应该关注redis哪些方面
1、功能测试 数据结构操作:验证字符串、列表、哈希、集合和有序的基本操作是否正确 持久化:测试aof和aof持久化机制,确保数据在开启后正确恢复。 事务:检查事务的原子性和回滚机制。 发布订阅:确保消息正确传递。 2、性…...