原理
我们知道自然界中很多量都是模拟量,而CPU只能识别数字量,为此,我们按一定的时间间隔对模拟量进行采样,并把采集到的值转换成数字量。
一般情况,ADC都要经过采样,保持,量化,编码四个过程。
如何实现
首先,我们看下如何实现一个简单的ADC,如下图,
模拟信号从UI输入后,通过比较器与UREF(假设是+UREF=3.2V,-UREF=0V)进行比较,每当采样脉冲到来时,就完成一次转化,转化结果如下表,参考下表,CPU只要读取编码器输出值,就可以知道模拟输入UI的电压值了。
模拟输入UI | 比较器输出(Q7-Q1) | 编码器输出(3bit) | 对应电压(+UREF=3.2V,-UREF=0) |
---|---|---|---|
UI<1/8UREF | 0000000 | 0x0 | 0 |
1/8UREF<=UI<2/8UREF | 0000001 | 0x1 | 0.4 |
2/8UREF<=UI<3/8UREF | 0000011 | 0x2 | 0.8 |
3/8UREF<=UI<4/8UREF | 0000111 | 0x3 | 1.2 |
4/8UREF<=UI<5/8UREF | 0001111 | 0x4 | 1.6 |
5/8UREF<=UI<6/8UREF | 0011111 | 0x5 | 2.4 |
6/8UREF<=UI<7/8UREF | 0111111 | 0x6 | 2.8 |
UI>=7/8UREF | 1111111 | 0x7 | 3.2 |
重要参数
ADC有下面几个重要参数必须掌握,可能不同芯片还会提供一些其他的功能参数,但是本质上都离不开下面几个参数。
-
分辨率
如上例中,编码器输出只有3个bit,最多能分辨UREF/3bit=3.2/2^3=0.4V,那么这个ADC的分辨率就是3位的。可见,分辨率代表了ADC对模拟量的识别精度。
-
转换时间
如上例中,假设比较器输出要1us,编码器输出3us,那么该ADC最快1+3=4us才能完成转换,这个就是转化时间。可见,转化时间代表了ADC的转化速度。至此,可以理解采样脉冲的时间间隔至少应该大于转换时间。
-
输入范围
如上例中,输入的模拟信号是通过比较器跟参考电压进行比较才能完成采样和转换的,如果超出参考电压的范围,上述电路肯定无法正常工作,因此,输入范围是-UREF到+UREF。
使用举例
硬件设计
如图,我们采集可变电阻的电压值。
软件设计
代码很简单,如下
static VOID ADC_GpioConfig(VOID)
{
GPIO_InitPara GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = GPIO_PIN_3;
GPIO_InitStructure.GPIO_Speed = GPIO_SPEED_50MHZ;
GPIO_InitStructure.GPIO_Mode = GPIO_MODE_AIN;
GPIO_Init(GPIOC, &GPIO_InitStructure);
}
static VOID ADC_AdcConfig(VOID)
{
ADC_InitPara ADC_InitStructure;
ADC_InitStructure.ADC_Mode = ADC_MODE_INDEPENDENT;
ADC_InitStructure.ADC_Mode_Scan = DISABLE;
ADC_InitStructure.ADC_Mode_Continuous = ENABLE;
ADC_InitStructure.ADC_Trig_External = ADC_EXTERNAL_TRIGGER_MODE_NONE;
ADC_InitStructure.ADC_Data_Align = ADC_DATAALIGN_RIGHT;
ADC_InitStructure.ADC_Channel_Number = 1 ;
ADC_Init(ADC1, &ADC_InitStructure);
ADC_RegularChannel_Config(ADC1, ADC_CHANNEL_13, 1, ADC_SAMPLETIME_71POINT5);
ADC_Enable(ADC1, ENABLE);
ADC_Calibration(ADC1);
ADC_SoftwareStartConv_Enable(ADC1, ENABLE);
}
VOID DRV_ADC_Init(VOID)
{
RCC_APB2PeriphClock_Enable(RCC_APB2PERIPH_GPIOC , ENABLE);
RCC_APB2PeriphClock_Enable(RCC_APB2PERIPH_ADC1, ENABLE);
RCC_ADCCLKConfig(RCC_ADCCLK_APB2_DIV12);
ADC_GpioConfig();
ADC_AdcConfig();
}
U16 DRV_ADC_GetConversionValue(VOID)
{
return ADC_GetConversionValue(ADC1);
}