STM32 DMA数据转运

news/2025/2/7 1:08:27/

DMA简介

        DMA(Direct Memory Access)直接存储器存取

        DMA可以提供外设和存储器或者存储器和存储器之间的高速数据传输,无须CPU干预,节省了CPU的资源

        12个独立可配置的通道: DMA17个通道), DMA25个通道)

        每个通道都支持软件触发和特定的硬件触发

        STM32F103C8T6 DMA资源:DMA17个通道)

        DMA是数据转运助手,主要用来协助CPU,完成数据转运的工作

存储器映像

STM32中的存储器

计算机系统的五大组成部分:运算器、控制器、存储器、输入设备和输出设备,运算器和控制器合在一起叫做CPU,所以计算机的核心关键部分就是CPU和存储器

存储器:存储器内容与存储器地址

ROM:只读存储器,是一种非易失性、掉电不丢失的存储器

RAM:随机存储器,是一种易失性、掉电丢失的存储器

DMA框图

DMA总线:用于访问各个存储器的DMA总线

内部的多个通道:可以进行独立的数据转运

仲裁器:用于调度各个通道,防止产生冲突

AHB从设备:用于配置DMA参数

DMA请求:用于硬件触发DMA的数据转运

DMA基本结构图

函数介绍

恢复缺省设置

void DMA_DeInit(DMA_Channel_TypeDef* DMAy_Channelx);

初始化

void DMA_Init(DMA_Channel_TypeDef* DMAy_Channelx, DMA_InitTypeDef* DMA_InitStruct);

结构体初始化

void DMA_StructInit(DMA_InitTypeDef* DMA_InitStruct);

使能

void DMA_Cmd(DMA_Channel_TypeDef* DMAy_Channelx, FunctionalState NewState);

中断输出使能

void DMA_ITConfig(DMA_Channel_TypeDef* DMAy_Channelx, uint32_t DMA_IT, FunctionalState NewState);

DMA设置当前寄存器,这个函数,就是给传输计数器写数据的

void DMA_SetCurrDataCounter(DMA_Channel_TypeDef* DMAy_Channelx, uint16_t DataNumber); 

DMA获取当前数据寄存器,这个函数就是返回传输计数器的值,如果想看看还剩多少数据没有转运,可以调用这个函数

uint16_t DMA_GetCurrDataCounter(DMA_Channel_TypeDef* DMAy_Channelx);

这四个函数是获取标志位状态、清除标志位、获取中断状态、清除中断挂起位

FlagStatus DMA_GetFlagStatus(uint32_t DMAy_FLAG);
void DMA_ClearFlag(uint32_t DMAy_FLAG);
ITStatus DMA_GetITStatus(uint32_t DMAy_IT);
void DMA_ClearITPendingBit(uint32_t DMAy_IT);

代码编写

1.定义结构体变量

//定义结构体变量DMA_InitTypeDef DMA_InitStructure;//定义DMA结构体变量

2.RCC开启时钟

开启DMA的时钟

//开启RCC时钟RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE);//开启DMA1的时钟

3.调用DMA_Init

初始化参数包括外设和存储器站点的起始地址、数据宽度、地址是否自增、方向、传输计数器、是否需要自动重装、选择触发源、通道优先级

//配置DMA
//外设站点
DMA_InitStructure.DMA_PeripheralBaseAddr = AddrA;//外设站点的基地址,这里要写一个32位的地址
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;//数据宽度 
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Enable;//地址是否自增
//存储器站点
DMA_InitStructure.DMA_MemoryBaseAddr = AddrB;//存储器站点的及地址
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;//数据宽度
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;//存储器站点地址自增
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;//传输方向 选择外设站点到存储器站点
DMA_InitStructure.DMA_BufferSize = Size;//传输次数
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;//传输计数器是否自动重装 这里选择正藏模式不自动重装
DMA_InitStructure.DMA_M2M = DMA_M2M_Enable;//选择触发源,这里选择软件触发
DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;//通道优先级DMA_Init(DMA1_Channel1, &DMA_InitStructure);

4.开关控制

使能DMA_Cmd,给指定的通道使能

//使能
DMA_Cmd(DMA1_Channel1,DISABLE);//使能DMA

功能代码

实现数据转运功能,将数组DataA的数据转运到数组DataB中,并实时更新

这里需要定义一个全局变量Size,将初始化里的Size用到功能函数里

void MyDMA_Transfer(void)
{DMA_Cmd(DMA1_Channel1,DISABLE);//失能DMADMA_SetCurrDataCounter(DMA1_Channel1, MyDMA_Size);//转运数据DMA_Cmd(DMA1_Channel1,ENABLE);//使能DMA//等待转运完成while(DMA_GetFlagStatus(DMA1_FLAG_TC1) == RESET);DMA_ClearFlag(DMA1_FLAG_TC1);//清除标志位
}

整体代码

uint16_t MyDMA_Size;void MyDMA_Init(uint32_t AddrA,uint32_t AddrB,uint16_t Size)
{MyDMA_Size = Size;//定义结构体变量DMA_InitTypeDef DMA_InitStructure;//定义DMA结构体变量//开启RCC时钟RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE);//开启DMA1的时钟//配置DMA//外设站点DMA_InitStructure.DMA_PeripheralBaseAddr = AddrA;//外设站点的基地址,这里要写一个32位的地址DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;//数据宽度 DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Enable;//地址是否自增//存储器站点DMA_InitStructure.DMA_MemoryBaseAddr = AddrB;//存储器站点的及地址DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;//数据宽度DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;//存储器站点地址自增DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;//传输方向 选择外设站点到存储器站点DMA_InitStructure.DMA_BufferSize = Size;//传输次数DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;//传输计数器是否自动重装 这里选择正藏模式不自动重装DMA_InitStructure.DMA_M2M = DMA_M2M_Enable;//选择触发源,这里选择软件触发DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;//通道优先级DMA_Init(DMA1_Channel1, &DMA_InitStructure);//使能DMA_Cmd(DMA1_Channel1,DISABLE);//使能DMA}void MyDMA_Transfer(void)
{DMA_Cmd(DMA1_Channel1,DISABLE);//失能DMADMA_SetCurrDataCounter(DMA1_Channel1, MyDMA_Size);//转运数据DMA_Cmd(DMA1_Channel1,ENABLE);//使能DMA//等待转运完成while(DMA_GetFlagStatus(DMA1_FLAG_TC1) == RESET);DMA_ClearFlag(DMA1_FLAG_TC1);//清除标志位
}

主函数

#include "MyDMA.h"
int main(void)
{uint8_t DataA[] = {0x01, 0x02, 0x03, 0x04};uint8_t DataB[] = {0, 0, 0, 0};OLED_Init();MyDMA_Init((uint32_t)DataA, (uint32_t)DataB, 4);OLED_ShowString(1, 1, "DateA:");OLED_ShowString(3, 1, "DataB:");OLED_ShowHexNum(1, 8, (uint32_t)DataA, 8);OLED_ShowHexNum(3, 8, (uint32_t)DataB, 8);while(1){DataA[0] ++;DataA[1] ++;DataA[2] ++;DataA[3] ++;OLED_ShowHexNum(2, 1, DataA[0], 2);OLED_ShowHexNum(2, 4, DataA[1], 2);OLED_ShowHexNum(2, 7, DataA[2], 2);OLED_ShowHexNum(2, 10, DataA[3], 2);OLED_ShowHexNum(4, 1, DataB[0], 2);OLED_ShowHexNum(4, 4, DataB[1], 2);OLED_ShowHexNum(4, 7, DataB[2], 2);OLED_ShowHexNum(4, 10, DataB[3], 2);Delay_ms(1000);MyDMA_Transfer();OLED_ShowHexNum(2, 1, DataA[0], 2);OLED_ShowHexNum(2, 4, DataA[1], 2);OLED_ShowHexNum(2, 7, DataA[2], 2);OLED_ShowHexNum(2, 10, DataA[3], 2);OLED_ShowHexNum(4, 1, DataB[0], 2);OLED_ShowHexNum(4, 4, DataB[1], 2);OLED_ShowHexNum(4, 7, DataB[2], 2);OLED_ShowHexNum(4, 10, DataB[3], 2);Delay_ms(1000);}}


http://www.ppmy.cn/news/1569948.html

相关文章

RTMP 和 WebRTC

WebRTC(Web Real-Time Communication)和 RTMP(Real-Time Messaging Protocol)是两种完全不同的流媒体协议,设计目标、协议栈、交互流程和应用场景均有显著差异。以下是两者的详细对比,涵盖协议字段、交互流程及核心设计思想。 一、协议栈与设计目标对比 特性RTMPWebRTC传…

Spring Web MVC基础第一篇

目录 1.什么是Spring Web MVC? 2.创建Spring Web MVC项目 3.注解使用 3.1RequestMapping(路由映射) 3.2一般参数传递 3.3RequestParam(参数重命名) 3.4RequestBody(传递JSON数据) 3.5Pa…

JVM执行流程与架构(对应不同版本JDK)

直接上图(对应JDK8以及以后的HotSpot) 这里主要区分说明一下 方法区于 字符串常量池 的位置更迭: 方法区 JDK7 以及之前的版本将方法区存放在堆区域中的 永久代空间,堆的大小由虚拟机参数来控制。 JDK8 以及之后的版本将方法…

python-leetcode-验证二叉搜索树

98. 验证二叉搜索树 - 力扣(LeetCode) # Definition for a binary tree node. # class TreeNode: # def __init__(self, val0, leftNone, rightNone): # self.val val # self.left left # self.right right class Soluti…

信息安全、网络安全和数据安全的区别和联系

一、区别 1.信息安全 定义 信息安全是指为数据处理系统建立和采用的技术和管理的安全保护,保护计算机硬件、软件和数据不因偶然和恶意的原因而遭到破坏、更改和泄露。它的范围比较广泛,涵盖了信息的保密性、完整性和可用性等多个方面。 侧重点 更强…

Nginx 命令行参数

文章来源:命令行参数 -- nginx中文文档|nginx中文教程 nginx 支持以下命令行参数: -?| — 打印帮助 以获取命令行参数。-h-c file— 使用替代项 configuration 而不是 default 文件。file-e file— 使用替代项 error log 来存储日志 而不是默认文件 &…

Linux中安装rabbitMQ

使用docker安装 Linux中还没有安装docker的可以看我之前的视频,先把docker安装了。 Docker的安装_docker version 25.0.1-CSDN博客 检查是否有docker docker -v 上传mq的tar包 我们把mq的tar包上传到我们的Linux服务器中,随后加载成docker的镜像。 加载…

C++ Primer 标准库vector

欢迎阅读我的 【CPrimer】专栏 专栏简介:本专栏主要面向C初学者,解释C的一些基本概念和基础语言特性,涉及C标准库的用法,面向对象特性,泛型特性高级用法。通过使用标准库中定义的抽象设施,使你更加适应高级…