【STM32】ADC模拟数字转换(规则组多通道)+ DMA数据转运(外设到存储器)

news2024/11/24 7:21:00

本篇博客重点在于标准库函数的理解与使用,搭建一个框架便于快速开发

目录

前言

ADC规则组扫描模式+DMA

定义变量

规则组配置 

ADC初始化 

连续模式

 扫描模式

规则组通道个数 

 ADC初始化框架

 DMA初始化

ADC和DMA使能 

 软件触发转运

 代码框架

ADC扫描转换与DMA循环转运

单次扫描+单轮转运


前言

本篇博客会在下面两篇的代码及理解的基础上修改。阅读本篇之前建议先阅读以下两篇博客: 

 【STM32】ADC模拟数字转换-规则组单通道-CSDN博客

【STM32】DMA数据转运(存储器到存储器)-CSDN博客

ADC规则组扫描模式+DMA

  之前学习了ADC规则组单通道,这种方式只能一次触发一个通道的ADC转换,虽然可以通过每次触发前改变序列上的通道号来对通道实现轮询的转换,但每次触发也只能转换一个通道的模拟量,不能一次ADC触发实现多个模数转换,效率较低。

本篇来学习ADC规则组的多通道转换,一次触发ADC转换可以实现转换多个通道,已知ADC规则组数据寄存器只有一个,当配置为多通道转换时,每个序列上的通道会依次把数据存在数据寄存器中。规则组转换完成一次时(标志位EOC为1),最终数据寄存器上的数据是最后一个指定的序列上的通道转换的值。前面通道的数据都会覆盖,因为组内每一个序列上通道转换完成时,没有标志位,无法通过软件实现检查标志位控制CPU来实现转运数据,那该怎么办呢?

可以通过ADC发出DMA请求,每一个序列上的通道转换完成都会发出DMA请求。ADC序列1的通道转换完成发出DMA请求,触发DMA转运,DMA就会把ADC规则组数据寄存器位置上的数据转运到指定地址,序列2的通道转换完成,数据覆盖上一次转化的数据,再次发出DMA请求,DMA转运数据(转运相当于复制了数据再转运,原数据依然在寄存器中)

图片来源于[8-1] DMA直接存储器存取_哔哩哔哩_bilibili

参考手册

DMA请求 因为规则通道转换的值储存在一个仅有的数据寄存器中,所以当转换多个规则通道时需要使用 DMA,这可以避免丢失已经存储在ADC_DR寄存器中的数据。 只有在规则通道的转换结束时才产生DMA请求,并将转换的数据从ADC_DR寄存器传输到用户指定的目的地址。

注: 只有ADC1和ADC3拥有DMA功能。由ADC2转化的数据可以通过双ADC模式,利用ADC1的 DMA功能传输。 

定义变量

ADC分辨率为12位,但规则组通道数据寄存器为16位,我这里数据设置右对齐,定义无符号16位储存规则组4个通道的值

关于数据对齐的解释这里不再赘述

uint16_t AD_Value[4]; //存放DMA转运的ADC转换数据

规则组配置 

将ADC1的通道0 ,1,2,3分别放在序列1,2,3,4的位置,采样时间都为55.5个ADC周期

	ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_55Cycles5);
	ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 2, ADC_SampleTime_55Cycles5);
	ADC_RegularChannelConfig(ADC1, ADC_Channel_2, 3, ADC_SampleTime_55Cycles5);
    ADC_RegularChannelConfig(ADC1, ADC_Channel_3, 4, ADC_SampleTime_55Cycles5);

ADC初始化 

连续模式

触发ADC转换一次就可使ADC连续不停的转换,从序列1的通道到指定的序列号上的通道转换完成后,再次从序列1的通道转换

ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;//连续模式使能

 扫描模式

 扫描模式用于规则组多通道,从第一个序列到指定序列,依次扫描,就是依次转换模拟量

    ADC_InitStructure.ADC_ScanConvMode = ENABLE;

规则组通道个数 

指定的序列号,共有几个通道要转换

ADC_InitStructure.ADC_NbrOfChannel = 4;

 ADC初始化框架

	ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
    ADC_InitStructure.ADC_ScanConvMode = ENABLE;
    ADC_InitStructure.ADC_NbrOfChannel = 4;

 DMA初始化

    DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&ADC1->DR;//ADC1规则组数据寄存器的32位地址(基地址)
	DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;//半字,16位
	DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;//外设基地址指针自增失能,不用自增,固定指(uint32_t)&ADC1->DR
	DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)AD_Value;//存储器32位基地址
	DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;//半字,16位
    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;//转运数据寄存器地址指针自增
    DMA_InitStructure.DMA_BufferSize = 4;//一次DMA触发的转运次数
	DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;//循环模式,与ADC连续模式对应
    DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;//存储器到存储器失能,也是软件触发失能。用硬件触发,本代码硬件触发为ADC1

ADC和DMA使能 

    DMA_Cmd(DMA1_Channel1, ENABLE);//使能DMA1的通道1
	ADC_DMACmd(ADC1, ENABLE);//使能ADC发出DMA请求,与硬件触发DMA对应
    ADC_Cmd(ADC1, ENABLE);//ADC上电

 软件触发转运

软件触发ADC转换模拟量,不用硬件触发

	ADC_SoftwareStartConvCmd(ADC1, ENABLE);//与ADC软件触发对应

 代码框架

ADC扫描转换与DMA循环转运

ADC开启连续转换模式,ADC规则组内转换完成就会再次重复转换。DMA开启循环转运模式。这样就不需要每次都软件触发ADC转换,且待DMA置转运完成标志位,再去取数据了。只需要软件触发一次,就可ADC连续转换,DMA循环转运到存储器,初始化后数据直接读取寄存器即可

uint16_t AD_Value[4]; //存放DMA转运的ADC转换数据

void AD_Init(void)
{
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
	RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
	
	RCC_ADCCLKConfig(RCC_PCLK2_Div6);
	
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);
	
	ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_55Cycles5);
	ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 2, ADC_SampleTime_55Cycles5);
	ADC_RegularChannelConfig(ADC1, ADC_Channel_2, 3, ADC_SampleTime_55Cycles5);
	ADC_RegularChannelConfig(ADC1, ADC_Channel_3, 4, ADC_SampleTime_55Cycles5);
		
	ADC_InitTypeDef ADC_InitStructure;
	ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
	ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
	ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
	ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
	ADC_InitStructure.ADC_ScanConvMode = ENABLE;
	ADC_InitStructure.ADC_NbrOfChannel = 4;
	ADC_Init(ADC1, &ADC_InitStructure);
	
	DMA_InitTypeDef DMA_InitStructure;
	DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&ADC1->DR;
	DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
	DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
	DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)AD_Value;
	DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
	DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
	DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
	DMA_InitStructure.DMA_BufferSize = 4;
	DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
	DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
	DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;
	DMA_Init(DMA1_Channel1, &DMA_InitStructure);
	
	DMA_Cmd(DMA1_Channel1, ENABLE);
	ADC_DMACmd(ADC1, ENABLE);
	ADC_Cmd(ADC1, ENABLE);
	
	ADC_ResetCalibration(ADC1);
	while (ADC_GetResetCalibrationStatus(ADC1) == SET);
	ADC_StartCalibration(ADC1);
	while (ADC_GetCalibrationStatus(ADC1) == SET);
	
	ADC_SoftwareStartConvCmd(ADC1, ENABLE);
}

单次扫描+单轮转运

将上面代码主函数的软件触发ADC删除;再将ADC连续模式失能,软件触发转换后,规则组转换扫描一次就停止;DMA转运循环模式失能,ADC规则组每个通道转换完,发出DMA请求后,转运次数减一,直到转运次数为0,一轮转运就结束,ADC各个通道的数据就可以取出来了

ADC_InitStructure.ADC_ContinuousConvMode = DISABLE; //ADC扫描模式失能

DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;//DMA转运一轮

ADC_SoftwareStartConvCmd(ADC1, ENABLE);//使能软件触发ADC转换

 获取ADC数据

获取ADC数据,需要触发ADC转换和改变转运次数 ,等到DMA转运完成后就可取出数据

void AD_GetValue(void)
{	
	DMA_Cmd(DMA1_Channel1, DISABLE);
    DMA_SetCurrDataCounter(DMA1_Channel1, 4);
    DMA_Cmd(DMA1_Channel1, ENABLE);
	
	ADC_SoftwareStartConvCmd(ADC1,ENABLE);
	
    while(DMA_GetFlagStatus(DMA1_FLAG_TC1) == RESET);
    DMA_ClearFlag(DMA1_FLAG_TC1);	
}

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

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

相关文章

一眼心动的HAProxy高级功能配置

目录 一.haproxy-基于cookie的会话保持 二.七层IP透传 三.四层IP透传 四.访问控制列表ACL 五.acl做动静分离访问控制 六.基于自定义的错误页面文件 七.HAProxy 四层负载 八.HAProxy https 实现 九.让文件编写更简单的方法 一.haproxy-基于cookie的会话保持 cookie va…

C语言程序设计(初识C语言后部分)

1024M1GB,1GB1级棒。关爱一级棒的程序员们,宠TA没商量! 5)函数的嵌套调用和链式访问 函数和函数之间可以根据实际的需求进行组合的,也就是相互调用的。 1.嵌套调用 函数可以嵌套调用,但不可以嵌套定义&a…

【网络】UDP和TCP之间的差别和回显服务器

文章目录 UDP 和 TCP 之间的差别有连接/无连接可靠传输/不可靠传输面向字节流/面向数据报全双工/半双工 UDP/TCP API 的使用UDP APIDatagramSocket构造方法方法 DatagramPacket构造方法方法 回显服务器(Echo Server)1. 接收请求2. 根据请求计算响应3. 将…

html+css+js网页制作 纳尔多珠宝40个页面

htmlcssjs网页制作 纳尔多珠宝40个页面 网页作品代码简单,可使用任意HTML编辑软件(如:Dreamweaver、HBuilder、Vscode 、Sublime 、Webstorm、Text 、Notepad 等任意html编辑软件进行运行及修改编辑等操作)。 获取源码 1&#…

用python制作88键赛博钢琴(能用鼠标键盘进行弹奏)

用python制作88键赛博钢琴 前言 恭喜这位博主终于想起了自己的账号密码! 时光荏苒,转眼间已逾一年未曾在此留下墨香。尽管这一年间,博主投身于无尽的忙碌与挑战之中,但令人欣慰的是,那份初心与热情似乎并未因岁月的流…

谷歌浏览器网页底图设置为全黑

输入网址:chrome://flags/ 搜索dark,选择Enabled,重启浏览器即可

C#使用SharGL实现PUMA560机械臂

1、四轴机械臂 下载链接:https://download.csdn.net/download/panjinliang066333/89645225 关键代码 public void DrawRobot1(ref OpenGL gl,float[] angle,float[] yLength,bool isPuma560_Six){//坐标系说明://①X轴正向:屏幕朝右//②Y轴…

【运维系列】windows虚拟机作为服务器,将服务启动作为脚本设置为开机自启,服务中断、手动操作的烦恼通通滚蛋!

文章目录 前言一、开机启动文件夹(StartUp)是否可行?二、任务计划程序1.编写脚本2.打开任务计划程序3.创建任务4.配置常规选项5.配置触发器选项6. 配置操作选项7.配置条件选项8.配置设置选项 总结 前言 在实际应用过程中,我们难免…

有没有电脑桌面监控软件|大佬都在用的7大电脑屏幕监控软件!

当谈到电脑桌面监控软件时,确实有许多受欢迎且功能强大的选项。 这些软件在企业管理、远程办公、家庭监控等多个领域都有广泛应用。 以下是大佬常用的7大电脑屏幕监控软件推荐: 1. Teramind 特点:它是一款功能强大的企业级监控软件&#x…

永久旋转 PDF 文件的 3 种简便方法

PDF 文件通常由扫描仪创建,用于呈现文档或书籍。当您输出 PDF 作品时,打开它,会发现有几页是颠倒的。 你应该做什么? 将这些页面倒置扫描,按顺序排列,最后创建正确的 PDF 文件? 当然&#xf…

<数据集>安全帽和安全背心识别数据集<目标检测>

数据集格式:VOCYOLO格式 图片数量:22141张 标注数量(xml文件个数):22141 标注数量(txt文件个数):22141 标注类别数:3 标注类别名称:[helmet, vest, head] 序号类别名称图片数框数1helmet15937572402v…

轻量级TinyDB数据库文件写入和增删改查操作

1. TinyDB 数据库简介 TinyDB 是一个轻量级的 NoSQL 文档型数据库,由 Python 实现,无需额外的配置,以 JSON 文件作为存储,默认使用文件系统来存储数据。 2. 安装基本库 pip install tinydb pip install Faker3. 数据库操作 im…

无线麦克风哪个品牌音质最好,口碑最好的麦克风品牌推荐

​随着个人媒体和视频内容的普及,每个人都有机会成为内容的创作者。在这样的趋势下,拥有一个好的录音设备就显得尤为重要。无线领夹麦克风正好满足了这种需要,它不仅能够提供清晰、稳定的音质,还能使内容创作更具有专业性和观赏性…

基于个性化定制的智慧校园管理系统设计与开发

TOC springboot296基于个性化定制的智慧校园管理系统设计与开发 第1章 绪论 1.1 课题背景 二十一世纪互联网的出现,改变了几千年以来人们的生活,不仅仅是生活物资的丰富,还有精神层次的丰富。在互联网诞生之前,地域位置往往是…

C语言常用的内存函数

在上一篇博客中我为大家分享了一些常用的字符串函数,以及它们的用法和模拟实现。通过字符串函数中的strcpy,我们能够做到将一个字符串中的内容拷贝到另一个字符串上,可如果有一天我们想把一个整型数组中的内容拷贝到另一个整型数组中呢&#…

大模型混合云,到了系统性创新突围的关键时刻

文 | 智能相对论 作者 | 陈泊丞 亚马逊与Anthropic、微软与OpenAI以及华为云提出的大模型混合云概念等等种种信号都在表明,云计算与大模型深度融合发展的趋势已是业内共识。 目前,以生成式AI为导向,越来越多的公司开始加速大模型技术在云计…

够豪横,310万不要了,后续损失恐上千万

近日,深圳一套法拍房引起了整个圈子的轰动! 20年前花费382万购入的豪宅,现在竟能拍到8389万,翻了22倍! 就在大家都感慨深圳顶豪的购买力惊人时,事情却迎来了更大的反转! 该豪宅竟重现法拍市场…

【HarmonyOS】鸿蒙应用实现调用系统地图导航或路径规划

【HarmonyOS】鸿蒙应用实现调用系统地图导航或路径规划 前言 在涉及地图业务中,调用地图导航和路径规划是三方应用中较为常见的功能。 若只是子业务需要地图导航效果,整个APP内部集成地图去实现导航或者路径规划,会造成SDK集成冗余。毕竟很…

校园外卖服务系统设计与实现

TOC springboot292校园外卖服务系统设计与实现 第一章 课题背景及研究内容 1.1 课题背景 信息数据从传统到当代,是一直在变革当中,突如其来的互联网让传统的信息管理看到了革命性的曙光,因为传统信息管理从时效性,还是安全性&…

若依 Ruoyi4.7.9 创建页面并显示

自行从https://gitee.com/y_project/RuoYi下载源代码,这个不再赘述。 // 下载后会发现现在的Ruoyi环境,分成了6个模块: 模块主要的介绍大家可以看文档。 官网地址:https://doc.ruoyi.vip/ruoyi/ 我下载的这个是基于mvc框架&…