>🎀 文章作者:二土电子 >🐸 期待大家一起学习交流! # 一、什么是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。库函数提供了设置分频因子的函数 ```c void RCC_ADCCLKConfig(uint32_t RCC_PCLK2) ``` 可选的分频因子有 ```c #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个时钟周期。使用软件触发时,可选择的采样时间如下 ```c #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校准的函数 ```c 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,单次转换模式,软件触发。 ```c /* *============================================================================== *函数名称: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转换 ```c void ADC_SoftwareStartConvCmd(ADC_TypeDef* ADCx, FunctionalState NewState) ``` ## 5.3 读取AD转换结果 库函数提供了用于读取AD转换结果的函数 ```c uint16_t ADC_GetConversionValue(ADC_TypeDef* ADCx) ``` 这里给出另一个函数,用于软件触发AD转换并读取转换结果 ```c /* *============================================================================== *函数名称: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