STM32入门学习之DMA

1.直接存储访问DMA(Direct Memory Access):DMA传输不需要CPU的参与,直接在内存和I/O设备间开辟了一条新的数据传输通道,不仅提高数据传输的速率,还因为不需要CPU的干预,从而提高了CPU的利用率。(注:文中的资料参考于正点原子)

STM32最多有2个DMA通道(只有大容量的STM32才有DMA2)。DMA1有7个通道,DMA2有5个通道,每个通道用来管理一个或者多个外设对存储器的访问请求。还有一个通道用来仲裁协调各个DMA请求的优先级。STM32的DMA特性如下:

STM32F103RCT6的DMA1通道表如下:

每个通道同一时刻只能有一个外设使用DMA进行数据传输。比如DMA1的通道1中有三个外设(ADC1、TIM2_CH3、TIM4_CH1),同一时刻只能使用其中的一个外设进行DMA数据传输。本文是利用USART1进行数据传输,由表可知,需要使用的DMA1的通道4。

DMA配置的基本步骤:

(1)使能DMA的时钟,并配置DMA的初始结构体。

(2)开启DMA。

(3)开启对应外设的DMA数据传输。

2.DMA相关的寄存器:

(1)DMA中断状态寄存器(DMA_ISR):当开启DMA_ISR的这些中断后,产生中断触发条件时会跳转到相应的中断服务函数。即使没有开启这些中断,也可以通过这些位来判断当前DMA的传输状态。比如可以用TCIFx来判断DMA是否传输完成。此寄存器为只读寄存器,所以当被置位之后,需要通过其他的操作来清除。

(2)DMA中断标志清除寄存器(DMA_IFCR):DMA_IFCR 的各位就是用来清除 DMA_ISR 的对应位的,通过写 0 清除。在 DMA_ISR 被置位后,必须通过向该位寄存器对应的位写入 0 来清除。

(3)DMA的其他寄存器:

3.DMA的初始化配置:

DMA的初始化函数为:void DMA_Init(DMA_Channel_TypeDef* DMAy_Channelx, DMA_InitTypeDef* DMA_InitStruct)。参数1是DMA的通道号,参数2是一个结构体,其定义如下:

如下为DMA的一个配置实列:

初始化DMA后,然后需要使能外设的DMA功能:

最后,再使能DMA传输通道:

当需要查下DMA的状态时,可使用如下的函数:

4.代码:本文只展示DMA和main部分的代码,如果需要完整的代码,可以结合前面的文章来获取。

(1)dma.h:

#ifndef __DMA_H
#define __DMA_H

#include "stm32f10x.h"

//DMA_CHx:DMAͨµÀCHx
//cpar:ÍâÉèµØÖ·
//cmar:´æ´¢Æ÷µØÖ·
//cndtr:Êý¾Ý´«ÊäÁ¿ 
void MYDMA_Config(DMA_Channel_TypeDef* DMA_CHx,u32 cpar,u32 cmar,u16 cndtr );


#endif

(2)dma.c:

#include "dma.h"

DMA_InitTypeDef DMA_InitStructure;
u16 DMA1_LEN;											//DMA´«ÊäµÄÊý¾Ý³¤¶È

void MYDMA_Config(DMA_Channel_TypeDef* DMA_CHx,u32 cpar,u32 cmar,u16 cndtr )
{
	//1.ʹÄÜʱÖÓ£º
	RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE);
	
	//2.ÅäÖÃDMAµÄÏà¹Ø¼Ä´æÆ÷£º
	DMA_DeInit(DMA_CHx);   			//½«DMAµÄͨµÀ1¼Ä´æÆ÷ÖØÉèΪȱʡֵ
	DMA1_LEN = cndtr;
	
	DMA_InitStructure.DMA_PeripheralBaseAddr = cpar;		//ÍâÉè»ùµØÖ·
	DMA_InitStructure.DMA_MemoryBaseAddr = cmar;			//´æ·ÅDMAÊý¾ÝµÄµØÖ·
	DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;//DMA´«Êä·½Ïò
	DMA_InitStructure.DMA_BufferSize = cndtr;		//Ò»´Î´«ÊäµÄÊý¾ÝÁ¿
	DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;	//ÍâÉèµØÖ·ÊÇ·ñµÝÔö
	DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;			//Êý¾Ý´«ÊäʱÄÚ´æµØÖ·ÊÇ·ñµÝÔö
	DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;	//ÍâÉèÊý¾Ý¿í¶È
	DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;			//ÄÚ´æÊý¾Ý¿í¶È
	DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;						//DMA¹¤×÷ģʽ
	DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;				//DMAÓÅÏȼ¶
	DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;					//ÉèÖÃÊÇ·ñÊÇ´æ´¢Æ÷µ½´æ´¢Æ÷µÄ´«Êäģʽ
	
	DMA_Init(DMA_CHx,&DMA_InitStructure);					//½«ÉÏÊöÅäÖÃÐÅϢдÈëDMAµÄ¼Ä´æÆ÷ÖÐ
	
	//¿ªÆôDMA£º
	DMA_Cmd(DMA_CHx,DISABLE);													//Ïȸ´Î»Ò»ÏÂ
	DMA_SetCurrDataCounter(DMA1_Channel4,DMA1_LEN);		//ÉèÖÃDMAͨµÀµÄDMA»º´æ´óС
	DMA_Cmd(DMA_CHx,ENABLE);
}

(3) main.c:

#include "led.h"
#include "usart.h"
#include "delay.h"
#include "lcd.h"
#include "dma.h"
#include "key.h"

const u8 TEXT_TO_SEND[]={"hello world,there are many good things,so we should hold on,hold on"};
#define TEXT_LENGTH sizeof(TEXT_TO_SEND) - 1				//-1ÊDz»°üº¬½áÊø·û
u8 SendBuff[(TEXT_LENGTH+2)*100];

int main(void)
{
	float pro = 0;
	
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
	
	LED_Init();
	LCD_Init();
	usart_init(9600);
	KEY_Init();
	USART_DMACmd(USART1,USART_DMAReq_Tx,ENABLE);			//¿ªÆô´®¿ÚµÄDMA
	
	//DMA1ͨµÀ4,ÍâÉèΪ´®¿Ú1,´æ´¢Æ÷ΪSendBuff,³¤(TEXT_LENTH+2)*100
	MYDMA_Config(DMA1_Channel4,(u32)&USART1->DR,(u32)SendBuff,(TEXT_LENGTH+2)*100);
	
	GPIO_SetBits(GPIOA,GPIO_Pin_8);
	GPIO_ResetBits(GPIOD,GPIO_Pin_2);
	
	
	while(1)
	{
		//printf("test\r\n");
		POINT_COLOR=RED;	  
		if(KEY_2)
		{
			LCD_ShowString(60,150,200,16,16,"Start Transimit....");
			LCD_ShowString(30,40,200,24,24,"hello world");
			LCD_ShowString(60,170,200,16,16,"   %");//ÏÔʾ°Ù·ÖºÅ
			
			while(1)
			{
				if(DMA_GetFlagStatus(DMA1_FLAG_TC4)!=RESET)//µÈ´ýͨµÀ4´«ÊäÍê³É
				{
					DMA_ClearFlag(DMA1_FLAG_TC4);//Çå³ýͨµÀ4´«ÊäÍê³É±êÖ¾
					break; 
				}
			
				pro=DMA_GetCurrDataCounter(DMA1_Channel4);//µÃµ½µ±Ç°»¹Ê£Óà¶àÉÙ¸öÊý¾Ý
				pro=1-pro/((TEXT_LENGTH+2)*100);//µÃµ½°Ù·Ö±È	  
				pro*=100;      //À©´ó100±¶
				LCD_ShowNum(60,170,pro,3,16);	  
			}
			LCD_ShowNum(60,170,100,3,16);//ÏÔʾ100%	  
			LCD_ShowString(60,150,200,16,16,"Transimit Finished!");//Ìáʾ´«ËÍÍê³É
			
			delay_ms(1000);
		}
		
	}
}


5.运行结果:

6.总结:

本文介绍了DMA使用方法,并实验了串口的DMA功能。使用DMA的基本步骤是:

(1)开启时钟,并初始化DMA

(2)配置初始化的结构体信息,调用函数进行初始化

(3)开启DMA数据传输,并使能外设的MDA功能。

本文中理论部分介绍较多,下一节会利用DNM和ADC来进行实验。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

OpenCV如何在图像中寻找轮廓(60)

返回:OpenCV系列文章目录(持续更新中......) 上一篇:OpenCV如何模板匹配(59) 下一篇 :OpenCV检测凸包(61) 目标 在本教程中,您将学习如何: 使用 OpenCV 函数 cv::findContours使用 OpenCV 函数 cv::d rawContours …

基于SSM的校园短期闲置资源置换平台(有报告)。Javaee项目。ssm项目。

演示视频: 基于SSM的校园短期闲置资源置换平台(有报告)。Javaee项目。ssm项目。 项目介绍: 采用M(model)V(view)C(controller)三层体系结构,通过…

英语语法动词和动词的虚拟语气

动词 谓语动词的三大功能:时、态、气 1、时 和 态 的组合构成了英语的 16 种时态。 2、气 表示的是动作的情感和假设。

uboot-网络配置

文章目录 一、网络简介二、修改PHY芯片地址三、删除 uboot 中 74LV595 的驱动代码1.删除宏定义,添加ENET1和ENET2复位引脚,宏定义2.删除内容如下 四、添加 I.MX6U-ALPHA 开发板网络复位引脚驱动 一、网络简介 💦I.MX6UL/ULL 内部有个以太网 …

perl:用 MIDI::Simple 生成midi文件,用 pygame 播放 mid文件

在 csdn.net 下载 strawberry-perl-5.32.1.1-64bit.zip 解压安装在 D:\Strawberry\ 运行 cpan install MIDI::Simple D:\Strawberry\c\bin\gmake.exe test -- OK Running make install for CONKLIN/MIDI-Perl-0.84.tar.gz Installing D:\Strawberry\perl\site\lib\MIDI.pm I…

算法打卡day40

今日任务: 1)139.单词拆分 2)多重背包理论基础(卡码网56携带矿石资源) 3)背包问题总结 4)复习day15 139单词拆分 题目链接:139. 单词拆分 - 力扣(LeetCode) …

【数据库原理及应用】期末复习汇总高校期末真题试卷

试卷 一、填空题 1.________是位于用户与操作系统之间的一层数据管理软件。 2.数据库系统的三级模式结构是指________、________、________。 3.数据库系统的三种数据模型是________ 、________、________。 4.若关系中的某一属性组的值能唯一地标识一个元组,则…

项目管理-项目进度管理3/3

项目管理:每天进步一点点~ 活到老,学到老 ヾ(◍∇◍)ノ゙ 何时学习都不晚,加油 项目进度管理:需掌握 ITTO, 搞懂计算图,问题和解决方案。 项目进度管理6个过程,包括(口…

Qt5.15.2安装Android开发环境。

下载Java 8,不要下Java 20 jdk8 安装跟着默认走就行:C:\Program Files\Java 需要将QtCreator的sdk_definitions.json文件修改一下 “cmdline-tools;latest” 修改为 “cmdline-tools;6.0” 在一个非中文路径,建立一个android-sdk-windows空…

MATLAB 微积分

MATLAB 微积分 MATLAB提供了多种方法来解决微分和积分问题,求解任意程度的微分方程式以及计算极限。最重要的是,您可以轻松求解复杂函数的图,并通过求解原始函数及其导数来检查图上的最大值,最小值和其他文具点。 本章将讨论微…

AD中如何器件带动导线一起旋转

选中器件和导线,右键点击联合,从选中的器件生成联合 点击屏幕右上角的小齿轮(设置按钮),选择下图所示的旋转步进为45度(或其他),器件拖拽设置为Connected Tracks 之后就可以按住空格…

从零开始搭建一个vue项目

从零开始搭建一个vue项目 一、环境准备 1.1 安装node.js 选择合适的LTS版本,然后下载安装,安装地址:https://nodejs.org/en/download 在命令行中查看已安装的node.js版本 node -v v14.14.01.2 切换为淘宝的镜像源 解决国内下载慢的问题,…

【数据结构(邓俊辉)学习笔记】向量06——位图

文章目录 0.概述1.结构2.实现3. 应用3.1 去重3.2 筛法 0.概述 位图(Bitmap)是一种特殊的序列结构,可用以动态地表示由一组(无符号)整数构成的集合。 test() 判断k 是否存在集合S中。set() 将k 加入到集合S中。clear…

免费APP分发平台 - 一个指南和解析

数字化时代的APP分发平台 随着数字化进程的加速免费APP分发平台 - 一个指南和解析,移动应用(APP)市场正迅速扩大。在这个充满竞争的市场中免费APP分发平台 - 一个指南和解析,一个优秀的APP分发平台能够帮助开发者和商家更有效地触…

【matlab基础知识】(三)二维曲线绘制plot

x[-pi:0.0001:pi]; 选择较小步距 ysin(tan(x))-tan(sin(x));plot(x,y) 条件和函数值做一个点乘 x[-2:0.02:2];y1.1*sign(x).*(abs(x)>1.1)x.*(abs(x)<1.1);plot(x,y) 颜色&#xff0c;线形&#xff0c;曲线上的标志 由于0.01cosx波动太小&#xff0c;所以plotyy绘制多…

蓝桥杯练习系统(算法训练)ALGO-949 勇士和地雷阵

资源限制 内存限制&#xff1a;256.0MB C/C时间限制&#xff1a;1.0s Java时间限制&#xff1a;3.0s Python时间限制&#xff1a;5.0s 问题描述 勇士们不小心进入了敌人的地雷阵&#xff08;用n行n列的矩阵表示&#xff0c;*表示某个位置埋有地雷&#xff0c;-表示某个…

可视化大屏C位图:智慧场馆/场所图

Hello&#xff0c;我是大千UI工场&#xff0c;本期可视化大屏的焦点图&#xff08;C位&#xff09;分享将场馆作为焦点图的情形&#xff0c;欢迎友友们关注、评论&#xff0c;如果有订单可私信。 智慧场馆是指通过物联网、大数据、人工智能等技术手段&#xff0c;将传统场馆与…

ctfshow crypto rsa部分题目简单题解

easyrsa1 下载点击打开附件 e 65537 n 1455925529734358105461406532259911790807347616464991065301847 c 69380371057914246192606760686152233225659503366319332065009 题目中给了e,n,c的值。 使用在线网址factordb.com 分解n得到p&#xff0c;q 编写脚本 import gm…

Java项目:基于SSM框架实现的在线医疗服务系统(ssm+B/S架构+源码+数据库+毕业论文+开题报告)

一、项目简介 本项目是一套基于SSM框架实现的在线医疗服务系统 包含&#xff1a;项目源码、数据库脚本等&#xff0c;该项目附带全部源码可作为毕设使用。 项目都经过严格调试&#xff0c;eclipse或者idea 确保可以运行&#xff01; 该系统功能完善、界面美观、操作简单、功能…

为什么 IP 地址通常以 192.168 开头?(精简版)

网络通讯的本质就是收发数据包。如果说收发数据包就跟收发快递一样。IP地址就类似于快递上填的收件地址和发件地址一样&#xff0c;路由器就充当快递员的角色&#xff0c;在这个纷繁复杂的网络世界里找到该由谁来接收这个数据包&#xff0c;所以说&#xff1a;IP地址就像快递里…