ADC数模转换
注意:本篇笔记以ZET6为例
其中,12位的分辨率指ADC可将模拟量转化为12位的二进制数。
每个ADC都有18个通道,其中外部通道有16个。
内部Vrefint是指内部的参考电压值。
连接内部的Vss是指连接到内部的公共接地端。
模拟量转化为数字量,需要进行采样、转化、编码三个步骤。
因此ADC的转化时间包含了采样时间以及后面的量化/编码时间,即TCONV = 采样时间 + 12.5个采样周期。
如果ADCCLK的时钟频率为14M,则当个周期时间为1/14M,即14分之一微秒,所以整个TCONV合起来是1us,采样周期是可以在代码当中进行设置的。
一、ADC功能框图
1、电压输入范围
VREF+是模拟参考正级:需要满足表中要求的范围(2.4v<=VREF+<=VDDA)
VREF-是模拟参考负极:一般将模拟参考负极接入到单片机的接地端
因此ADC输入电压的范围实际上就是在0-3.3v之间
2、输入通道
除了外部通道外,还有一些内部通道(内部温度传感器)
这些ADC通道又被区分为注入通道和规则通道,不同的通道转化的结果会存放在不同的地方。
而注入通道的模拟量转化完成的结果存放至“注入通道数据寄存器”(4个)
规则通道的模拟量转换完成的结果存放至“规则通道数据寄存器”(1个)
在ADCCLK中可以设置ADC的时钟,设置ADC的分频系数。
注入通道的转换可以打断规则通道的转换,在注入通道被转换完后,规则通道才得以继续转换。
在常规的情况下如果没有使用注入通道,那就是使用常规通道轮流转换,从第一个通道到最后一个通道。
如果有使用注入通道,注入通道可以随时打断常规通道的转换,注入通道最多就只有四个通道了,注入
通道轮流转换完后再会得到常规通道进行转换。
如果ADC转化完成后,还可以产生相对应的中断。
ADC的触发方式有很多种,可以软件启动ADC转换,也可以用其他的定时器来触发。
二、ADC转换编程流程
方式1
第一步,打开ADC的时钟、对应GPIO的时钟
根据数据手册当中的时钟框图,可以看到ADC的时钟来源于APB2上,所以我们需要打开在APB2的时钟。当然,还有IO口的时钟。
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1 | RCC_APB2Periph_GPIOA, ENABLE);
根据参考手册(8.1.11)可以查询到GPIO使用ADC时,需要使用模拟输入模式:
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AIN;
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_1;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
第二步,配置ADC的时钟分频系数,ADC的时钟频率最高不能超过14M,超过14M会导致精度丢失。
RCC_ADCCLKConfig(RCC_PCLK2_Div6); //72M分频,6分频后ADC时钟为12M
第三步,复位ADC
ADC_DeInit(ADC1);
第四步,初始化ADC
ADC_Mode
正常情况下,只使用一个ADC单元使用的模式是独立模式。
后面那些同步规则和同步注入的模式适用于同时使用多个ADC单元同时使用的情景。
ADC扫描转换模式与ADC连续转换模式,由于只用了一个通道,所以不需要打开这两个模式,赋值为DISABLE。
ADC外部触发转换
上文提到ADC具有多种外部触发条件,这里我们选择直接软件启动。
从程序可以看出ADC的外部触发有多种条件,其中包括多个定时器的多个通道。
但是这里不需要使用外部触发,我们选择直接软件触发,所以这里设置为None。
ADC数据对齐方式
中文参考手册可查
ADC分辨率12位即将输入的电压值转换成12位的二进制数
数据右对齐时,规则组内的数据全部往右边对齐,左边的数据直接补零
数据左对齐则相反,数据往左对其,低位补零。此时该值如果要还原成原来的大小,需要除以2的4次方
因为数据左对齐的数据需要还原比较麻烦,所以一般选择数据右对齐
ADC通道数目
由于我们只使用了一个通道,所以我们在这里赋值为1
完整的ADC定义:
ADC_InitStruct.ADC_Mode = ADC_Mode_Independent; //只用了一个通道,因此设置为独立模式
ADC_InitStruct.ADC_ScanConvMode = DISABLE; //多通道还是单通道使能
ADC_InitStruct.ADC_ContinuousConvMode = DISABLE; ;//连续模式还是单次模式
ADC_InitStruct.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; //触发方式选择了软件触发
ADC_InitStruct.ADC_DataAlign = ADC_DataAlign_Right;
ADC_InitStruct.ADC_NbrOfChannel = 1;
ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 1, ADC_SampleTime_1Cycles5);
//使能ADC,注意ADC使能完成之后再进行校准
ADC_Cmd(ADC1, ENABLE);
//ADC复位校准
ADC_ResetCalibration(ADC1);
//获取ADC复位校准标志位等待校准
while(ADC_GetResetCalibrationStatus(ADC1)) ;
//ADC开始校准
ADC_StartCalibration(ADC1);
//ADC获取开始校准标志位
while(ADC_GetCalibrationStatus(ADC1));
//校准完成后才开始AD转换,软件启动转换
ADC_SoftwareStartConvCmd(ADC1, ENABLE);
获取ADC转换后的值,编写获取转换值的函数
u16 Get_ADCRes() {
// ADC_SoftwareStartConvCmd(ADC1, ENABLE); //软件开启转换
while(ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET);
return ADC_GetConversionValue(ADC1);
}