1.什么是ADC?
ADC(Analog-Digital Converter)模拟-数字转换器,可以将引脚上连续变化的模拟电压转换为内存中存储的数字变量,建立模拟电路到数字电路的桥梁。
2.ADC是如何转换的?
ADC是通过逐次逼近进行AD转换的,那么什么是逐次逼近呢?如上图示,比较器左侧是输入的未知电压,右侧是DAC输出的已知电压(知道电压值并且知道电压对应的数字信号值),外部输入的未知编码的电压与DAC输出的已知编码的电压,它俩同时输入到电压比较器,进行大小判断,如果DAC输出的电压大,就调小DAC的数据,如果小,就增大DAC数据,为了提高比较速度,ADC选择二分法比较。如:数字转换的范围是0~128,利用二分法的原则,先比较输入电压对应的值是否大于64,如果小于64,则比较是否大于32,依此类推。直到DAC输出的电压与外部通道输入的电压近视相等。这样DAC对应的的数据就是外部输入电压的编码数据了。
上图中,EOC(End Of Convert)为:转换结束信号。START:是开始转换CLOCK:是ACD的时钟。VREF(+)、VREF(-)是DAC的参考电压,即是对应5v还是3.3v。
3.STM32逐次逼近型框图
触发ADC转换的方式:
硬件触发:如定时器定时等(红框表示硬件出发源)。
软件触发:软件调用触发ADC转换
ADC转换通道(绿框):1.规则组;2.注入组
规则组:有16个ADC通道,同时可以进行16个AD转换,但是只有一个DR(数据寄存器),也就是说,如果同时转换16个AD,那么前15个转换结果将会被覆盖。
注入组:有4个ADC通道,同时可以进行4个AD转换,有4个DR(数据寄存器),所以数据不会被覆盖。
图中模拟至数字转换器就是逐次比较的过程,比较的数据放入数据寄存器里。
ADC时钟(蓝框):来自内部时钟72MHZ,可以进行2、4、6、8预分频,不过这里规定ADC最大的频率为14MHZ,也就是说,2、4分频无效。
规则组有四种转换模式:
单次转换,非扫描模式
连续转换,非扫描模式
单次转换,扫描模式
连续转换,扫描模式
单次转换,转换一次就停止;连续转换:只需要触发一次,就一直转换;扫描模式:可以选择多个通道;非扫描模式:只能选择一个通道。
单次转换,非扫描模式:
连续转换,非扫描模式:
单次转换,扫描模式
连续转换,扫描模式
4.STM32 ADC代码
#include "stm32f10x.h" // Device header
void AD_Init(void)
{
//第一步:开启RCC时钟(ADC,GPIO,ADCCLK)
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
RCC_ADCCLKConfig(RCC_PCLK2_Div6);
//第二步:配置GPIO(把GPIO配置成模拟输入的模式)
GPIO_InitTypeDef GPIO_InitStructure;
//在AIN模式下GPIO口是无效的,断开GPIO,防止GPIO口的输入/出对模拟电压造成干扰
//AIN模式是ADC的专属模式
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);
//第三步:配置多路开关,把左边的通道接入到右边的规则列表里(点菜)
//规则通道选择
ADC_RegularChannelConfig(ADC1,ADC_Channel_0,1,ADC_SampleTime_55Cycles5);
//第四步:配置ADC转换器(连续扫描、转换、几个通道、触发源、左右对齐)
ADC_InitTypeDef ADC_InitStructure;
//连续转换模式
ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
//数据对齐
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
//外部触发转换选择(触发控制的触发源)
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
//ADC的工作模式
ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
//通道数目(在扫描模式下用几个通道)
ADC_InitStructure.ADC_NbrOfChannel = 1;
//扫描转换模式
ADC_InitStructure.ADC_ScanConvMode = DISABLE;
ADC_Init(ADC1,&ADC_InitStructure);
//第五步:模拟看门狗或开启中断
//第六步:调用ADC_Cmd()函数,开启ADC(给ADC通电)
ADC_Cmd(ADC1,ENABLE);
//第七步:开启ADC之后,最好对ADC进行校准,较小误差。
//7.1复位校准
ADC_ResetCalibration(ADC1);
//7.2等待复位校准完成
while (ADC_GetResetCalibrationStatus(ADC1));
//7.3开始校准
ADC_StartCalibration(ADC1);
//7.4等待校准完成
while (ADC_GetCalibrationStatus(ADC1));
//触发ADC转换
ADC_SoftwareStartConvCmd(ADC1,ENABLE);
}
//启动转换,获取结果
uint16_t AD_GetValue(void)
{
//while (ADC_GetFlagStatus(ADC1,ADC_FLAG_EOC) == RESET);
//获取转换值
return ADC_GetConversionValue(ADC1);
}