1.什么是ADC
ADC指模数转换,模拟信号是指时间幅值均连续的信号,对其采样后得到的信号称之为离散时间信号,若再对其进行量化处理则得到数字信号。请注意对模拟信号采样得到的信号不是数字信号,仅仅是离散时间信号。(详情请见数字电子电路,信号与系统,数字信号处理等教材)
2.分辨率
当前的STM32的ADC芯片是12位的,如果参考电压是3.3v那就是说最小量化间隔就是3.3的4096分之一,如果变化量低于一个最小量化间隔则在量化时相对于上一刻无变化。故3.3的4096分之一就是STM32的ADC的分辨率。
3.连续转换,单次转换,扫描模式
一个ADC控制器最多有18个通道,在非扫描模式下是对一个通道进行转换,如果是的单次转换则会在EOC之后停止转换直到再次被触发,如果是连续转换则在一次EOC后立刻进行下次转换;如果是扫描模式则是多多通道进行转换,比如有10个通道,按照顺序依次转换,十个通道均转换完成后视其是单次转换模式还是连续转换模式,如果是连续转换模式则立即进行下一轮转换,如果是单次转换则等待下次触发。
注:扫描模式下每完成一个通道的转换都会把对应通道的EOC标志置位,但EOC中断是在整个一轮转换都完成后触发。规则组通道的数据在ADC_DR寄存器内,注入组的数据在ADC_DRJ寄存器内。如果设置了DMA的位则会在每次转换完成后把规则组的数据传入SRAM,注入组的仍然在ADC_DRJ寄存器内。
4.举例:用ADC测量3.3v电压(即参考电压)
配置:单通道单次转换。(虽然是单次转换也可以搞出连续转换的效果)
//1.main.c
#include "stm32f10x.h"
#include "delay.h"
#include "usart.h"
#include "adc.h"
#include "usart.h"
int main()
{
u16 temp;
float val;
delay_init();
my_adc_init();
uart_init(115200);
while(1)
{
temp=adc_get_val();
val=(3.3/4096)*temp;
printf("ADC:%d 转换值:%f\n",temp,val);
delay_ms(1000);
}
}
//2.ADC.C
#include "adc.h"
#include "stm32f10x.h"
void my_adc_init()
{
ADC_InitTypeDef ADC_InitType;
GPIO_InitTypeDef GPIO_InitType;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_ADC1,ENABLE);
GPIO_InitType.GPIO_Mode=GPIO_Mode_AIN;
GPIO_InitType.GPIO_Pin=GPIO_Pin_1;
GPIO_InitType.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_InitType);
RCC_ADCCLKConfig(RCC_PCLK2_Div6);
ADC_DeInit(ADC1);
ADC_InitType.ADC_ContinuousConvMode=DISABLE;//单次转换
ADC_InitType.ADC_DataAlign=ADC_DataAlign_Right;
ADC_InitType.ADC_ExternalTrigConv=ADC_ExternalTrigConv_None;
ADC_InitType.ADC_Mode=ADC_Mode_Independent;
ADC_InitType.ADC_NbrOfChannel=1;
ADC_InitType.ADC_ScanConvMode=DISABLE;//不开启扫描模式
ADC_Init(ADC1,&ADC_InitType);
ADC_Cmd(ADC1,ENABLE);
ADC_ResetCalibration(ADC1);//复位校准
while(ADC_GetResetCalibrationStatus(ADC1));
ADC_StartCalibration(ADC1);//AD校准
while(ADC_GetCalibrationStatus(ADC1));
}
u16 adc_get_val()
{
ADC_RegularChannelConfig(ADC1,ADC_Channel_1,1,ADC_SampleTime_239Cycles5);
ADC_SoftwareStartConvCmd(ADC1,ENABLE);
while(!ADC_GetFlagStatus(ADC1,ADC_FLAG_EOC));
ADC_ClearFlag(ADC1,ADC_FLAG_EOC);//清除或不清除都不影响,但如果是中断标志位的话必须清除
return ADC_GetConversionValue(ADC1);
}
//3.ADC.h
#ifndef adc_h
#define adc_h
#include "stm32f10x.h"
void my_adc_init();
u16 adc_get_val();
#endif
结果:
这里使用的是PA1,在PA1悬空时可以看到结果是飘忽不定的,当PA1接3.3v时转换结果几乎就是3.3,接地是基本就是0。
5.为什么单次转换能够连续工作:
奥秘在于adc.c下的adc_get_val()函数。该函数是在main.c的while循环里被调用的,每调用一次就会设置一次规则通道配置以及软件触发转换使能
如果把这两行放到my_adc_init()里面执行就是转换一次就停止了。