1、adc简介
2、函数配置
3、代码
1、adc简介
在ADC就是模数转换器,将模拟量转换成数字量,举个例子就是将电压转换位数字量,STM32拥有1-3个ADC(模数转换器),这些ADC可以独立使用,也可以采用双从模式(提高采样频率)STM32的ADC是12位逐次逼近的模拟数字转换器。它的每个adc有18个通道(ADC工作的时候只接一个通道),可以测量16个外部通道和2个内部信号源。各通道的ad可以单次转换、连续转换、扫描模式或者间断模式。这边我需要解释上面的几个模式:首先对于单通道来说,是不存在扫描模式的,这里的单次转换指的是就是你使能一次之后,那么adc本次转换完成之后就停止转换。连续模式是使能一次之后,一次转换结束之后,马上开始下一次转换。对于多通道来说,如果我们选择读取多个通道的值的时候,我们是需要选择扫描模式的,然后在扫描模式下单次转换是指一个通道转换结束之后就开始下一通道的转换,走一圈后停止。连续转换指的是一个通道转换结束之后,马上开始下一通道的转换,走一圈之后不停止,继续下一圈的转换。
在使用ADC的时候有一个东西需要注意,那就是STM32的ADC的最大转换速率为1MHZ,也就是转换时间为1us(在 ADCCLK=14M,采样周期 为 1.5 个 ADC 时钟下得到),不要让 ADC 的时钟超过 14M,否则将导致结果准确度下降。因为ADC1是挂在APB2时钟下面的,APB1的时钟为72MHZ,所以今天我们在选择分频系数的时候要大于5.14,所以今天的实验我们选择的分频系数为6。
在使用ADC的时候,还有一个知识点需要注意,那就是规则通道组和注入通道组。规则通道组相当于是正常执行的程序,注入通道组就相当于是一个中断,注入通道执行完之后才会回到正常程序继续执行。区分这两个分组是为了提高单片机的效率,这和中断的设定是一个道理,为了提高单片机处理事情的速率。
2、函数配置
这边主要讲一下ADC的初始化函数和读取ADC的函数
ADC函数的初始化:
1、开启我们的GPIO的时钟和ADC的时钟,这边我们使用的是A1和ADC1,这两个外设都挂在APB2的时钟下面。
2、开启时钟之后,我们需要设置 ADC1的分频系数,按照之前的解释这边选择分频系数为6。
3、初始化我们的IO口,这边选择IO的工作模式为模拟输入。
4、上面设置完成后,需要重初始化ADC1。这边我们调用的是ADC_DeInit(ADC1);
5、对ADC1的工作进行设置
//初始化adc
ADC_InitTypesTructure.ADC_ContinuousConvMode=DISABLE;//不允许连续转换模式,即单次转换
ADC_InitTypesTructure.ADC_DataAlign=ADC_DataAlign_Right;//12位的adc,存储在16位的数据寄存器中,所以这边选择右对齐
ADC_InitTypesTructure.ADC_ExternalTrigConv=ADC_ExternalTrigConv_None;//adc转换由软件启动而不是外部事件触发
ADC_InitTypesTructure.ADC_Mode=ADC_Mode_Independent;//独立模式
ADC_InitTypesTructure.ADC_NbrOfChannel=1;//进行转换的通道数是1;
ADC_InitTypesTructure.ADC_ScanConvMode=DISABLE;//单通道模式
ADC_Init(ADC1,&ADC_InitTypesTructure);
6、初始化ADC之后,我们需要对ADC进行使能然后校准
ADC_Cmd(ADC1, ENABLE); //使能指定的ADC1
ADC_ResetCalibration(ADC1); //使能复位校准
while(ADC_GetResetCalibrationStatus(ADC1)); //等待复位校准结束
ADC_StartCalibration(ADC1); //开启AD校准
while(ADC_GetCalibrationStatus(ADC1)); //等待校准结束
下面说一下我们读取ADC的函数:
1、在读取ADC的值的时候,我们需要设定ADC的规则组通道规则,这边就是之前我说的,这通过调用下面的函数设置,哪个ADC、哪个通道、采样时间
ADC_RegularChannelConfig(ADC1, ch, 1, ADC_SampleTime_239Cycles5 ); //ADC1,ADC通道,设置转换的序列,采样时间为239.5周期
2、然后软件使能我们的ADC开始工作,获取EOC(转换完成标志位)的状态,如果转换完成,我们就获取ADC的值并将这个值返回。
3、然后你可以根据返回的值进行处理。
3、代码
adc.c
void Adc_Init(void)
{
GPIO_InitTypeDef GPIO_InitTypeStructure;
ADC_InitTypeDef ADC_InitTypesTructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1 ,ENABLE);
//设置ADC1的时钟分频系数,并复位ADC1
RCC_ADCCLKConfig(RCC_PCLK2_Div6);
//初始化引脚
GPIO_InitTypeStructure.GPIO_Mode=GPIO_Mode_AIN;
GPIO_InitTypeStructure.GPIO_Pin=GPIO_Pin_1;
GPIO_InitTypeStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_InitTypeStructure);
//设置ADC1的时钟分频系数,并复位ADC1
ADC_DeInit(ADC1);
//初始化adc
ADC_InitTypesTructure.ADC_ContinuousConvMode=DISABLE;//不允许连续转换模式,即单次转换
ADC_InitTypesTructure.ADC_DataAlign=ADC_DataAlign_Right;//12位的adc,存储在16位的数据寄存器中,所以这边选择右对齐
ADC_InitTypesTructure.ADC_ExternalTrigConv=ADC_ExternalTrigConv_None;//adc转换由软件启动而不是外部事件触发
ADC_InitTypesTructure.ADC_Mode=ADC_Mode_Independent;//独立模式
ADC_InitTypesTructure.ADC_NbrOfChannel=1;//进行转换的通道数是1;
ADC_InitTypesTructure.ADC_ScanConvMode=DISABLE;//单通道模式
ADC_Init(ADC1,&ADC_InitTypesTructure);
//使能ADC并校准,这部分的代码直接拷过来就可以
ADC_Cmd(ADC1, ENABLE); //使能指定的ADC1
ADC_ResetCalibration(ADC1); //使能复位校准
while(ADC_GetResetCalibrationStatus(ADC1)); //等待复位校准结束
ADC_StartCalibration(ADC1); //开启AD校准
while(ADC_GetCalibrationStatus(ADC1)); //等待校准结束
// ADC_SoftwareStartConvCmd(ADC1, ENABLE); //使能指定的ADC1的软件转换启动功能
}
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 i;
for(i=0;i<times;i++)
{
temp_val+=Get_Adc(ch);
delay_ms(5);
}
return temp_val/times;
}