STM32 LCD-ADC-DMA实验

news2025/1/19 8:14:40

目录

1.1 STM32 DMA简介

1.2 STM32 DMA的操作

1.DMA的初始化

2. 初始化代码

3. 主函数代码


本文将向大家介绍 STM32 的 DMA。(如有错误,欢迎批评指正) 在本章中,我们将利用 STM32 的 DMA 来实现ADC1通道1内数据传送,并在 TFTLCD 模块上显示传送数据AD的电压值。本章分为以下学习目标:

1.了解什么是DMA

2.懂得操作STM32的DMA

1.1 STM32 DMA简介

DMA,全称为: Direct Memory Access,即直接存储器访问, DMA 传输将数据从一个地址空间复制到另外一个地址空间。 当 CPU 初始化这个传输动作,传输动作本身是由DMA 控制器来实行和完成。典型的例子就是移动一个外部内存的区块到芯片内部更快的内存区。像是这样的操作并没有让处理器工作拖延,反而可以被重新排程去处理其他的工作。 DMA 传输对于高效能嵌入式系统算法和网络是很重要的。DMA 传输方式无需 CPU 直接控制传输,也没有中断处理方式那样保留现场和恢复现场的过程,通过硬件为 RAM 与 I/O 设备开辟一条直接传送数据的通路, 能使 CPU 的效率大为提高。

STM32 最多有 2 个 DMA 控制器( DMA2 仅存在大容量产品中), DMA1 有 7 个通道。 DMA2 有 5个通道。每个通道专门用来管理来自于一个或多个外设对存储器访问的请求。还有一个仲裁起来协调各个 DMA 请求的优先权。

STM32的DMA有以下一些特性:

  • 每个通道都直接连接专用的硬件 DMA 请求,每个通道都同样支持软件触发。这些功能通过软件来配置。
  • 在七个请求间的优先权可以通过软件编程设置(共有四级:很高、高、中等和低),假如 在相等优先权时由硬件决定(请求 0 优先于请求 1,依此类推) 。
  • 独立的源和目标数据区的传输宽度(字节、半字、全字),模拟打包和拆包的过程。源和 目标地址必须按数据传输宽度对齐。
  • 支持循环的缓冲器管理。
  • 每个通道都有 3 个事件标志(DMA 半传输, DMA 传输完成和 DMA 传输出错),这 3 个 事件标志逻辑或成为一个单独的中断请求。
  • 存储器和存储器间的传输。
  • 外设和存储器,存储器和外设的传输
  • 闪存、 SRAM、外设的 SRAM、 APB1 APB2 和 AHB 外设均可作为访问的源和目标。
  • 可编程的数据传输数目:最大为 65536

STM32F103ZET6 有两个 DMA 控制器, DMA1 和 DMA2, 本章我们仅针对 DMA1 进行介绍。

从外设( TIMx、 ADC、 SPIx、 I2Cx 和 USARTx)产生的 DMA 请求,通过逻辑或输入到DMA 控制器,这就意味着同时只能有一个请求有效。外设的 DMA 请求,可以通过设置相应的外设寄存器中的控制位,被独立地开启或关闭。

接下来我们来看一下,DMA 1主要有哪些通道:

 这里解释一下上面说的逻辑或,例如通道 1 的几个 DMA1 请求( ADC1、 TIM2_CH3、 TIM4_CH1),这几个是通过逻辑或到通道 1 的,这样我们在同一时间,就只能使用其中的一个。其他通道也是类似的。

接下来我们来看一下,DMA 2主要有哪些通道:

 从上图我们看出 STM32 的 DMA 很多,但大致操作时一样的,这里我们主要讲述ADC DMA 的操作方式。

1.2 STM32 DMA的操作

1.DMA的初始化

DMA配置通道的过程为:

 不过呢,我们使用 V3.5 库函数操作的话,我们只需要调用 DMA_Init()函数就可以了。

DMA_Init()函数有两个输入参数:

1) DMA_Channelx:用来选择要初始化的通道参数。我们这里以ADC1为例,查看上
面的 DMA1 的通道表,我们知道ADC 1的 DMA 通道是是通道 1,所以打开ADC1的通道:DMA1_Channel1。

2) DMA_InitStruct:这个是用来设置 DAM 参数的结构,它一共有 11 个成员,它的成员如下:

  • DMA_PeripheralBaseAddr:外设基地址,也就是你 DMA 要传输数据 的目的地,我们是要使用到ADC1,所以设置为ADC1 的地址:(u32)&ADC1->DR(注意是地址)。
  • DMA_MemoryBaseAddr:内存基地址,也就是你 DMA 要搬运数据的存放的首地址,如果你是定义了一组数组发送,那么就设置为你的数据首地址。
  • DMA_BufferSize:DMA 通道的缓存大小。即设置一次传输数据量的大小,这个很容易理解。
  • DMA_PeripheralInc:是否使能外设地址递增。我们直接使用ADC1的 发 送 寄 存 器 , 地 址 不 递 增 , 所 以 设 置 为 : DMA_PeripheralInc_Disable。
  • DMA_MemoryInc:是否使能内存地址递增。我们发送的数据发送完 一 位 , 肯 定 是 发 送 下 一 位 , 所 以 这 里 肯 定 要 使 能 : DMA_MemoryInc_Enable。
  • DMA_PeripheralDataSize:设置外设数据宽度,ADC保存数组内数据是16位,所以设置为:DMA_PeripheralDataSize_HalfWord。
  • MA_MemoryDataSize : 内 存 数 据 宽 度 , 这 里 也 设 置 为 :DMA_MemoryDataSize_HalfWord。
  • DMA_Mode:传送模式。DMA 的工作模式又两种,第 1 种是工作在 循环缓存模式,也就是将数据一直重复发送,第 2 种工作在正常缓存模式,也就是只将数据传送一次。我们这里设置为循环缓存模式:DMA_Mode_Circular。
  • DMA_Priority:DMA 的传输顺序是有优先级的,当有两个 DMA 同时使用的时候, 优先级高的先发送。 而 DMA 的等级一共有四种等级:

                a) 最高优先级
                b) 高优先级
                c) 中优先级
                d) 低优先级 我们这里只使用一个 DMA,随便设置就好。

  • DMA_M2M : 是 否 使 用 存 储 器 到 存 储 器 模 式 , 我 们 设 置 为 DMA_M2M_Disable。

2. 初始化代码

void dma_init()	   //DMA初始化
{
	//结构体定义
	GPIO_InitTypeDef GPIO_InitStructure;
	ADC_InitTypeDef ADC_InitStructure;
	DMA_InitTypeDef DMA_InitStructure;

	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_AFIO|RCC_APB2Periph_ADC1,ENABLE);
	RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE);
	RCC_ADCCLKConfig(RCC_PCLK2_Div6);//12M  最大14M 设置ADC时钟(ADCCLK)
	ADC_DeInit(ADC1);

	GPIO_InitStructure.GPIO_Pin=GPIO_Pin_1;//ADC  //1
	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AIN;	//模拟输入
	GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_Init(GPIOA,&GPIO_InitStructure);	  //A


	ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; 
	ADC_InitStructure.ADC_ScanConvMode = DISABLE; 
	ADC_InitStructure.ADC_ContinuousConvMode = ENABLE; 
	ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; 
	ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; 
	ADC_InitStructure.ADC_NbrOfChannel = 1; 
	ADC_Init(ADC1, &ADC_InitStructure);
	
	//设置指定ADC的规则组通道,设置它们的转化顺序和采样时间
	ADC_RegularChannelConfig(ADC1,ADC_Channel_1,1,ADC_SampleTime_239Cycles5); //1
	
	//内部温度传感器是在ADC1通道16的。
//	ADC_RegularChannelConfig(ADC1,ADC_Channel_16,1,ADC_SampleTime_239Cycles5);
//	ADC_TempSensorVrefintCmd(ENABLE);//打开内部温度传感器使能

	ADC_DMACmd(ADC1,ENABLE);//将ADC与DMA链接在一起
	ADC_Cmd(ADC1,ENABLE);	

	ADC_ResetCalibration(ADC1);//重置指定的ADC的校准寄存器
	while(ADC_GetResetCalibrationStatus(ADC1));//获取ADC重置校准寄存器的状态	
	ADC_StartCalibration(ADC1);//开始指定ADC的校准状态
	while(ADC_GetCalibrationStatus(ADC1));//获取指定ADC的校准程序
	ADC_SoftwareStartConvCmd(ADC1, ENABLE);//使能或者失能指定的ADC的软件转换启动功能

	DMA_DeInit(DMA1_Channel1);
	DMA_InitStructure.DMA_PeripheralBaseAddr =(u32)&ADC1->DR;//DMA外设地址
	DMA_InitStructure.DMA_MemoryBaseAddr=(u32)&adc_data;//DMA内存地址
	DMA_InitStructure.DMA_DIR=DMA_DIR_PeripheralSRC;//外设作为数据传输的来源
	DMA_InitStructure.DMA_BufferSize=1;//指定DMA通道的DMA缓存的大小
	DMA_InitStructure.DMA_PeripheralInc=DMA_PeripheralInc_Disable;//外设地址寄存器递增
	DMA_InitStructure.DMA_MemoryInc=DMA_PeripheralInc_Enable;//内存地址寄存器递增
	DMA_InitStructure.DMA_PeripheralDataSize=DMA_PeripheralDataSize_HalfWord;//外设数据宽度16  
	DMA_InitStructure.DMA_MemoryDataSize=DMA_MemoryDataSize_HalfWord;//存储数据宽度16
	DMA_InitStructure.DMA_Mode=DMA_Mode_Circular;//工作在循环缓存模式	 
	DMA_InitStructure.DMA_Priority=DMA_Priority_High;//DMA通道x拥有高优先级
	DMA_InitStructure.DMA_M2M=DMA_M2M_Disable;//DMA通道x没有设置为内存到内存传输
	DMA_Init(DMA1_Channel1,&DMA_InitStructure);	//ADC1在DMA1通道1内
	DMA_Cmd(DMA1_Channel1,ENABLE);//使能DMA1
}

3. 主函数代码

int main()			  
{	
	u16 value;
	u8 i,j,dat[6];
	float ad;
	dma_init();	  //DMA初始化 
	TFT_Init();	 //TFT彩屏初始化
	LED_Init();	  //端口初始化
	printf_init();	//printf初始化
	TFT_ClearScreen(BLACK);	   //清屏
	GUI_Show12ASCII(10,10,"This is a ADC1-DMA1 Check!",YELLOW,BLACK);
	GUI_Show12ASCII(10,27,"PA1 is AD Input!",YELLOW,BLACK);
	GUI_Show12ASCII(10,100,"The AD Volage is:",YELLOW,BLACK);
	while(1)
	{
		value=0;
		for(i=0;i<10;i++)//读取10次的AD数值取其平均数较为准确	
		{
			value=value+adc_data[0];		
		}
		delay_ms(500);
		value=value/10;
		ad=value*3.3/4095;
		value=(u16)(ad*100);
		dat[0]=value/100+0x30;
		dat[1]='.';
		dat[2]=value%100/10+0x30;
		dat[3]=value%100%10+0x30;
		dat[4]='V';
		dat[5]='\0';
		GUI_Show12ASCII(160,100,dat,YELLOW,BLACK);
		if(j>1)
		{
			j=0;
			GPIO_SetBits(GPIOC,GPIO_Pin_0);
		}
		else
		{
			j++;
			GPIO_ResetBits(GPIOC,GPIO_Pin_0);
		} 
								
	}			
}

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

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

相关文章

图像处理学习——基于霍夫变换(Matlab代码实现)

目录 &#x1f4a5;1 概述 &#x1f4da;2 运行结果 &#x1f389;3 参考文献 &#x1f468;‍&#x1f4bb;4 Matlab代码 &#x1f4a5;1 概述 霍夫变换是一种在图像中寻找直线、圆形以及其他简单形状的方法。 霍夫变换采用类似于投票的方式来获取当前图像内的形状集合&…

银河麒麟之语言设置和服务开机自启动设置

一、前言 银河麒麟操作系统作为国产操作系统&#xff0c;是目前国产化、信创等项目场景的主流操作系统之一&#xff0c;但它本质上还是基于现有的开源操作系统上的二次开发&#xff0c;银河麒麟服务器版是基于centos的&#xff0c;银河麒麟桌面版是基于debain的。既然是国产化系…

CAPL语言

1. CAPL简介 CAPL&#xff0c;Communication Access Programming Language&#xff0c;即通信访问编程语言类C语言2. CAPL主要用途 仿真节点或模块仿真时间报文、周期报文或者附加条件的重复报文使用PC键盘模拟操作按钮等人工操作事件仿真节点的定时或网络事件仿真多个时间事…

从编译器角度理解C++代码的编译和链接原理

在本文中&#xff0c;我们将探讨C代码的预处理、编译和链接过程。我们将详细介绍每个过程的作用和步骤&#xff0c;并通过代码演示来解释这个过程。 预处理 C代码预处理是将源代码转换为另一个源代码的过程&#xff0c;其中包括宏展开、条件编译、头文件包含等操作。预处理器…

Level3题目整理

文章目录L3-001 凑零钱L3-002 特殊堆栈L3-003 社交集群&#xff08;并查集vector暴力⭐&#xff09;L3-004 肿瘤诊断(三维bfs)L3-005 垃圾箱分布&#xff08;多次dijkstra&#xff09;L3-008 喊山&#xff08;邻接表bfs&#x1f53a;&#xff09;L3-010 是否完全二叉搜索树&…

C++ STL学习之【list的模拟实现】

✨个人主页&#xff1a; 夜 默 &#x1f389;所属专栏&#xff1a; C修行之路 &#x1f38a;每篇一句&#xff1a; 图片来源 A year from now you may wish you had started today. 明年今日&#xff0c;你会希望此时此刻的自己已经开始行动了。 文章目录&#x1f307;前言&am…

零售数据分析之操作篇12:子查询的应用

各位数据的朋友&#xff0c;大家好&#xff0c;我是老周道数据&#xff0c;和你一起&#xff0c;用常人思维数据分析&#xff0c;通过数据讲故事。 上期内容与作业 上一讲讲了占比相关内存计算的应用场景&#xff0c;包括占比、TOP占比、累计占比等&#xff0c;不同的占比&am…

sinGAN论文笔记

Background Knowledge 基于推理的视觉理论&#xff1a; 只根据图像数据本省不能对相对应的物体空间结构提供充分的约束&#xff0c;也就是说这是一个约束不充分的问题&#xff0c;因此为了理解图像的内容必须要有附加的约束条件&#xff08;例如知道图中是哪一类物体的知识&am…

帮助中心能帮助企业解决什么问题?

帮助中心是企业在网站、应用程序或其他数字渠道上提供的一种资源&#xff0c;旨在帮助客户解决问题、回答常见问题并提供支持。一个完善的帮助中心可以为企业带来很多好处&#xff0c;包括提高客户忠诚度、提高满意度、降低客户支持成本等。 帮助中心能帮助企业解决的问题 提…

为什么会有JMM?从0到1一次性说清楚

JMM&#xff08;Java Memory Model&#xff09;是一种规范&#xff0c;定义了在多线程环境下Java程序中的内存访问行为。JMM保证了在多线程环境下程序的正确性&#xff0c;同时也允许编译器和处理器对指令进行优化&#xff0c;以提高程序的性能。 Java线程之间的通信由Java内存…

网络编程套接字(一)

学习任务&#xff1a; 我们先来认识端口号&#xff0c;区分好主机IP和端口号的区别&#xff0c;以及涉及到进程PID和端口号的区别。 然后简单认识一下TCP协议和UDP协议&#xff0c;这两个协议都是传输层的。接着了解什么是网络字节序&#xff0c;它有什么作用。然后是网络编程的…

Windows搭建Typecho个人博客并发布公网访问【内网穿透】

文章目录前言1. 环境安装2. 安装Typecho3. 安装cpolar内网穿透4. 固定公网地址5. 配置Typecho前言 本文小新为大家带来windwos系统搭建typecho博客cpolar内网穿透工具将博客发布到公共网络环境教程。 Typecho是一款PHP语言编写的开源博客程序&#xff0c;它是一个轻量级的内容…

某某客户的一次勒索病毒应急响应

Lockbit勒索病毒应急响应背景1、应急处理排查2、勒索病毒来源分析3、勒索病毒分析4、勒索病毒解密5、主机分析分析6、后续安全加固和改进措施结论背景 美好的周六刚开始&#xff0c;眼睛一睁&#xff0c;领导就发消息&#xff0c;说某客户中了勒索病毒&#xff0c;特别着急&am…

测评了100款零售软件,选出5个最好用零售软件分享给你!

满大街的各种服装店、便利店、百货店、母婴店...... 每天都要处理大量的订单&#xff0c;使用传统的人工开单记账&#xff0c;效率低下、客户体验差、而且容易出现&#xff0c;需要耗费很多时间来回对账&#xff1b; 聪明的零售店老板都已经开始使用零售软件来管理门店&#xf…

[C++]list类的模拟实现和相关函数的详解(正反向迭代器)

文章目录架构代码实现listNode正向迭代器框架迭代器函数重载*&#xff08;解引用&#xff09;->&#xff08;箭头指向&#xff09; -- ! 反向迭代器框架*&#xff08;解引用&#xff09;->&#xff08;箭头指向&#xff09; -- ! list默认成员函数构造函数拷贝构造赋值重…

QT学习笔记2

1.重载自定义信号与槽&#xff1a; 定义天黑类&#xff1a;里面有一个有参数的信号和没有参数的信号 tianhei.h #ifndef TIANHEI_H #define TIANHEI_H#include <QObject>class Tianhei : public QObject {Q_OBJECT public:Tianhei(); //构造函数声明signals:void tia…

Linux 用户的特殊shell与PAM模块

文章目录Linux 用户的特殊shell与PAM模块特殊的shell&#xff1a;/sbin/nologinPAM模块简介PAM模块设置语法常用模块简介login的PAM验证机制流程其他相关文件limits.conf使用案例/var/log/secure、/var/log/messagesLinux 用户的特殊shell与PAM模块 你想过吗&#xff1f;如果我…

无向连通图中长度为 n 的循环

给定一个无向连通图和一个数字 n,计算图中长度为 n 的循环总数。长度为 n 的圈简单地表示该圈包含 n 个顶点和 n 条边。我们必须计算所有存在的此类循环。 示例: 输入:n = 4 输出:总周期数 = 3 解释 :遵循 3 个独特的循环0 -> 1 -> 2 -> 3 -> 0 0 -> 1 …

【一起啃书】《机器学习》第一章 绪论 + 第二章 模型评估与选择

第一章 绪论 1.机器学习&#xff1a;研究如何通过计算的手段&#xff0c;利用经验来改善系统自身的性能。在计算机系统中&#xff0c;”经验“通常以“数据”的形式存在&#xff0c;所以机器学习研究的主要内容也是如何通过这些数据产生一个模型&#xff0c;进而通过这个模型为…

基于SpringBoot+Vue毕业生信息招聘平台系统【源码+论文+演示视频+包运行成功】

您好&#xff0c;我是码农飞哥&#xff0c;感谢您阅读本文&#xff0c;欢迎一键三连哦。 &#x1f4aa;&#x1f3fb; 1. Python基础专栏&#xff0c;基础知识一网打尽&#xff0c;9.9元买不了吃亏&#xff0c;买不了上当。 Python从入门到精通 ❤️ 2.网上优质的Python题库很少…