文章目录
- 1.ADC概述
- 1.1 转换模式(规则组)
- 1.2 数据对齐
- 1.3 转换时间
- 1.4 校准
- 2.代码步骤
STM32F103C8T6的12位逐次逼近型ADC的工作原理,包括转换模式、数据对齐、转换时间、校准以及程序配置流程,同时涵盖了关键的库函数和中断管理。
1.ADC概述
-
ADC(Analog-Digital Converter)模拟-数字转换器
-
ADC可以将引脚上连续变化的模拟电压转换为内存中存储的数字变量,建立模拟电路到数字电路的桥梁
-
12位逐次逼近型ADC,1us转换时间
-
输入电压范围:0 ~ 3.3V,转换结果范围:0 ~ 4095
-
18个输入通道,可测量16个外部(最大16个)和2个内部信号源
-
规则组和注入组两个转换单元
-
模拟看门狗自动监测输入电压范围
左侧是ADC的输入通道,包括16个GPIO口,两个内部通道。通过模拟多路开关,选择我们需要的通道。
规则组一次可最多选16个通道,但数据寄存器只有16位,故每个通道的更新数据会覆盖前一个通道的更新数据数据(需使用DMA及时搬运数据,防止数据被覆盖)。
注入组一次最多可选4个通道,数据寄存器有4*16位,可同时读取四个通道的数据。
VREF+,VREF- ADC参考电压
VDDA,VSSA ADC供电电压
ADCCLK:ADC时钟,推动ADC进行逐次比较获得数字信号,最大为14MHZ,由APB2时钟72MHZ经过ADC预分频器获得。
模拟看门狗:存有阈值高限和阈值低限。启功后,一旦数据寄存器的值在阈值范围之外,看门狗就会申请中断,执行中断函数
EOC:规则组完成信号,规则组完成转换完成后,置标志位。
JEOC:注入组完成信号,注入组完成转换完成后,置标志位。
AWD:模拟看门狗事件,转换结果高于阈值时,置标志位。
1.1 转换模式(规则组)
单次转换, 非扫描模式:
- 非扫描模式下,规则组16个可选通道中只有第一个通道有效。
- 我们可在序列一的位置转换我们想要选择的通道,触发信号发生后,ADC就会对这个通道的数据进行模数转换,完成之后EOC置一,我们可判断EOC标志位,如果转换完成我们可在数据寄存器中读取结果。
- 再次转换需要再次触发。
连续转换, 非扫描模式:
- 与上一个模式相比,该模式会立刻进行下一次转换,不需每次转换前都发生一次触发信号,只在第一次发生触发信号即可,也不用判断是否结束,直接读取即可。
单次转换, 扫描模式:
- 与第一个相比,我们一次可选择多个通道(需指定一共的通道数),扫描各个通道,进行模数转换,但下一个数据会覆盖上一个数据。
多次转换, 扫描模式:
- 与上一个模式相比,该模式会立刻进行下一次转换,不需每次转换前都发生一次触发信号,只在第一次发生触发信号即可,也不用判断是否结束,直接读取即可。
1.2 数据对齐
数据寄存器是16位的,但ADC数模转换器的12位的,这会造成左右对齐不同时,数据不同。
右对齐:高四位为0,为真实值。(常用)
左对齐:第四位为0,可降低分辨率(使用时,只取出高八位)。
1.3 转换时间
AD: 采样, 保持, 量化, 编码
Tconv = 采样时间 + 12.5ADC 周期
量化和编码是进行比较的时间, 采样和保持时间是如果电压不断的变化, 那么会造成数据的丢失。
故我们在转换过程中,使用电容和开关,存储这段电压,当转换完成时,再输出这段电压(这段过程产生了采样时间)。
采样时间越大,越能避免一些毛刺信号的干扰。
1.4 校准
2.代码步骤
第一步:开启RCC时钟,GPIO,ADC;ADCCLK分频器配置。
/*开启时钟*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
/*配置ADCCLK预分频系数*/
RCC_ADCCLKConfig(RCC_PCLK2_Div6);
第二部:配置GPIO为模拟输入。
/*配置GPIO*/
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.GPIO_Mode=GPIO_Mode_AIN;//配置位模拟输入模式
GPIO_InitStruct.GPIO_Pin=GPIO_Pin_0;
GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_InitStruct);
第三步:配置多路开关,选择通道进入ADC中。
ADC_RegularChannelConfig(ADC1,ADC_Channel_1, 0, ADC_SampleTime_55Cycles5);//规则组序列1的位置,配置为通道0
//多通道配置时,此函数可在ADC_Init()中省略,在取值函数中每次重新配置序列数,以读取不同通道的值。(我们仍然使用的是单次,非扫描模式来实现的ADC多通道读取模拟值。)
第四步:配置ADC转化器,结构体配置。
/*配置ADC转化器*/
ADC_InitTypeDef ADC_InitStruct;
ADC_InitStruct.ADC_Mode=ADC_Mode_Independent;//独立模式
ADC_InitStruct.ADC_DataAlign=ADC_DataAlign_Right ;//右对齐模式
ADC_InitStruct.ADC_ExternalTrigConv=ADC_ExternalTrigConv_None;//软件触发
ADC_InitStruct.ADC_ContinuousConvMode=DISABLE;//非连续模式
ADC_InitStruct.ADC_ScanConvMode=DISABLE;//非扫描模式
ADC_InitStruct.ADC_NbrOfChannel=1;
ADC_Init(ADC1,&ADC_InitStruct);
第五步:开关控制,开始ADC;进行校准。
/*开启ADC*/
ADC_Cmd(ADC1, ENABLE);
/*ADC校准*/
ADC_ResetCalibration(ADC1);
while(ADC_GetResetCalibrationStatus(ADC1)==SET);//等待是否校准完成
ADC_StartCalibration(ADC1);
while(ADC_GetCalibrationStatus(ADC1)==SET);
取值函数:
/*单通道取值*/
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转换的结果
}
/*多通道取值*/
uint16_t AD_GetValue(uint8_t ADC_Channel)
{
ADC_RegularChannelConfig(ADC1, ADC_Channel, 1, ADC_SampleTime_55Cycles5); //在每次转换前,根据函数形参灵活更改规则组的通道1
ADC_SoftwareStartConvCmd(ADC1, ENABLE); //软件触发AD转换一次
while (ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET); //等待EOC标志位,即等待AD转换结束
return ADC_GetConversionValue(ADC1); //读数据寄存器,得到AD转换的结果
}
//上文ADC初始化,是单通道的初始化;多通道配置多通道取值函数,再使能几个引脚即可。