一、什么是ADC
ADC(Analogto-Digital Converter)模拟数字转换器,是将模拟信号转换成数字信号的一种外设。比如某一个电阻两端的是一个模拟信号,单片机无法直接采集,此时需要ADC先将短租两端的电压这个模拟信号转化成数字信号,单片机才能够进行处理。
二、ADC的用途
ADC具有将模拟信号转换成数字信号的能力,比如将模拟的电压转换成数字信号,单片机进行处理。可以用作温度监测或者电流监测等方面,用途极广。
三、STM32F103ZET6的ADC
根据中文参考手册介绍,STM32F103ZET6单片机有3个12位ADC,共有18个通道,可测量16个外部和2个内部信号源。各通道的A/D转换可以单次、连续、扫描或间断模式执行。ADC的结果可以左对齐或右对齐方式存储在16位数据寄存器中。ADC的输入时钟不得超过14MHz,它是由PCLK2经分频产生。
3.1 ADC通道对应引脚
STM32F103ZET6的ADC各通道对应IO如下
通道 ADC1 ADC2 ADC3
通道0 PA0 PA0 PA0
通道1 PA1 PA1 PA1
通道2 PA2 PA2 PA2
通道3 PA3 PA3 PA3
通道4 PA4 PA4 PA4
通道5 PA5 PA5 PA5
通道6 PA6 PA6 PA6
通道7 PA7 PA7 PA7
通道8 PB0 PB0 PB0
通道9 PB1 PB1 PB1
通道10 PC0 PC0 PC0
通道11 PC1 PC1 PC1
通道12 PC2 PC2 PC2
通道13 PC3 PC3 PC3
通道14 PC4 PC4 PC4
通道15 PC5 PC5 PC5
通道10 内部温度传感器
通道10 内部参考电压VREF
3.2ADC时钟
ADC输入时钟ADC_CLK由APB2分频产生,最大值是14MHz。库函数提供了设置分频因子的函数
void RCC_ADCCLKConfig(uint32_t RCC_PCLK2)
可选的分频因子有
#define RCC_PCLK2_Div2 ((uint32_t)0x00000000)
#define RCC_PCLK2_Div4 ((uint32_t)0x00004000)
#define RCC_PCLK2_Div6 ((uint32_t)0x00008000)
#define RCC_PCLK2_Div8 ((uint32_t)0x0000C000)
APB2总线时钟为72MHz,而ADC的最大工作频率为14MHz,所以,分频因子一般设置为6,这样ADC的输入时钟频率为12MHz。
3.3 ADC工作模式
根据中文参考手册介绍,STM32F1的ADC有三种工作模式
单次转换模式
单次转换模式下,ADC只执行一次转换。该模式既可通过设置ADC_CR2寄存器的ADON位(只适用于规则通道)启动也可通过外部触发启动(适用于规则通道或注入通道),这时CONT位为0。
连续转换模式
在连续转换模式中,当前面ADC转换一结束马上就启动另一次转换。此模式可通过外部触发启动或通过设置ADC_CR2寄存器上的ADON位启动,此时CONT位是1。
扫描模式
3.4 ADC转换时间
ADC的总转换时间与时钟频率有关,总转换时间 = 采样时间 + 12.5个周期
。其中,采样时间最短为1.5个周期,也就是最短转换时间为14个时钟周期。使用软件触发时,可选择的采样时间如下
#define ADC_SampleTime_1Cycles5 ((uint8_t)0x00)
#define ADC_SampleTime_7Cycles5 ((uint8_t)0x01)
#define ADC_SampleTime_13Cycles5 ((uint8_t)0x02)
#define ADC_SampleTime_28Cycles5 ((uint8_t)0x03)
#define ADC_SampleTime_41Cycles5 ((uint8_t)0x04)
#define ADC_SampleTime_55Cycles5 ((uint8_t)0x05)
#define ADC_SampleTime_71Cycles5 ((uint8_t)0x06)
#define ADC_SampleTime_239Cycles5 ((uint8_t)0x07)
3.5 ADC校准
使能ADC后,需要对ADC进行校准。使用库函数开发时,提供了ADC校准的函数
ADC_ResetCalibration(ADC1);//重置指定的ADC的校准寄存器
while(ADC_GetResetCalibrationStatus(ADC1));//获取ADC重置校准寄存器的状态
ADC_StartCalibration(ADC1);//开始指定ADC的校准状态
while(ADC_GetCalibrationStatus(ADC1));//获取指定ADC的校准程序
3.6 ADC转换结果与实际电压的换算
获取到的AD转换结果并不是实际电压,如果想要得到实际电压,需要经过换算。上面介绍了,STM32的ADC为12位,也就是AD值取值范围为0~4095。采集电压范围为0到3.3V。AD值与实际电压之间存在比例关系。
实际电压 = (AD值 / 4095) * 3.3。单位为伏特(V)
四、ADC配置步骤
- 使能GPIO时钟和ADC时钟,设置引脚为模拟输入
- 设置ADC的分频因子
- 初始化ADC参数,包括ADC工作模式,规则序列等
- 使能ADC并校准
- 触发AD转换,读取AD转换值
五、ADC配置程序
5.1 ADC初始化程序
这里以配置ADC1的通道1为例,给出ADC的配置例程,分频因子设置为6,单次转换模式,软件触发。
/*
*==============================================================================
*函数名称:ADC1_Init
*函数功能:初始化ADCx
*输入参数:无
*返回值:无
*备 注:无
*==============================================================================
*/
void ADC1_Init(void)
{
// 结构体定义
GPIO_InitTypeDef GPIO_InitStructure;
ADC_InitTypeDef ADC_InitStructure;
// 开启时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_ADC1,ENABLE);
// 设置ADC分频因子6 72M/6=12,ADC最大时间不能超过14M
RCC_ADCCLKConfig(RCC_PCLK2_Div6);
// GPIO配置
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_1; //ADC1通道1
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AIN; // 模拟输入
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_InitStructure);
// ADC参数配置
ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; // 独立模式
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_InitStructure.ADC_NbrOfChannel = 1; // 1个转换在规则序列中 也就是只转换规则序列1
ADC_Init(ADC1, &ADC_InitStructure); // ADC初始化
ADC_Cmd(ADC1, ENABLE); // 开启AD转换器
// ADC校准
ADC_ResetCalibration(ADC1); // 重置指定的ADC的校准寄存器
while(ADC_GetResetCalibrationStatus(ADC1)); // 获取ADC重置校准寄存器的状态
ADC_StartCalibration(ADC1); // 开始指定ADC的校准状态
while(ADC_GetCalibrationStatus(ADC1)); // 获取指定ADC的校准程序
ADC_SoftwareStartConvCmd(ADC1, ENABLE); // 使能或者失能指定的ADC的软件转换启动功能
}
5.2 软件触发AD转换
库函数开发,配置为软件触发时,可以通过下面的函数触发AD转换
void ADC_SoftwareStartConvCmd(ADC_TypeDef* ADCx, FunctionalState NewState)
5.3 读取AD转换结果
库函数提供了用于读取AD转换结果的函数
uint16_t ADC_GetConversionValue(ADC_TypeDef* ADCx)
这里给出另一个函数,用于软件触发AD转换并读取转换结果
/*
*==============================================================================
*函数名称:Get_ADC_Value
*函数功能:读取某一规则通道AD值
*输入参数:ch:规则通道ADC_Channel_x;times:读取次数
*返回值:无
*备 注:该函数配置好后,返回的结果是N次后的平均值
*==============================================================================
*/
u16 Get_ADC_Value(u8 ch,u8 times)
{
u32 temp_val = 0;
u8 t;
// 设置指定ADC的规则组通道,一个序列,采样时间
// ADC1,ADC通道,239.5个周期,提高采样时间可以提高精确度
ADC_RegularChannelConfig(ADC1, ch, 1, ADC_SampleTime_239Cycles5);
for(t=0;t<times;t++)
{
ADC_SoftwareStartConvCmd(ADC1, ENABLE); // 使能指定的ADC1的软件转换启动功能
while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC )); // 等待转换结束
temp_val+=ADC_GetConversionValue(ADC1);
delay_ms(5);
}
return temp_val/times;
}