STM32的ADC是12位逐次逼近型的模拟数字转换器。它有18个通道,可测量16个外部和2个内部信号源。各通道的A/D转换可以单次、连续、扫描或间断模式执行。ADC的结果可以左对齐或右对齐方式存储在16位数据寄存器中。模拟看门狗特性允许应用程序检测输入电压是否超出用户定义的高/低阀值。
STM32F103系列最少都拥有2个ADC,我们选择的STM32F103ZET包含有3个ADC。STM32的ADC最大的转换速率为1Mhz,也就是转换时间为1us(在ADCCLK=14M,采样周期为1.5个ADC时钟下得到),不要让ADC的时钟超过14M,否则将导致结果准确度下降。
STM32将ADC的转换分为2个通道组:规则通道组和注入通道组。规则通道相当于你正常运行的程序,而注入通道呢,就相当于中断。在你程序正常执行的时候,中断是可以打断你的执行的。同这个类似,注入通道的转换可以打断规则通道的转换,在注入通道被转换完成之后,规则通道才得以继续转换。
STM32的单次转换模式下的相关设置,使用库函数的函数来设定使用ADC1的通道1进行AD转换。这里需要说明一下,使用到的库函数分布在stm32f10x_adc.c文件和stm32f10x_adc.h文件中。其详细设置步骤:
1)开启PA口时钟和ADC1时钟,设置PA1为模拟输入。
STM32F103ZET6的ADC通道1在PA1上,所以,我们先要使能PORTA的时钟和ADC1时钟,然后设置PA1为模拟输入。使能GPIOA和ADC时钟用RCC_APB2PeriphClockCmd函数,设置PA1的输入方式,使用GPIO_Init函数即可。
2)复位ADC1,同时设置ADC1分频因子。
开启ADC1时钟之后,我们要复位ADC1,将ADC1的全部寄存器重设为缺省值之后我们就可以通过RCC_CFGR设置ADC1的分频因子。分频因子要确保ADC1的时钟(ADCCLK)不要超过14Mhz。这个我们设置分频因子位6,时钟为72/6=12MHz,库函数的实现方法是:
RCC_ADCCLKConfig(RCC_PCLK2_Div6);
ADC时钟复位的方法是:
ADC_DeInit(ADC1);
3)初始化ADC1参数,设置ADC1的工作模式以及规则序列的相关信息。
在设置完分频因子之后,我们就可以开始ADC1的模式配置了,设置单次转换模式、触发方式选择、数据对齐方式等都在这一步实现。同时,我们还要设置ADC1规则序列的相关信息,我们这里只有一个通道,并且是单次转换的,所以设置规则序列中通道数为1。这些在库函数中是通过函数ADC_Init实现的,下面我们看看其定义:
voidADC_Init(ADC_TypeDef*ADCx,ADC_InitTypeDef*ADC_InitStruct);
从函数定义可以看出,第一个参数是指定ADC号。这里我们来看看第二个参数,跟其他外设初始化一样,同样是通过设置结构体成员变量的值来设定参数。
typedefstruct
{
uint32_tADC_Mode;//设置ADC的模式独立模式,注入同步模式
FunctionalStateADC_ScanConvMode;//设置是否开启扫描模式
FunctionalStateADC_ContinuousConvMode;//设置是否开启连续转换模式
uint32_tADC_ExternalTrigConv;//设置启动规则转换组转换的外部事件
uint32_tADC_DataAlign;//设置ADC数据对齐方式是左对齐还是右对齐
uint8_tADC_NbrOfChannel;//设置规则序列的长度
}ADC_InitTypeDef;
初始化范例:
ADC_InitTypeDefADC_InitStructure;
ADC_InitStructure.ADC_Mode=ADC_Mode_Independent;//ADC工作模式:独立模式
ADC_InitStructure.ADC_ScanConvMode=DISABLE;//AD单通道模式
ADC_InitStructure.ADC_ContinuousConvMode=DISABLE;//AD单次转换模式
ADC_InitStructure.ADC_ExternalTrigConv=ADC_ExternalTrigConv_None;//转换由软件而不是外部触发启动
ADC_InitStructure.ADC_DataAlign=ADC_DataAlign_Right;//ADC数据右对齐
ADC_InitStructure.ADC_NbrOfChannel=1;//顺序进行规则转换的ADC通道的数目1
ADC_Init(ADC1,&ADC_InitStructure);//根据指定的参数初始化外设ADCx
5)使能ADC并校准。
在设置完了以上信息后,我们就使能AD转换器,执行复位校准和AD校准,注意这两步是必须的!不校准将导致结果很不准确。
使能指定的ADC的方法是:
ADC_Cmd(ADC1,ENABLE);//使能指定的ADC1
执行复位校准的方法是:
ADC_ResetCalibration(ADC1);
执行ADC校准的方法是:
ADC_StartCalibration(ADC1);//开始指定ADC1的校准状态
记住,每次进行校准之后要等待校准结束。这里是通过获取校准状态来判断是否校准是否结束。下面我们一一列出复位校准和AD校准的等待结束方法:
while(ADC_GetResetCalibrationStatus(ADC1));//等待复位校准结束
while(ADC_GetCalibrationStatus(ADC1));//等待校AD准结束
6)读取ADC值。
在上面的校准完成之后,ADC就算准备好了。接下来我们要做的就是设置规则序列1里面的通道,采样顺序,以及通道的采样周期,然后启动ADC转换。在转换结束后,读取ADC转换结果值就是了。这里设置规则序列通道以及采样周期的函数是:
voidADC_RegularChannelConfig(ADC_TypeDef*ADCx,uint8_tADC_Channel,uint8_tRank,uint8_tADC_SampleTime);
我们这里是规则序列中的第1个转换,同时采样周期为239.5,所以设置为:
ADC_RegularChannelConfig(ADC1,ch,1,ADC_SampleTime_239Cycles5);
软件开启ADC转换的方法是:
ADC_SoftwareStartConvCmd(ADC1,ENABLE);//使能指定的ADC1的软件转换
启动功能开启转换之后,就可以获取转换ADC转换结果数据,方法是:
ADC_GetConversionValue(ADC1);
同时在AD转换中,我们还要根据状态寄存器的标志位来获取AD转换的各个状态信息。库函数获取AD转换的状态信息的函数是:
FlagStatusADC_GetFlagStatus(ADC_TypeDef*ADCx,uint8_tADC_FLAG)
比如我们要判断ADC1d的转换是否结束,方法是:
while(!ADC_GetFlagStatus(ADC1,ADC_FLAG_EOC));//等待转换结束
通过以上几个步骤的设置,我们就能正常的使用STM32的ADC1来执行AD转换操作了。
/** 初始化ADC
* 这里我们仅以规则通道为例 * 我们默认将开启通道0~3
*/
void Adc_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
ADC_InitTypeDef ADC_InitStructure;
RCC_APB2PeriphClockCmd
(RCC_APB2Periph_GPIOA |RCC_APB2Periph_ADC1, ENABLE ); //使能ADC1通道时钟
RCC_ADCCLKConfig(RCC_PCLK2_Div6); //设置ADC分频因子6 72M/6=12,ADC最大时间不能超过14M
//PA1 作为模拟通道输入引脚
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;//模拟输入引脚
GPIO_Init(GPIOA, &GPIO_InitStructure);
ADC_DeInit(ADC1); //复位ADC1,将外设 ADC1 的全部寄存器重设为缺省值
ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;//ADC工作模式:ADC1和ADC2工作在独立模式
ADC_InitStructure.ADC_ScanConvMode = DISABLE;//模数转换工作在单通道模式
ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;//模数转换工作在单次转换模式
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;//转换由软件而不是外部触发启动
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;//ADC数据右对齐
ADC_InitStructure.ADC_NbrOfChannel = 1;//顺序进行规则转换的ADC通道的数目
ADC_Init(ADC1, &ADC_InitStructure);//根据ADC_InitStruct中指定的参数初始化外设ADCx的寄存器
ADC_Cmd(ADC1, ENABLE);//使能指定的ADC1
ADC_ResetCalibration(ADC1);//使能复位校准 while(ADC_GetResetCalibrationStatus(ADC1));//等待复位校准结束
ADC_StartCalibration(ADC1); //开启AD校准
while(ADC_GetCalibrationStatus(ADC1)); //等待校准结束
} //获得ADC值
//ch:通道值 0~3 u16 Get_Adc(u8 ch)
{ //设置指定ADC的规则组通道,一个序列,采样时间 ADC_RegularChannelConfig(ADC1, ch, 1, ADC_SampleTime_239Cycles5 );
//ADC1,ADC通道,采样时间为239.5周期 ADC_SoftwareStartConvCmd(ADC1, ENABLE);//使能指定的ADC1的软件转换启动功能
while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC ));//等待转换结束
return ADC_GetConversionValue(ADC1);//返回最近一次ADC1规则组的转换结果 }
u16 Get_Adc_Average(u8 ch,u8 times)
{
u32 temp_val=0; u8 t; for(t=0;t<times;t++) { temp_val+=Get_Adc(ch); delay_ms(5); }
return temp_val/times;
}