Skip to content

STM32外设-ADC


一、ADC简介

ADC-模拟数字转换器 ADC可以将引脚上连续变化的模拟电压转化为内存中储存的变量 stm32f1系列内部采用逐次逼近型ADC 输入电源0\~3.3V,输出数字量0\~4095 18个输入通道,16个外部通道,2个内部通道,内部划分为规则组和注入组两个转化单元 模拟看门狗可监测输入电压范围并产生中断

tip: STM32F103C8T6 ADC资源:ADC1、ADC2,10个外部输入通道

二、逐次逼近型ADC


840X535/008ad3O3gy1i5gt5c6o02j30nc0evq78.jpg

逐次逼近型ADC(SAR ADC)是一种常见的模数转换器,它通过一种“二分搜索”策略逐步确定输入模拟电压对应的数字值。其工作过程始于采样保持电路对输入电压进行捕获,随后内部数模转换器(DAC)从最高有效位(MSB)开始,逐次产生不同的参考电压与输入电压进行比较。每次比较后,根据比较器的输出结果(0或1)来锁定或舍弃当前位,并调整下一次的参考电压,逐步逼近实际输入值。这一过程就像天平称重,通过依次尝试不同砝码(对应二进制位的权重)来精确测量。SAR ADC在速度、精度和功耗之间取得了良好平衡,因此被广泛应用于中速高精度的数据采集系统、传感器接口和工业控制等领域。


三、stm32-ADC结构

ADC框图

448X583/008ad3O3gy1i5gt5c6o02j30nc0evq78.jpg

基本结构

1396X647/008ad3O3gy1i5gtf253t6j312s0hzwkz.jpg

输入通道

753X721/008ad3O3gy1i5gthmb4baj30kx0k1jw6.jpg

四、ADC转换

1、单次转化,非扫描模式

单次转换模式下,一次触发信号,ADC只执行一次转换,EOC(转换结束)标志被设置

image

2、连续转化,非扫描模式

在连续转换模式中,当前面ADC转换一结束马上就启动另一次转换,EOC为下次转化提供脉冲信号。

1041X736/ff2801fc49ad41fe9c445f7b075a4068_(1).jpg

3、单次转化,扫描模式

使用该模式需配置规则组/注入组的通道列表

1174X669/ed5c6ce47252e0b50709907b4bf6bc6c.jpg

4、连续转化,扫描模式

使用该模式需配置规则组/注入组的通道列表

1305X673/008ad3O3gy1i5gu6j3ozej31090iptcp.jpg

5、其他模式见手册11.3部分

6、转化时序

1187X643/008ad3O3gy1i5gv46erdlj30wz0hvdm1.jpg


7、校准

•ADC有一个内置自校准模式。校准可大幅减小因内部电容器组的变化而造成的准精度误差。校准期间,在每个电容器上都会计算出一个误差修正码(数字值),这个码用于消除在随后的转换中每个电容器上产生的误差

•建议在每次上电后执行一次校准

•启动校准前, ADC必须处于关电状态超过至少两个ADC时钟周期

五、代码

1、单路ADC

使能ADC和GPIO时钟

RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);    //开启ADC1的时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);   //开启GPIOA的时钟

设置ADC时钟

ADC时钟来源于APB2总线,最大14Mhz,进行预分配处理时需注意

RCC_ADCCLKConfig(RCC_PCLK2_Div6);                     //选择时钟6分频,ADCCLK = 72MHz / 6 = 12MHz

GPIO初始化

GPIO需设置为模拟输入模式,以采集模拟电压值

/*GPIO初始化*/
  GPIO_InitTypeDef GPIO_InitStructure;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_Init(GPIOA, &GPIO_InitStructure);                  //将PA0引脚初始化为模拟输入

规则组通道配置

//规则组序列1的位置,配置为通道0
  ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_55Cycles5);

ADC初始化

通道数仅需在扫描模式下配置

/*ADC初始化*/
    ADC_InitTypeDef ADC_InitStructure;                      //定义结构体变量
    ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;      //模式,选择独立模式,即单独使用ADC1
    ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;  //数据对齐,选择右对齐
    ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; //外部触发,使用软件触发,不需要外部触发
    ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;     //连续转换,失能,每转换一次规则组序列后停止
    ADC_InitStructure.ADC_ScanConvMode = DISABLE;           //扫描模式,失能,只转换规则组的序列1这一个位置
    ADC_InitStructure.ADC_NbrOfChannel = 1;                 //通道数,为1,仅在扫描模式下,才需要指定大于1的数,在非扫描模式下,只能是1
    ADC_Init(ADC1, &ADC_InitStructure);                     //将结构体变量交给ADC_Init,配置ADC1

ADC使能并校准

/*ADC使能*/
    ADC_Cmd(ADC1, ENABLE);                                  //使能ADC1,ADC开始运行

    /*ADC校准*/
    ADC_ResetCalibration(ADC1);                             //固定流程,内部有电路会自动执行校准
    while (ADC_GetResetCalibrationStatus(ADC1) == SET);
    ADC_StartCalibration(ADC1);
    while (ADC_GetCalibrationStatus(ADC1) == SET);

获取转化值

通常情况下,不需要、也不应该手动清除EOC标志。它在您读取ADC转换数据寄存器(DR)时会自动由硬件清除。

uint16_t AD_GetValue(void)
{
    ADC_SoftwareStartConvCmd(ADC1, ENABLE);                 //软件触发AD转换一次
    while (ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET); //等待EOC标志位,即等待AD转换结束
    return ADC_GetConversionValue(ADC1);                    //读数据寄存器,得到AD转换的结果
}

2、多路ADC