抱歉,您的浏览器无法访问本站
本页面需要浏览器支持(启用)JavaScript
了解详情 >

ADC相关介绍

基本原理:采样、量化、编码

性能参数:

  • 量程: 允许输入模拟电压的范围
  • 分辨率:所能检测到最小的模拟输入量
  • 精度:对于ADC的数字输出,实际需要的模拟输入值与理论上需要的模拟输入值之差(比如模拟输入值为1.95,假设转为数字量【量化】后为2,理论上需要模拟输入值为2,所以误差是0.05)
  • 转换时间:ADC完成一次A/D转换所需要的时间,包括从启动开始到获得相应数据所需要的总时间(转换时间=采样时间+量化和编码时间)

ADC主要类型:

  • 逐次逼近型
  • 电压时间转换型(V-T):模拟电压信号转为与之成正比的时间宽度信号,然后在这个时间宽度内对固定频率的时钟脉冲计数,计数结果就是转化后的输出的数字信号
  • 电压频率转换型(V-F):模拟电压信号转为与之成正比的频率信号,然后在固定的时间间隔内对得到的频率信号计数,计数结果即输出的数字量

ADC工作原理

ADC特性

stm32f103微控制器内部集成1~3个12位逐次逼近型ADC,主要特性如下:

  1. 每个ADC最多有18路模拟输入通道,可测量16个外部信号(ADCx_IN0~ADCx_IN15),2个内部信号
  2. 18路通道可分为规则通道组(最多包含16路)和注入通道组(最多包含4路),仅有规则通道组可以产生DMA请求
  3. 供电要求:2.4V~3.6V
  4. 模拟输入信号Vin要求:Vref- <= Vin <= Vref+(Vref-, Vref+分别是负极和正极的参考电压)
  5. 工作模式:
    • 单次(单次转换模式下,ADC只执行一次转换)
    • 连续(连续转换模式中,当前面ADC转换一结束马上就启动另一次转换)
    • 扫描(扫描多路通道)
    • 间断
  6. 转换结束后,以左对齐或者右对齐方式存入16位数据寄存器,同时产生中断请求(ADC1、ADC3还可以产生DMA请求)
  7. 系统时钟为56MHz时,ADC时钟为14MHz,采样时间为1.5个ADC时钟周期,ADC获得最短转换时间为1us
内部结构

image-20211005200614756

image-20211005202040923

image-20211005202524900

ADC通道及分组

输入通道

ADC的信号输入就是通过通道来实现的,信号通过通道输入到单片机中,单片机经过转换后,将模拟信号输出为数字信号。STM32中的ADC有着18个通道,其中外部的16个通道已经在框图中标出,如下:

image-20211005213529577

这16个通道对应着不同的IO口,此外ADC1/2/3 还有内部通道:

ADC1 的通道 16 连接到了芯片内部的温度传感器, Vrefint 连接到了通道 17。

ADC2 的模拟通道 16 和 17 连接到了内部的 VSS。

img

外部的16个通道在转换时又分为规则通道和注入通道,其中规则通道最多有16路,注入通道最多有4路(注入通道貌似使用不多),下面简单介绍一下俩种通道:

规则通道

规则通道顾名思义就是,最平常的通道、也是最常用的通道,通常的ADC转换都是用规则通道实现的。

注入通道

注入通道是相对于规则通道的,注入通道可以在规则通道转换时,强行插入转换,相当于一个“中断通道”。当有注入通道需要转换时,规则通道的转换会停止,优先执行注入通道的转换,当注入通道的转换执行完毕后,再回到之前规则通道进行转换。

转换顺序

知道了ADC的转换通道后,如果ADC只使用一个通道来转换,那就很简单,但如果是使用多个通道进行转换就涉及到一个先后顺序了,毕竟规则转换通道只有一个数据寄存器。多个通道的使用顺序分为俩种情况:规则通道的转换顺序和注入通道的转换顺序。

规则通道转换顺序

规则通道中的转换顺序由三个寄存器控制:SQR1、SQR2、SQR3,它们都是32位寄存器。SQR寄存器控制着转换通道的数目和转换顺序,只要在对应的寄存器位SQx中写入相应的通道,这个通道就是第x个转换。具体的对应关系如下:

通过SQR1寄存器就能了解其转换顺序在寄存器上的实现

image-20211005214343170

注入通道转换顺序

和规则通道转换顺序的控制一样,注入通道的转换也是通过注入寄存器来控制,只不过只有一个JSQR寄存器来控制,控制关系如下:

在这里插入图片描述

需要注意的是,只有当JL=4的时候,注入通道的转换顺序才会按照JSQ1、JSQ2、JSQ3、JSQ4的顺序执行。

当JL<4时,注入通道的转换顺序恰恰相反,也就是执行顺序为:JSQ4、JSQ3、JSQ2、JSQ1。

触发源

ADC转换的输入、通道、转换顺序都已经说明了,但ADC转换是怎么触发的呢?就像通信协议一样,都要规定一个起始信号才能传输信息,ADC也需要一个触发信号来实行模/数转换。

  1. 通过直接配置寄存器触发,通过配置控制寄存器CR2的ADON位,写1时开始转换,写0时停止转换。在程序运行过程中只要调用库函数,将CR2寄存器的ADON位置1就可以进行转换,比较好理解。

  2. 还可以通过内部定时器或者外部IO触发转换,也就是说可以利用内部时钟让ADC进行周期性的转换,也可以利用外部IO使ADC在需要时转换,具体的触发由控制寄存器CR2决定。
    ADC_CR2寄存器的详情如下:

    展开

    image-20211005215100030

    image-20211005215206185

    image-20211005215220210

转换时间

ADC的每一次信号转换都要时间,这个时间就是转换时间,转换时间由输入时钟和采样周期来决定。

输入时钟

由于ADC在STM32中是挂载在APB2总线上的,所以ADC得时钟是由PCLK2(72MHz)经过分频得到的,分频因子由 RCC 时钟配置寄存器RCC_CFGR 的位 15:14 ADCPRE[1:0]设置,可以是 2/4/6/8 分频,一般配置分频因子为8,即8分频得到ADC的输入时钟频率为9MHz。

采样周期

采样周期是确立在输入时钟上的,配置采样周期可以确定使用多少个ADC时钟周期来对电压进行采样,采样的周期数可通过 ADC采样时间寄存器 ADC_SMPR1 和 ADC_SMPR2 中的 SMP[2:0]位设置,ADC_SMPR2 控制的是通道 0~9, ADC_SMPR1 控制的是通道 10~17。每个通道可以配置不同的采样周期,但最小的采样周期是1.5个周期,也就是说如果想最快时间采样就设置采样周期为1.5.

转换时间

转换时间 = 采样时间 + 12.5个周期
12.5个周期是固定的,一般我们设置 PCLK2=72M,经过 ADC 预分频器能分频到最大的时钟只能是 12M,采样周期设置为 1.5 个周期,算出最短的转换时间为 1.17us。

数据寄存器

转换完成后的数据就存放在数据寄存器中,但数据的存放也分为规则通道转换数据和注入通道转换数据的。

规则数据寄存器
规则数据寄存器负责存放规则通道转换的数据,通过32位寄存器ADC_DR来存放。

image-20211005215724455

当使用ADC独立模式(也就是只使用一个ADC,可以使用多个通道)时,数据存放在低16位中,当使用ADC多模式时高16位存放ADC2的数据。需要注意的是ADC转换的精度是12位,而寄存器中有16个位来存放数据,所以要规定数据存放是左对齐还是右对齐。
左对齐:数据存放在16位中的左边12位,(右边)低4位补0
右对齐:高(左边)4位补0,右边12位填采集到的数据

当使用多个通道转换数据时,会产生多个转换数据,然鹅数据寄存器只有一个,多个数据存放在一个寄存器中会覆盖数据导致ADC转换错误,所以我们经常在一个通道转换完成之后就立刻将数据取出来,方便下一个数据存放。一般开启DMA模式将转换的数据,传输在一个数组中,程序对数组读操作就可以得到转换的结果。

注入数据寄存器

注入通道转换的数据寄存器有4个,由于注入通道最多有4个,所以注入通道转换的数据都有固定的存放位置,不会跟规则寄存器那样产生数据覆盖的问题。 ADC_JDRx 是 32 位的,低 16 位有效,高 16 位保留,数据同样分为左对齐和右对齐,具体是以哪一种方式存放,由ADC_CR2 的 11 位 ALIGN 设置。

image-20211005220008835

数据转换完成

在这里插入图片描述

从框图中可以知道数据转换完成之后可以产生中断,有三种情况:

规则通道转换完成中断

规则通道数据转换完成之后,可以产生一个中断,可以在中断函数中读取规则数据寄存器的值。这也是单通道时读取数据的一种方法。

注入通道转换完成中断

注入通道数据转换完成之后,可以产生一个中断,并且也可以在中断中读取注入数据寄存器的值,达到读取数据的作用。

模拟看门狗事件

当输入的模拟量(电压)不再阈值范围内就会产生看门狗事件,就是用来监视输入的模拟量是否正常。
以上中断的配置都由ADC_SR寄存器决定:

在这里插入图片描述

当然,在转换完成之后也可以产生DMA请求,从而将转换好的数据从数据寄存器中读取到内存中。

电压转换

要知道,转换后的数据是一个12位的二进制数,我们需要把这个二进制数代表的模拟量(电压)用数字表示出来。

比如测量的电压范围是0~3.3V,转换后的二进制数是x,因为12位ADC在转换时将电压的范围大小(也就是3.3)分为4096(2^12)份,所以转换后的二进制数x代表的真实电压的计算方法就是:
y = 3.3 * x / 4096

ADC用法

初始化结构体

1
2
3
4
5
6
7
8
9
typedef struct{
uint32_t ADC_Mode; // ADC 工作模式选择
FunctionalState ADC_ScanConvMode; // ADC 扫描(多通道)或者单次(单通道)模式选择
FunctionalState ADC_ContinuousConvMode; // ADC 单次转换或者连续转换选择
uint32_t ADC_ExternalTrigConv; // ADC 转换触发信号选择
uint32_t ADC_DataAlign; // ADC 数据寄存器对齐格式
uint8_t ADC_NbrOfChannel; // ADC 采集通道数
} ADC_InitTypeDef;

例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
void  Adc_Init(void){
ADC_InitTypeDef ADC_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA |RCC_APB2Periph_ADC1, ENABLE ); //使能ADC1通道时钟

RCC_ADCCLKConfig(RCC_PCLK2_Div6); //设置ADC分频因子6 72M/6=12,ADC最大时间不能超过14M

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1; //PA1 作为模拟通道输入引脚
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; //模拟输入引脚
GPIO_Init(GPIOA, &GPIO_InitStructure);

ADC_DeInit(ADC1); //复位ADC1

ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; //ADC工作模式:ADC1和ADC2工作在独立模式
ADC_InitStructure.ADC_ScanConvMode = DISABLE; //模数转换工作在单通道模式
ADC_InitStructure.ADC_ContinuousConvMode = DISABLE; //模数转换工作在单次转换模式
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; //转换由软件而不是外部触发启动
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; //ADC数据右对齐
ADC_InitStructure.ADC_NbrOfChannel = 1; //顺序进行规则转换的ADC通道的数目
ADC_Init(ADC1, &ADC_InitStructure); //初始化外设ADC1


ADC_Cmd(ADC1, ENABLE); //使能指定的ADC1

ADC_ResetCalibration(ADC1); //使能复位校准

while(ADC_GetResetCalibrationStatus(ADC1)); //等待复位校准结束

ADC_StartCalibration(ADC1); //开启AD校准

while(ADC_GetCalibrationStatus(ADC1)); //等待校准结束

// ADC_SoftwareStartConvCmd(ADC1, ENABLE); //使能指定的ADC1的软件转换启动功能

}

评论