1.7 ADC模数转换测电平(普通和DMA模式)

  嵌入式系统在微控制领域(温度,湿度,压力检测,四轴飞行器)中占据着重要地位,这些功能的实现是由微处理器cpu(如stm32)和传感器以及控制器共同完成的,而连接他们,使它们能够互相正常交流的正是本小节要讲诉的模块,ADC模数转换外设。下面从最简单的实验说起,逐渐深入了解这个神奇的外设。

本次ADC模数转换设计实现并不复杂,步骤可简化为以下三步:

  1. 接收板上电位器的输入电压

2. 经过A/D转换获得数字量,并传送给cpu

3. 通过串口在PC机上输出。

解析上面三个步骤,分析要求,就会发现ADC、GPIO、USART以及RCC模块就是本次实验所需要的用到的外设,因为除ADC模块,其它外设前面已经学习和实践了,那么理解和学习ADC模块,就可开始程序的设计实现了。

  根据stm32f系列微控制器手册ADC章节

   

ADC转换的后数字量为12位(分辨率),在参考开发板用户手册和原理图,可知电位器的端口为PC0,输入电压范围0~3.3V,可知精度为3.3/(2^12)V.

查询stm32f107的引脚定义分配,可知PC0对应ADC12_IN10,也就是说采集电位器电压用ADC1和ADC2都可以,但必须采用通道10。

目前来说,用库函数操作可以避免出现漏错,因此我还是推荐使用库函数配置寄存器,但是了解库函数的含义还是十分有必要的:

typedef struct
{
  u32  ADC_Mode;                            //明确ADC1和ADC2的工作方式,独立或其它组合

  FunctionalState  ADC_ScanConvMode;      //通道工作方式,单通道还是多通道(扫描)

  FunctionalState  ADC_ContinuousConvMode;  //工作在连续还是单次模式(ADC转换工作在连续模式

  u32 ADC_ExternalTrigConv;              //A/D转换启动规则

  u32  ADC_DataAlign;                      //判断转换数据的对齐方式

  u8  ADC_NbrOfChannel;                    //明确规则转换通道的具体数目1~16

}ADC_InitTypeDef

了解上述结构体代表含义,下面就可以初始化相关寄存器实现ADC外设的配置:

GPIO_InitTypeDef GPIO_InitStructure;
ADC_InitTypeDef ADC_InitStructure;
ADC_DeInit(ADC1); 

//ADC模块外设时钟需在APB2时钟基础上设置,决定单个周期的时钟长度(因为ADC时钟不能大于14MHZ,注意)RCC_ADCCLKConfig(RCC_PCLK2_Div4);    //使能ADC对应GPIO口,外设区域及复用功能时钟
RCC_APB2PeriphClockCmd(RCC_ADC1, ENABLE);

//初始化ADC模块对应GPIO
GPIO_InitStructure.GPIO_Pin = GPIO_ADC1_Pin;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
GPIO_Init(GPIO_ADC1, &GPIO_InitStructure);

ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;                                //ADC1和ADC2工作在独立模式
ADC_InitStructure.ADC_ScanConvMode = ENABLE;                                      //工作在扫描模式ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;                                //转换工作在连续模式ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; //转换由软件触发,启动需调用ADC_Cmd程序
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;                            //ADC数据右对齐
ADC_InitStructure.ADC_NbrOfChannel = 1;                                           //ADC通道数目为1
ADC_Init(ADC1, &ADC_InitStructure);

//指定ADC转换的通道和转换周期
ADC_RegularChannelConfig(ADC1, ADC_Channel_10, 1, ADC_SampleTime_55Cycles5);
#ifdef USE_ADC1_DMA_PER
    ADC_DMACmd(ADC1, ENABLE);                 //ADC1 DMA请求使能
#endif

ADC_Cmd(ADC1, ENABLE);                       //ADC1使能
ADC_ResetCalibration(ADC1);                  //重置ADC1校准寄存器
while (ADC_GetCalibrationStatus(ADC1))       //等待ADC1校准寄存器重置完成
{
}
ADC_StartCalibration(ADC1);                  //ADC1进入校准状态
while(ADC_GetCalibrationStatus(ADC1))        //等待ADC1校准完成
{
}

ADC_SoftwareStartConvCmd(ADC1, ENABLE);      //ADC1软件触发方式启动

这里有一个重要知识点:ADC通道的规则组和注入组

在AD转换中,规则组定义的是ADC扫描通道的顺序,按照规则组配置时的采样顺序从小到大依次扫描ADC通道,而注入组的优先级高于规则组,当注入组转换触发时就打断规则组的扫描而执行注入组的通道扫描,具体流程类似于中断中的抢占。本次ADC的转换仅仅使用到一个端口,这些不用考虑,但是在多通道AD/DA采集时,规则组和注入组要根据实际情况进行配置。

注意:配置通道的规则组和注入组是一定要在使能ADC转换之前的。

完成了初始化后,剩下的就简单了,只要获得ADC处理后的数字量,在转换成整形变量,就可以通过串口发送接收了,如下:

//直接获得当前ADC转换后的值,转换并输出,CPU参与传送
ADValue = ADC_GetConversionValue(ADC1);
Precent = (ADValue*100/0x1000);
Voltage = Precent*33;
printf("\r\n\n ADCConvertedValue is 0x%x, Percent is %d%%, voltage is %d.%d%dV",
      ADValue,Precent,Voltage/1000,(Voltage%1000)/100,(Voltage%100)/10);
printf("\r\n ADC output");

ARM_DELAY(2000000);

注意:使用了printf函数作为输入输出时,包含头文件#include ”stdio.h” Target下要选择use MicroLib,否则是不会有输出的(串口章节已经说明,重要)

如此便实现了电位记电压的采集和输出,不过这并不是结束,因为今天我们还要学习另一个同样用途广泛的外设-DMA模块。

首先我们要知道DMA是干什么的?DMA模块的主要作用是将内存或者外设中的数据自由移动,而不需要cpu的参与,同时通过存储指针的自偏移,实现大量数据的顺序存储(这一点在通讯领域具有重要意义)。和上面一样,学习DMA,肯定首先查询手册了:

从这上面我们可以得出,ADC1对应的传输通道为通道1,因为ADC是工作模式,在了解下面的结构体后:

typedef struct
{
  u32 DMA_PeripheralBaseAddr;     //定义的外设基地址
  u32 DMA_MemoryBaseAddr;         //定义的内存基地址
  u32 DMA_DIR;                    //外设作为数据传输的来源还是目的地
  u32 DMA_BufferSize;             //DMA通道的 DMA缓存的大小,单位为数据单位
  u32 DMA_PeripheralInc;          //外设地址寄存器递增或不变
  u32 DMA_MemoryInc;              //内存地址寄存器递增或不变
  u32 DMA_PeripheralDataSize;     //外设数据宽度
  u32 DMA_MemoryDataSize;         //内存数据宽度
  u32 DMA_Mode;                   //DMA缓存工作方式
  u32 DMA_Priority;               //DMA工作优先级
  u32 DMA_M2M;                    //DMA工作是内存到内存,还是外设到内存
} DMA_InitTypeDef;

我们可以得出以下结论:

定义uint16_t  ADCConvertedValue; //接收内存地址

1.外设基地址为ADC1_DR_Address或者(uint32_t)&(ADC1->DR)

2.数据来源于ADC外设,传送地址为内存

3.工作在循环模式,且都不自增

按照上面的结构体依此配置DMA_InitStructrue的各项参数,初始化如下:

DMA_InitTypeDef DMA_InitStructure;

RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
DMA_DeInit(DMA1_Channel1);                                                  //复位ADC1对应DMA通道DMA1_Channel1

DMA_InitStructure.DMA_PeripheralBaseAddr =(uint32_t)&(ADC1->DR);            //ADC1规则组转换值寄存器地址作为基地址
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)&ADCConvertedValue;        //数据传输至内存的基地址
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;                          //外设作为数据来源地
DMA_InitStructure.DMA_BufferSize = 1;                                       //可增加地址的的长度
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;            //外设地址不允许自增
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Disable;                    //内存地址不允许自增
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; //外设数据为半字16bit
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;         //内存数据为半字16bit
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;                             //DMA工作在循环模式
DMA_InitStructure.DMA_Priority = DMA_Priority_High;                         //DMA请求优先级高
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;                                //DMA是外设到内存传递
DMA_Init(DMA1_Channel1, &DMA_InitStructure);                                  

DMA_Cmd(DMA1_Channel1, ENABLE);                                             /*DMA使能*/

同时在main函数中添加:

//将DMA从ADC处传送的数字量经过处理,转换并输出,DMA控制器用于传送
ADCConvertedValueLocal = ADCConvertedValue;
Precent = (ADCConvertedValueLocal*100/0x1000);
Voltage = Precent*33;
printf("\r\n\n ADCConvertedValue is 0x%x, Percent is %d%%, voltage is %d.%d%dV",
       ADCConvertedValueLocal,Precent,Voltage/1000,(Voltage%1000)/100,(Voltage%100)/10);
printf("\r\n ADC DMA output");

如此便实现了通过ADC通过DMA的传输。

代码下载:http://files.cnblogs.com/files/zc110747/7.ADC-DMA.7z

以下来自外部资料及个人总结,希望对理解DMA模块有用处:

1.DMA传输将数据从一个地址空间复制到另外一个地址空间,这部分是由DMA控制器实现的,不需要依靠CPU的大量的数据采集传送,节省cpu资源。

2.DMA工作包含四个过程

DMA请求-〉DMA响应-〉DMA传输-〉DMA结束

3.DMA传送方式有以下三种

(1)停止CPU访内存;

当外围器件有一批数据需要传送时,DMA给CPU发送停止信号,CPU停止访问内存,释放相关总线控制权,DMA获得总线控制权后开始传递数据,完成后将总线控制权交给CPU。一次DMA传送结束。

优点:控制简单,用于速率很高的组传送

缺点:内存的效能没有发挥,一部分时间内存处于空闲状态。这是因为DMA传送阶段有很多时间是在读取外设的数据,总线一段时间肯定是空闲的,而这部分时间足够CPU进行内存的访问。

(2)周期挪用;(ADC转换采用的正是这种方式)

当I/O设备没有DMA请求时,CPU按程序要求访问内存;一旦I/O设备有DMA请求,则由I/O设备挪用一个或几个内存周期。

(3)DMA与CPU交替访内存.

时间: 2024-08-29 10:33:36

1.7 ADC模数转换测电平(普通和DMA模式)的相关文章

Pyboard基本功能---ADC模数转换/DAC数模转换

ADC模数转换 1.获取ADC类里面的方法 >>> help(pyb.ADC) object <class 'ADC'> is of type type read -- <function> read_timed -- <function> read_timed_multi -- <staticmethod> >>> ADC (模拟信号转换为数字量)是嵌入式中最常用的功能之一,在MicroPython 同样也提供了相应的函

stm32F103之ADC模数转换

一.ADC简介 通常是指一个将模拟信号转变为数字信号的电子元件.通常的模数转换器是把经过与标准量比较处理后的模拟量转换成以二进制数值表示的离散信号的转换器.  12位ADC是一种逐次逼近型模拟数字转换器.它有多达18个通道,可测量16个外部和2个内部信号源.各通道的A/D转换可以单次.连续.扫描或间断模式执行.ADC的结果可以左对齐或右对齐方式存储在16位数据寄存器中. 模拟看门狗特性允许应用程序检测输入电压是否超出用户定义的高/低阀值. 二.ADC功能框图 掌握了ADC 的功能框图,就可以对A

【STM32H7教程】第45章 STM32H7的ADC应用之定时器触发配合DMA双缓冲

完整教程下载地址:http://www.armbbs.cn/forum.php?mod=viewthread&tid=86980 第45章       STM32H7的ADC应用之定时器触发配合DMA双缓冲 本章教程为大家讲解定时器触发配合DMA双缓冲做ADC数据采集,实际项目中有一定的使用价值,一个缓冲接收数据的时候,另一个缓冲可以做数据处理. 45.1 初学者重要提示 45.2 ADC稳压基准硬件设计 45.3 ADC驱动设计 45.4 ADC板级支持包(bsp_adc.c) 45.5 AD

adc mda 的一些配置,,,非常感谢分享这些内容的人

1.  对于ADC来说,我们关注的是它的分辨率.转换速度.ADC类型.参考电压范围. A. 分辨率,12位分辨率,最小量化单位LSB=VREF+/212 B. 转换时间,可编程的,采样一次至少要用14个ADC时钟周期,而ADC时钟频率最高为14MHz,也就是说它的最短采样时间为1us C. ADC类型,类型决定了性能的极限,stm32是逐次比较型ADC D. 参考电压范围,当需要测量负电压或测量的信号超出范围时,要先经过运算电路进行平移或利用电阻分压 2.  ADC工作过程分析,ADC部件要受到

STM32——ADC

STM32--ADC 宗旨:技术的学习是有限的,分享的精神的无限的. 一.ADC指标 有 18 个通道,可测量 16 个外部和 2 个内部信号源.各通道的 A/D 转换可以单次.连续.扫描或间断模式执行 :ADC的结果可以左对齐或右对齐方式存储在 16 位数据寄存器中 :模拟看门狗特性允许应用程序检测输入电压是否超出用户定义的高 / 低阈值. 对于 ADC 来说,我们最关注的就是它的分辨率.转换时间.ADC 类型.参考电压范围: (1)分辨率:12 位分辨率.不能直接测量负电压,所以没有符号位,

STM32学习笔记1(ADC多通道采样)

STM32 ADC多通道转换描述:用ADC连续采集11路模拟信号,并由DMA传输到内存.ADC配置为扫描并且连续转换模式,ADC的时钟配置为12MHZ.在每次转换结束后,由DMA循环将转换的数据传输到内存中.ADC可以连续采集N次求平均值.最后通过串口传输出最后转换的结果.程序如下:#i nclude "stm32f10x.h" //这个头文件包括STM32F10x所有外围寄存器.位.内存映射的定义#i nclude "eval.h" //头文件(包括串口.按键.L

TPYBoard开发板ADC数模转换一: 初识ADC使用

转载请以链接形式注明文章来源,公众号:MicroPython玩家汇 1.前言 ADC,Analog-to-DigitalConverter的缩写,指模/数转换器或者模数转换器[1].是指将连续变化的模拟信号转换为离散的数字信号的器件.真实世界的模拟信号,例如温度.压力.声音或者图像等,需要转换成更容易储存.处理和发射的数字形式. 与之相对应的DAC,Digital-to-AnalogConverter,它是ADC模数转换的逆向过程. ADC在单片机开发过程中使用广泛,多样该文为ADC系列文章第一

ADC触摸屏

目录 ADC触摸屏 硬件原理 等效电路 测量逻辑 程序设计(一)获得ADC 寄存器初始化 中断初始化 ADC模式(中断.测量) 中断函数 程序设计(二)获得坐标 生产者与消费者 ADC获取 程序优化 个人修改意见 TODO title: ADC触摸屏 tags: ARM date: 2018-11-02 18:35:45 --- ADC触摸屏 硬件原理 s3c2440有8通道的ADC,一次同时只能查询一个通道.分为A0~A7.这里的P(positive)表示的是正的意思 ADC通道 A4 TSY

按键板的原理与实现----ADC

在嵌入式系统产品开发中,按键板的设计是最基本的,也是项目评估阶段必须要考虑的问题.其实现方式又很多种,具体使用那一种就需要结合特定IC的可用IO数量,并综合考虑成本,做出最终选择.本系列文章将介绍多种不同按键板的原理与实现. 使用ADC实现按键板     这是最简单的实现方式,它需要系统IC提供一个内部ADC.如果IC不能提供出额外的ADC的话,从成本等因素考虑,去外加一个ADC是不明智的选择,可考虑的替代方案将在后续文章中讨论. 1:硬件原理 按键其实就是一个开关电路,按下为导通,松开为断开.