ADC
1. ADC概述
-
ADC(Analog to Digital Converter)模拟数字转换器
作用:将模拟量(如电压值、光敏电阻阻值等)转换为数字量的设备
2. 原理图
5是ADC参考电压, 6是ADC供电引脚,10是数据寄存器存放结果,11是ADC转换完成的状态标志位,可以使能中断
2.1.1 16个外部通道(1)和两个内部通道(2)
- 16个外部通道即 ADCx_IN0…15,可查看引脚定义图。
- 内部通道有一个温度传感器,可查看CPU温度,另一个是内部的参考电压,为1.2V左右的基准电压(不受外界电压影响)。
2.1.2 ADC转换单元
规则组(16个):16个通道只有一个数据寄存器,所以适用于大规模的连续转换的场景。
注入组(4个):每个通道都有数据寄存器,并且注入组比规则组有更高的优先级(可以打断规则组的转换),所以适用于快速响应,单次转换。
2.1.3 ADC转换模式的选择(3)
配置模式选择有两个函数ADC_ContinuousConvMode(是否启用连续转换)和ADC_ScanConvMode(是否启用扫描模式),所以两个配置就产生了四种结果:单次转换非扫描、连续转换非扫描、单次转换扫描、连续转换扫描模式。
模式 | 介绍 |
---|---|
单次转换 | 只执行转换一次 |
连续转换 | 转换一次后立马进行下一次转换 |
非扫描模式 | 只转换ADC_SQRx或ADC_JSQR选中的第一个通道 |
扫描模式 | 一次性转换所有被选中的通道 |
单次转换非扫描:
一次只转换选中的某一个通道,且只转换一次。其转换结果放在数据寄存器里面,EOC标志位置1表示转换完成。如果还想继续转换,就得重新再触发一次。
连续转换非扫描:
一次只转换选中的某一个通道,触发一次便可以一直转换。且读取AD值直接去数据寄存器里面取,无需判断转换是否结束。
单次转换扫描:
只转换一次,一次性转换所有被选中的通道,按你指定的顺序依次转换并放入到数据寄存器中。但数据寄存器只有一个,所以为了防止覆盖需要及时将数据挪走。当EOC标志位置1表示转换完成。
连续转换扫描:
一次性转换所有被选中的通道,触发一次便可以一直转换;同理上面。
2.1.4 ADC时钟(4)
由于ADC来源于APB2总线,其频率最大可以达到72MHz,而ADC的时钟最大只能为14MHz。故一般先经过ADC预分频器经行6分频得到12MHz的时钟。ADC的转换时间一般在1us,如果大于14MHz,采样时间就过少导致采样不精确,为什么是1us原因如下:
考虑到ADC的采样时间最低为1.5个周期(上图所示),根据 TCONV=采样时间+12.5周期
- 频率(f):单位时间内完成周期变化的次数。
- 周期(T):完成一次周期变化的时间。
其中12.5为ADC完成转换的固定时间,根据T=1/f, T= 1/(1.5+12.5) * 1/14MHz(单个周期的时间)= 1us
2.1.5 ADC触发源
定时器触发(7和8):给定时器设置定时时间,并把定时器更新事件选择为TRGO输出,这样就能自动触发ADC转换了且无需进入中断,节省中断资源。理论上可以在定时器中断使用软件触发。但这样频繁进入中断尤其是很多中断时,由于优先级不同会出现某些中断不能及时响应,也浪费资源。
外部中断触发(9):外部中断可以产生一个触发脉冲,触发ADC转换。
软件触发:也就是ADC_SoftwareStartConvCmd(ADC1, ENABLE);
2.1.6 模拟看门狗(12)
模拟看门狗用于检测输入电压范围:检测ADC值,当检测值低于或高于某个阈值时,用来执行某些操作(类似于自动监测,无需人为操作,好比家里有条看门狗)。
3. ADC配置代码
void Adc_Init(void){
GPIO_InitTypeDef GPIO_InitStructure;
ADC_InitTypeDef ADC_InitStructure;
//开启ADC和GPIO时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_ADC1, ENABLE);
//引脚初始化
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);
RCC_ADCCLKConfig(RCC_PCLK2_Div6);//设置ADC分频因子为12MHz,最大不超过14MHz
ADC_InitStructure.ADC_ContinuousConvMode = DISABLE; //非连续
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;//数据右对齐
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;//禁止外部触发,使用软件触发
ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;//独立模式
ADC_InitStructure.ADC_NbrOfChannel = 1; //通道数目
ADC_InitStructure.ADC_ScanConvMode = DISABLE; //非扫描
ADC_Init(ADC1, &ADC_InitStructure);
ADC_Cmd(ADC1, ENABLE); //开启ADC
ADC_ResetCalibration(ADC1); //使能复位校准
while(ADC_GetResetCalibrationStatus(ADC1) == SET); // 返回SET表示未复位完成
ADC_StartCalibration(ADC1); //开启AD校准
while(ADC_GetCalibrationStatus(ADC1) == SET); //等待完成校准
}
uint16_t Get_Adc(uint8_t ch){
ADC_RegularChannelConfig(ADC1,ch,1, ADC_SampleTime_239Cycles5);//设置采样时间(对应之前采样时间图的239.5个周期)
ADC_SoftwareStartConvCmd(ADC1, ENABLE); //软件转换
while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC)); //等待完成
return ADC_GetConversionValue(ADC1);
}
- 启动复位校准:因为ADC 模块内部有许多寄存器和状态机。在进行配置之前启动复位操作,可以将 ADC 的内部状态机、寄存器等恢复到初始状态,确保没有残留的错误设置或者未完成的操作影响后续的配置和转换过程。
- 启动AD校准:因为 ADC 内部的参考电压偏差、比较器的阈值偏差等,通过校准并对这些偏差进行补偿,从而提高 ADC 转换结果的准确性
- 数据对齐:因为芯片的ADC为12位的,而数据寄存器为16位,所以通过左移或右移完成数据对齐