基于STM32F103C8T6的高速DMA传输多通道ADC数据
文章目录
- 前言
- 一、软件设计思路
- 二、代码
- 总结
前言
ADC在STM32系列单片机的使用中占用着很大的比例,常见的案例是通过ADC单次转换电压值,这种方式的缺陷在于转换效率不高。一般的单片机带有ADC1和ADC2两个ADC转换,单次转换需要执行一定的程序,想得到结果需要耗费一些时间在赋值,调用中断上面。在此基础上,为了提高转换的效率,借用单片机内部自带的DMA传输单元,可以直接越过CPU指令,将数据传送到我们所定义的寄存单元内部,这样我们需要查看检测的电压数据时,只需要直接访问存储数组即可。
一、软件设计思路
整体的软件设计思路分为两个大的环节:初始化ADC和开启高速DMA数据传输。在本次实验中,选用ADC1作为转换单元,这是比较基础的只用到一个ADC的转换方式,在ADC的使用之中,可以以ADC1和ADC2相互配合的方式进行交替采样,其优点在于两次采样中间只需要间隔极短的时间,比单次采样要快很多,在后续会进行更新,此处只用到一个ADC单元。
ADC初始化需要设置好转换的时间,转换的IO口以及转换的触发方式。而高速DMA也需要设置对应的触发方式,这里是通过ADC进行触发。在DMA传输的过程中,需要设定好DMA传输的方式以及地址,下面就针对具体的代码进行设计。
二、代码
代码如下:开头用define定义了ADC1_DR_Address,这是ADC存放检测数据的地址,DMA单元可以通过此地址访问数据,并将数据存储到我们定义的数组内部。那么后面定义了全局变量ADC_ConvertedValue,我们检测到的所有数据要存放到这个数组内部,可以看到,目前设置的ADC存放数据总共有四个,对应四个检测通道,可以根据自己的实际需求,去进行设计。具体数组的存放大小计算公式是:设置的检测通道*每个通道想要求平均的个数。比如四个通道,十个想要求平均的数据,则数组大小就设置为40,那么通过软件设置,数组[0]对应的就是第一个通道第一个数据,数组[1]对应的是第二个通道第一个数据,数组[4]对应的就是第一个通道第二个数据,依此类推。
在实际的ADC初始化中,调用ADC,DMA,GPIO三个InitTypeDef,这些都是实现定义好的,但是记得在FWlib库中调用dma和adc的官方例程库。前面初始化了DMA时钟,ADC1时钟,以及我们所定义的采样引脚,在这里定义的ADC采样引脚为PA1-PA4,可以自行修改。那么在GPIO口初始化了以后,就开始对DMA进行配置。
DMA配置过程中需要对几个参数进行注意,在这里重点说明一下:
DMA_PeripheralBaseAddr:可以理解为获取数据的地址,我们需要获取ADC的数据,则将ADC存放数据的地址放到此处。
DMA_MemoryBaseAddr:存放数据的地址,这里的地址单元由我们定义的数组决定,只需要将定义数组赋值过去即可。
DMA_BufferSize:缓冲区长度,取决于你的数组长度,有多少个数据就填多少
DMA_PeripheralDataSize:与下方内存的DataSize类似,都设置为了half word,那么half word其实等同于16位,2个byte,根据自己需求决定
其它的就正常配置就行,DMA配置完毕以后,就要对ADC进行设置。ADC设置的话是要与DMA相互配合,故初始化ADC的工作模式为独立工作,之前提到了ADC可以互相配合也可以单独工作。在只使用一个ADC的情况下,只需要设置为独立工作模式即可。需要注意的是,如果需要连续不断地采集ADC数据,就要设置ADC工作在扫描和连续转换模式中。用于转换的通道也可以进行设置,具体看通道的个数,用到了多少通道就设置参数为多少。通道配置中根据芯片本身的资源,可以从channel0-channel15(以STM32F103ZET6)为例,1,2,3,4等数代表的是转换的次序,主要是方便查看你的数据位置,避免出错。转换精度此处我们设置为239.5,这个得根据你自己的需求来,设置的精度越高转换时间越长,精度自然越好,反之亦然,这里折中设置。最后再对ADC进行一些使能即可。
adc.c
#include "adc.h"
#define ADC1_DR_Address ((u32)0x40012400+0x4c)
__IO uint16_t ADC_ConvertedValue[4];//ADC存放数据地址
void Init_adc(void)
{ ADC_InitTypeDef ADC_InitStructure; DMA_InitTypeDef DMA_InitStructure; GPIO_InitTypeDef GPIO_InitStructure; RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);//启动DMA时钟 RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);//启动ADC1时钟 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);//采样脚设置 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3 | GPIO_Pin_4; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; GPIO_Init(GPIOA, &GPIO_InitStructure); //DMA配置DMA_DeInit(DMA1_Channel1);//DMA1通道1配置 DMA_InitStructure.DMA_PeripheralBaseAddr = ADC1_DR_Address;//外设地址 DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)ADC_ConvertedValue;//内存地址 DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;//dma传输方向单向 DMA_InitStructure.DMA_BufferSize = 4;//设置DMA在传输时缓冲区的长度 DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;//设置DMA的外设递增模式,一个外设 DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;//设置DMA的内存递增模式 DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;//外设数据字长 DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; //内存数据字长 DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; //设置DMA的传输模式:连续不断的循环模式 DMA_InitStructure.DMA_Priority = DMA_Priority_High;//设置DMA的优先级别 DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;//设置DMA的2个memory中的变量互相访问 DMA_Init(DMA1_Channel1, &DMA_InitStructure); DMA_Cmd(DMA1_Channel1, ENABLE);//使能通道1 //ADC配置 ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;//独立工作模式 ADC_InitStructure.ADC_ScanConvMode = ENABLE;//扫描方式 ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;//连续转换 ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; //外部触发禁止 ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;//数据右对齐 ADC_InitStructure.ADC_NbrOfChannel = 4;//用于转换的通道数 ADC_Init(ADC1, &ADC_InitStructure); //规则模式通道配置 ADC_RegularChannelConfig(ADC1, ADC_Channel_1 , 1, ADC_SampleTime_239Cycles5); ADC_RegularChannelConfig(ADC1, ADC_Channel_2 , 2, ADC_SampleTime_239Cycles5); ADC_RegularChannelConfig(ADC1, ADC_Channel_3 , 3, ADC_SampleTime_239Cycles5); ADC_RegularChannelConfig(ADC1, ADC_Channel_4 , 4, ADC_SampleTime_239Cycles5); ADC_DMACmd(ADC1, ENABLE);//使能ADC1的DMA ADC_Cmd(ADC1, ENABLE);//使能ADC1 ADC_ResetCalibration(ADC1);//使能ADC1复位校准寄存器 while(ADC_GetResetCalibrationStatus(ADC1));//检查校准寄存器是否复位完毕 ADC_StartCalibration(ADC1);//开始校准 while(ADC_GetCalibrationStatus(ADC1));//检测是否校准完毕 ADC_SoftwareStartConvCmd(ADC1, ENABLE);//开启ADC1的软件转换
}
adc.h
#ifndef __ADC_H
#define __ADC_H#include "stm32f10x.h"void Init_adc(void);#endif /* __ADC_H */
需要调用参数只需要在定时器里面进行计数求平均即可,当初始化ADC以后,我们所定义的数组里面就会源源不断的出现数据,如前文提到的,第一个数据对应的就是第一个转换通道的,那么根据这个关系,就可以对采集到的数据进行平均化处理。
总结
此代码还有很多可以优化的地方,比如利用到交替采样。如果用到了F4的单片机,还可以利用F4的DSP库进行一些函数的计算,比如均方根算法,进行交流电压交流电流的采样。
基于STM32F103C8T6的高速DMA传输多通道ADC数据相关推荐
- 使用STM32 CUBE IDE配置STM32F7 用DMA传输多通道ADC数据
我的使用环境: 硬件:STM32F767ZGT6.串口1.ADC1.16MHz晶振.216MHz主频 软件:STM32 CUBE IDE 优点:不用定时触发采样,ADC数据是不停的实时更新,ADC数据 ...
- STM32F4基于DMA的多通道ADC采集——遇到的问题解决
这几天在尝试用DMA实现规则通道多通道的ADC采集,遇到了不少问题,在这记录一下我遇到的问题,一方面理顺一下思路,也希望后人少走弯路. 一开始按照开发板资料中的程序源码编写,但无论如何配置,也无法实现 ...
- STM32F407 DMA采集多通道ADC
STM32F407和STM32F103在HAL库使用的时候有较大的差别,同时407取消掉了ADC校准,在使用DMA进行多通道采集时需要打开DMA连续请求:hadc1.Init.DMAContinuou ...
- 立创梁山派GD32F450ZGT6--使用DMA实现多通道ADC采集
这次调试有些久,缺乏的知识很多,最重要的是ADC的引脚配置为浮空之后,如果没有接入东西,其读取的ADC值是不确定的,所以在测试的时候,一定要把对应的电压接入ADC引脚,测量的值才是准确的. 上代码. ...
- 【转载】基于Nios II的DMA传输总结(附源码)
转载:http://blog.ednchina.com/chactor/185802/message.aspx#92932 最近练了一段时间的DMA传输,现做如下的总结,分享自己获得心得以及遇到的一些 ...
- 第九章 AT32F403A基于V2库串口 dma接收不定长数据
目录 概述 硬件 DMA 软件 流程 初始化 初始化代码: 中断服务函数: DMA1通道5设置函数:(重新使能通道) DMA1通道4发送函数:(设置dma长度和内存地址) 测试 最后 概述 本文主要是 ...
- STM32Cubemx——ADC采集+DMA传输
文章目录 一.准备工具 二.前置知识 1.ADC简介 2.DMA简介 2.STM32Cubemx配置 1.新建工程 2.时钟源选择及时钟树配置 3.时基选择调试接口选择 4.配置ADC采集 1.选择要 ...
- stm32f429之多通道ADC通过DMA数据采集
stm32f429之多通道ADC通过DMA数据采集 原来的程序使用时stm32f103的芯片,现在给为stm32f429的芯片,查看一下几家开发板例程,发现没有使用adc+dma的,在网上也搜索了一下 ...
- [STM32F4]STM32F407 ADC采集+DMA传输
前言 有的项目中需要对多个通道的电压进行一定频率的AD采样. 第一种:是使用定时器去读取,通过检查转换完成标志位来读取,但这样就会加重整个系统的负担,占用CPU资源. 第二种:是采用定时 ...
最新文章
- linux内核SMP负载均衡浅析
- R语言splines包构建基于logistic回归的自然样条分析:南非心脏病数据集、非线性:基函数展开和样条分析、你简单分析的不重要特征,可能只是线性不显著、而非线性是显著的
- 神经网络在Keras中不work!博士小哥证明何恺明的初始化方法堪比“CNN还魂丹”...
- Maven(八)Eclipse创建Web项目(复杂方式)
- 用ABAP实现SM36的设置后台JOB
- kafka学习(二)kafka工作流程分析
- PAT_B_1011_Java(15分)
- 面向对象之迪米特法则
- 软件工程概论第二周 开课作业
- androidStudio使用卡顿
- Apache Shiro权限绕过漏洞 (CVE-2020-11989) 挖掘分析和复现
- Power Strings POJ - 2406,字符串hash
- 使用gcc编写c语言程序,利用GCC工具编译C语言程序
- mtk camera faq
- 22轴三菱Q系列程序案例点胶机,QJ71C24串口与位移传感器通信案例
- pgadminIII 的基本操作
- openerp环境的搭建
- 华3C交换机调试基本
- 德州学院大学计算机,德州学院 计算机系 李天志老师简介 联系方式 手机电话 邮箱...
- Pandas与SQL比较
热门文章
- python超市管理系统的设计与实现_超市管理系统毕业论文【参考】.doc
- Could not find artifact com.aliyun:aliyun-sdk-vod-upload报错解决
- 谷歌地球影像及地形高速下载器
- 基于MSP430智能小车的设计
- 利用matlab实现卷积实验报告,实验五 使用matlab实现卷积的运算
- 解读咸阳模式——中西部如何打造“智慧城市”?也许你该来咸阳看看
- dropdownlist控件设置默认值_关于DropDownList默认值的设定
- python计算机视觉-- 基于OpenCV的图像分割和图像融合系统
- mysql中多个表 master salve同步搭建过程
- 云计算 应用_云计算应用