文章目录

  • 前言
  • 一、软件设计思路
  • 二、代码
  • 总结

前言

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数据相关推荐

  1. 使用STM32 CUBE IDE配置STM32F7 用DMA传输多通道ADC数据

    我的使用环境: 硬件:STM32F767ZGT6.串口1.ADC1.16MHz晶振.216MHz主频 软件:STM32 CUBE IDE 优点:不用定时触发采样,ADC数据是不停的实时更新,ADC数据 ...

  2. STM32F4基于DMA的多通道ADC采集——遇到的问题解决

    这几天在尝试用DMA实现规则通道多通道的ADC采集,遇到了不少问题,在这记录一下我遇到的问题,一方面理顺一下思路,也希望后人少走弯路. 一开始按照开发板资料中的程序源码编写,但无论如何配置,也无法实现 ...

  3. STM32F407 DMA采集多通道ADC

    STM32F407和STM32F103在HAL库使用的时候有较大的差别,同时407取消掉了ADC校准,在使用DMA进行多通道采集时需要打开DMA连续请求:hadc1.Init.DMAContinuou ...

  4. 立创梁山派GD32F450ZGT6--使用DMA实现多通道ADC采集

    这次调试有些久,缺乏的知识很多,最重要的是ADC的引脚配置为浮空之后,如果没有接入东西,其读取的ADC值是不确定的,所以在测试的时候,一定要把对应的电压接入ADC引脚,测量的值才是准确的. 上代码. ...

  5. 【转载】基于Nios II的DMA传输总结(附源码)

    转载:http://blog.ednchina.com/chactor/185802/message.aspx#92932 最近练了一段时间的DMA传输,现做如下的总结,分享自己获得心得以及遇到的一些 ...

  6. 第九章 AT32F403A基于V2库串口 dma接收不定长数据

    目录 概述 硬件 DMA 软件 流程 初始化 初始化代码: 中断服务函数: DMA1通道5设置函数:(重新使能通道) DMA1通道4发送函数:(设置dma长度和内存地址) 测试 最后 概述 本文主要是 ...

  7. STM32Cubemx——ADC采集+DMA传输

    文章目录 一.准备工具 二.前置知识 1.ADC简介 2.DMA简介 2.STM32Cubemx配置 1.新建工程 2.时钟源选择及时钟树配置 3.时基选择调试接口选择 4.配置ADC采集 1.选择要 ...

  8. stm32f429之多通道ADC通过DMA数据采集

    stm32f429之多通道ADC通过DMA数据采集 原来的程序使用时stm32f103的芯片,现在给为stm32f429的芯片,查看一下几家开发板例程,发现没有使用adc+dma的,在网上也搜索了一下 ...

  9. [STM32F4]STM32F407 ADC采集+DMA传输

    前言        有的项目中需要对多个通道的电压进行一定频率的AD采样. 第一种:是使用定时器去读取,通过检查转换完成标志位来读取,但这样就会加重整个系统的负担,占用CPU资源. 第二种:是采用定时 ...

最新文章

  1. linux内核SMP负载均衡浅析
  2. R语言splines包构建基于logistic回归的自然样条分析:南非心脏病数据集、非线性:基函数展开和样条分析、你简单分析的不重要特征,可能只是线性不显著、而非线性是显著的
  3. 神经网络在Keras中不work!博士小哥证明何恺明的初始化方法堪比“CNN还魂丹”...
  4. Maven(八)Eclipse创建Web项目(复杂方式)
  5. 用ABAP实现SM36的设置后台JOB
  6. kafka学习(二)kafka工作流程分析
  7. PAT_B_1011_Java(15分)
  8. 面向对象之迪米特法则
  9. 软件工程概论第二周 开课作业
  10. androidStudio使用卡顿
  11. Apache Shiro权限绕过漏洞 (CVE-2020-11989) 挖掘分析和复现
  12. Power Strings POJ - 2406,字符串hash
  13. 使用gcc编写c语言程序,利用GCC工具编译C语言程序
  14. mtk camera faq
  15. 22轴三菱Q系列程序案例点胶机,QJ71C24串口与位移传感器通信案例
  16. pgadminIII 的基本操作
  17. openerp环境的搭建
  18. 华3C交换机调试基本
  19. 德州学院大学计算机,德州学院 计算机系 李天志老师简介 联系方式 手机电话 邮箱...
  20. Pandas与SQL比较

热门文章

  1. python超市管理系统的设计与实现_超市管理系统毕业论文【参考】.doc
  2. Could not find artifact com.aliyun:aliyun-sdk-vod-upload报错解决
  3. 谷歌地球影像及地形高速下载器
  4. 基于MSP430智能小车的设计
  5. 利用matlab实现卷积实验报告,实验五 使用matlab实现卷积的运算
  6. 解读咸阳模式——中西部如何打造“智慧城市”?也许你该来咸阳看看
  7. dropdownlist控件设置默认值_关于DropDownList默认值的设定
  8. python计算机视觉-- 基于OpenCV的图像分割和图像融合系统
  9. mysql中多个表 master salve同步搭建过程
  10. 云计算 应用_云计算应用