ADC

ADC (Analog to Digital Converter):模数转换器,它负责将模拟信号转化为数字信号。


1.概述

对于我们的STM32F103来说,它拥有3个ADC器件,其中每个ADC都是12位的精度。每个ADC器件都拥有18个通道,分别为16个外部通道和2个内部通道,这里说的通道就是ADC采集的信号源头。需要注意的是,尽管我们每个ADC都拥有16个外部通道,但是并不是我们STM32F103的ADC就能够采集48个外部通道的信息,因为这三个ADC共用了21个外部通道,这意味着什么呢?意味着同一信号,我们可以使用这三个ADC并行采集它,当然了这是后话。ADC采集得到的结果存储在ADC_DR这个寄存器里面,注意这个寄存器如果使用DMA搬运数据的话,那么这个寄存器的地址就是源头。关于采集数据需要注意的几点:1.位数:因为这里的ADC是32位的,所以说采集结果是12位的数据,但是我们规定将这12位的数据存储到寄存器的16位之中;2.存储方式:左对齐还是右对齐的问题,由于我们的机器是32位的,所以寄存器单元也就是32位,那么这16位数据是存储在高16位呢还是低16位呢?答案就是由开发人员配置。可高可低。

ADC的时钟是经过PCLK2分频产生的,这说明了什么,说明ADC是APB2的外设。需要注意的是,对于我们的STM32F103来说,规定最高时钟的频率不得超过14mhz。说到时钟问题,我们知道对于我们的STM32F103来说,它的时钟频率默认是72mhz的,而对于我们的高速外设APB2桥来说,它的时钟信号是PCLK2,而PCLK2默认就是SYSCLK系统时钟也就是72mhz。但是前面也说了我们的adc器件所支持的最高时钟频率也就是14mhz,因此需要分频了。而关于分频那也是后话,详见后文。

分辨率:12位的分辨率,不能直接测量负电压。最小量化单元LSB=VREF+ / 4096

转换时间:由于ADC的时钟频率是可配置的,所以说采样时间也是可以修改的。规定采样一次至少需要14个时钟周期,而ADC的时钟频率最高又为14mhz。所以说采样时间最小为:14 x 1 / 14 us = 1us。


2.工作流程分析

ADCX_IN0~ADCX_IN15是ADC器件的外部输入通道,即连接到了某些GPIO引脚。ADC器件要受到触发信号才会开始转换,比如说EXTI外部中断触发,定时器触发,或者是软件触发。当ADC器件受到触发信号之后,就会在ADCCLK时钟的驱动下对输入通道的信号进行采样,并且进行模数转换。

模数转换之后得到的结果存储在ADC_DR外设寄存器之中,我们可以通过CPU指令或者DMA将这个数据读取到内存里面。对于DMA来说,也就是模数转换之后,可以触发DMA请求。


3.ADC_InitTypeDef结构体介绍

部分复用功能-参阅STM32数据手册
typedef struct{
  uint32_t ADC_Mode;
  uint32_t ADC_DataAlign;
  uint8_t ADC_NbrOfChannel;
  uint32_t ADC_ExternalTrigConv;
  FunctionalState ADC_ScanConvMode;
  FunctionalState ADC_ContinuousConvMode;
} ADC_InitTypeDef

下面介绍一下各个成员的作用:

1.ADC_Mode:设置ADC的工作模式,我们知道STM32有三个ADC器件,这三个器件又共用21个通道,因此难免出现这种情况:多个ADC采集同一个输入通道的情况,那么问题来了该如何协调他们之间的工作方式呢?答案就是使用ADC_Mode设置模式。


2.ADC_DataAlign:设置数据对齐方式。我们知道ADC精度是12位,规定作16位存储,所以对于我们的32位机器来说,这采集得到的数据被存储在ADC_DR寄存器的高16位或者低16位(取决于是规则组还是注入组)。问题是我们的数据只有12位,所以这就带来了一个问题,这12位数据是左对齐还是右对齐。在STM32中,我们可以选择是左对齐还是右对齐。所谓右对齐(不论是规则组还是注入组),DATA0对应存储器的最低地址在这里就是DR0或者DR16,剩余的位注入组填SEXT,规则组填0。而对应左对齐那就稍许复杂,规则组好说就是DATA11对应就是DR15,剩余位填0;注入组是DATA11对应DR30,DR31填的是SEXT,剩余位填0。


3.ADC_NbrOfChannel:设置要采集多少个通道,我们知道我们STM32的ADC可以采集16个外部通道以及2个内部通道。这里成员的最大值并不是18个,而是16个。


4.ADC_ExternalTrigConv:设置是否使用外部中断触发信号。我们知道ADC当受到触发信号的时候才会开始工作,其中触发信号可以是外部中断或者是软件控制触发。


5.ADC_ScanConvMode:当我们希望使用某个ADC器件对多个通道进行数据采集的时候,我们就需要把这个ADC器件配置为按一定的顺序来对这多个通道进行扫描转换,即轮流采集各个通道的值。也就是说,如果是采集多个通道的话,那么必须开启这个模式,后面接着利用其它函数进行采集顺序的配置。如果只是采集一个通道的话,那么就不需要开启这个模式了,值设置为DISABLE即可。


6.ADC_ContinuousConvMode:是否开启连续转换模式。连续转换模式意味着:当上一次 ADC转换完成后,立即开启下一次转换。

参阅STM32库件库使用手册,我们可以明白各个成员可取的值以及各个值所代表的意义:

1.ADC_Mode

ADC_Mode可取的值

2.ADC_DataAlign

意义
ADC_DataAlign_Right 数据右对齐
ADC_DataAlign_Left 数据左对齐

3.ADC_NbrOfChannel:[1,16]


4.ADC_ExternalTrigConv

ADC_ExternalTrigConv成员可取的值

5.ADC_ScanConvMode:规定了ADC是工作在扫描模式(多通道)还是单通道模式,即分别对应ENABLE和DISABLE。


6.ADC_ContinuousConvMode:规定了是循环采集还是只采集一次。分别对应ENABE和DISABLE。

4.库函数使用方式

时钟树-STM32中文数据手册

是这样的,并不是说将ADC_InitTypeDef对象填充完毕了接着调用ADC_Init(ADCX,&ADC_InitStructure)然后再调用ADC_Cmd(ADCX,ENABLE),要希望ADC以正确的方式工作的话那么还得做额外的一些工作。分别是下面这些工作:

  • 1.设置好ADC的时钟信号频率,时钟信号频率越高则采样时间越小。通过前面的学习我们知道ADC的一次工作流程至少要14个周期,ADC的时钟信号的最高频率是14mhz。所以说ADC采样时间最少也就是1s了。这里提到了ADC的时钟信号频率的问题,那么问题来了如何配置呢?
    答案就是利用RCC_ADCCLKConfig()。这个函数所接受的参数就是分频因子,从上图我们可以看出ADC的时钟来源是APB2外设时钟,所接受的分频因子有2,4,6,8。对应的参数值分别是RCC_PCLK2_Div2,......,RCC_PCLK2_Div8。很显然,72除上面的这些分频因子是得不到最高频率14mhz的。那么问题来了要如何得到呢?答案就是将APB2的时钟配置为56mhz,接着ADC再4分频。那么问题来了如何将APB2的时钟配置为56mhz呢?很简单,修改system_stm32f10x.c文件的如下宏定义即可:
#if defined (STM32F10X_LD_VL) || (defined STM32F10X_MD_VL) || (defined STM32F10X_HD_VL)
/* #define SYSCLK_FREQ_HSE    HSE_VALUE */
 #define SYSCLK_FREQ_24MHz  24000000
#else
/* #define SYSCLK_FREQ_HSE    HSE_VALUE */
/* #define SYSCLK_FREQ_24MHz  24000000 */ 
/* #define SYSCLK_FREQ_36MHz  36000000 */
/* #define SYSCLK_FREQ_48MHz  48000000 */
#define SYSCLK_FREQ_56MHz  56000000 
//#define SYSCLK_FREQ_72MHz  72000000
#endif
  • 2.配置好了ADC的时钟信号频率后,我们可以接着着手第二步工作:配置工作通道,我们知道ADC器件有16个外部通道,2个内部通道。那么究竟该让ADC工作与哪个通道呢?所以我们需要使用ADC_RegularChannelConfig()函数来完成具体通道的配置工作。下面我们来看看ADC_RegularChannelConfig()函数的签名:
void ADC_RegularChannelConfig(ADC_TypeDef *ADCX,
      uint8_t ADC_Channel_X,
      uint8_t Rank,
      uint8_t ADC_SampleTime
)

下面解释一下函数的具体参数意义:
ADC_ChannelX,其中X属于[0,17]。因为ADC器件有16个外部通道,2个内部通道嘛,至于到底是哪个通道得看端口复用情况。
Rank属于[1,16],我们再前面提到了一个ADC_InitTypeDef结构体成员:ADC_ScanConvMode,这个成员可以开启扫描模式即多通道模式,那么问题来了如何协调这多个通道之间的采集顺序呢?答案就是这里的Rank了,前面我们也提到过只有16个通道可能并行被采集。所以这里的Rank的值就是属于[1,16]。Rank即排名,所以值越小那么越先被ADC采集。
ADC_SampleTime:配置本通道的采样周期。通过前面我们了解到了通道的采样周期最小为14个周期,那么是不是这里的最小值也为14呢?不是这样的。看采样周期数的计算公式:
采样周期=ADC_SampleTime + 12.5
所以说ADC_SampleTime的最小值是1.5,下面把这个参数所有可选值给列举出来:1.5,7.5,13.5,28.5,41.5,55.5,71.5,239.5。用如下形式的值表示:
ADC_SampleTime_xCycles5,其中x就是上面列举出来的整数部分。

  • 3.是不是经过RCC_ADCCLKConfig(RCC_PCLK2_Divx);和ADC_RegularChannelConfig(ADCX,ADC_ChannelX,Rank,ADC_SampleTime_xCycles5);这两个函数就ok了呢?答案是不是这样的。。。还需要开启DMA搬运许可ADC_DMACmd(ADCX, ENABLE);接着在使能ADC器件ADC_Cmd(ADCX, ENABLE);接着我们可以加入可选的ADC自检验代码,以使得转换结果更为的精确,这部分代码如下:
ADC_ResetCalibration(ADC1);
while(ADC_GetResetCalibrationStatus(ADC1));
ADC_StartCalibration(ADC1);
while(ADC_GetCalibrationStatus(ADC1));

到了这一步ADC的配置工作就基本完成了,我们只需要产生触发信号让ADC工作了,比如说产生外部中断或者软件中断,如果是利用软件中断来驱使ADC器件工作的话,那么就使用ADC_SoftwareStartConvCmd(ADCX, ENABLE)函数。

到了这个时候就真正OK了。

所以整个代码流程大致就是这样的:

void ADC_Config(void)
{
  ADC_InitTypeDef ADC_InitStructure;
  GPIO_InitTypeDef GPIO_InitStructure;
  //开启ADC时钟以及复用功能是ADC通道的那个GPIO的时钟,ADC都是APB2外设
  RCC_APB2PeriphClockCmd(APB2Periph_ADCX | APB2Periph_GPIOX, ENABLE);
  //配置GPIO作为ADC通道,由于是默认的复用功能所以无需开启AFIO时钟
  //配置GPIO为输入模式,注意一定得是GPIO_Mode_AIN模拟输入
  //配置好了GPIO_Init即可。
  
  //配置ADC,第一步是填充结构体
  ADC_InitStructure.ADC_Mode = ;
  ADC_InitStructure.ADC_DataAlign = ;
  ADC_InitStructure.ADC_NbrOfChannel = ;
  ADC_InitStructure.ADC_ExternalTrigConv = ;
  ADC_InitStructure.ADC_ScanConvMode = ;
  ADC_InitStructure.ADC_ContinuousConvMode = ;
  ADC_Init(ADCX, &ADC_InitStructure);
  RCC_ADCCLKConfig(RCC_PCLK2_DivX);
  ADC_RegularChannelConfig(ADCX,ADC_Channel_X,Rank,ADC_SampleTime_xCyces5);
  ADC_DMACmd(ADCX, ENABLE);
  ADC_Cmd(ADCX, EANBLE);
  //ADC自校验
  ADC_ResetCalibration(ADC1);
  while(ADC_GetResetCalibrationStatus(ADC1));
  ADC_StartCalibration(ADC1);
  while(ADC_GetCalibrationStatus(ADC1));
  //产生触发信号让ADC开始工作
  ADC_SoftwareStartConvCmd(ADCX, ENABLE);
}

END

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,911评论 5 460
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 82,014评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 142,129评论 0 320
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,283评论 1 264
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,159评论 4 357
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,161评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,565评论 3 382
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,251评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,531评论 1 292
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,619评论 2 310
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,383评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,255评论 3 313
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,624评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,916评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,199评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,553评论 2 342
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,756评论 2 335

推荐阅读更多精彩内容

  • ADC12功能模块 参考电压发生器 ADC需要一个基准信号,ADC的数字输出表示模拟输入相对于它的基准的比率。MS...
    nino天阅读 1,695评论 0 1
  • LED数码管或者LCD12864等显示器在显示温度采样值时,需要的是稳定的能反映温度实际变化的显示效果。ADC采样...
    Ben2Feng阅读 4,399评论 1 3
  • 姓名:丁英琦 学号:17101223408 转载自:http://mp.weixin.qq.com/s/H8K3D...
    dyq0618阅读 2,117评论 0 0
  • SPI通信实验 SPI简介 串行外设接口(Serial Peripheral Interface Bus,SPI)...
    btskyrmb阅读 9,289评论 1 12
  • 关于ADC模块,这是k60开发板中的十分重要的部分,也是十分复杂的一个部分。其实在这个模块,或者说是各个模块中,我...
    Cheer_up阅读 1,347评论 0 0