AD简介
-
ADC(Analog-Digital Converter)模拟-数字转换器。
-
ADC可以将引脚上连续变化的模拟电压转换为内存中存储的数字变量,建立模拟电路到数字电路的桥梁。
-
12位逐次逼近型ADC,1us转换时间。
-
输入电压范围:0~3.3V,转换结果范围:0~4095
-
18个输入通道,可测量16个外部和2个内部信号源。
-
规则组和注入组两个转换单元。
-
模拟看门狗自动监测输入电压范围。
-
STM32F103C8T6 ADC资源:ADC1、ADC2,10个外部输入通道。
-
逐次逼近型ADC:
-
ADC基本结构:
-
输入通道:
-
通道 ADC1 ADC2 ADC3 通道0 PA0 PA0 PA0 通道1 PA1 PA1 PA1 通道2 PA2 PA2 PA2 通道3 PA3 PA3 PA3 通道4 PA4 PA4 PF6 通道5 PA5 PA5 PF7 通道6 PA6 PA6 PF8 通道7 PA7 PA7 PF9 通道8 PB0 PB0 PF10 通道9 PB1 PB1 通道10 PC0 PC0 PC0 通道11 PC1 PC1 PC1 通道12 PC2 PC2 PC2 通道13 PC3 PC3 PC3 通道14 PC4 PC4 通道15 PC5 PC5 通道16 温度传感器 通道17 内部参考电压 -
转换模式:看PPT,图片太多了。
-
触发控制:
-
数据对齐(一般右对齐):
-
转换时间:
-
AD转换的步骤:采样,保持,量化,编码。
-
STM32 ADC的总转换时间为: TCONV = 采样时间 + 12.5个ADC周期
-
例如:当ADCCLK=14MHz,采样时间为1.5个ADC周期 TCONV = 1.5 + 12.5 = 14个ADC周期 = 1μs。
-
-
校准:
-
ADC有一个内置自校准模式。校准可大幅减小因内部电容器组的变化而造成的准精度误差。校准期间,在每个电容器上都会计算出一个误差修正码(数字值),这个码用于消除在随后的转换中每个电容器上产生的误差。
-
建议在每次上电后执行一次校准。
-
启动校准前, ADC必须处于关电状态超过至少两个ADC时钟周期。
-
-
硬件电路:
-
code show:
//单通道 -------------------AD.c----------------------------------------------------------------------- #include "stm32f10x.h" // Device header void AD_Init(void) { //第一步,开启RCC时钟,AD和GPIO的 RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //ADCCLK配置。72MHz / 6 = 12MHz RCC_ADCCLKConfig(RCC_PCLK2_Div6); //第二步,配置GPIO,配置为模拟输入模式 GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &GPIO_InitStructure); //第三步,配置多路开关 , 输入通道(这里选择了0,如果需要多个复制即可)。 ADC_RegularChannelConfig(ADC1,ADC_Channel_0,1,ADC_SampleTime_55Cycles5); //第四步,配置ADC转换器 ADC_InitTypeDef ADC_InitStructure; ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; //使用右对齐 ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; ADC_InitStructure.ADC_ContinuousConvMode = DISABLE; ADC_InitStructure.ADC_ScanConvMode = DISABLE; ADC_InitStructure.ADC_NbrOfChannel = 1; ADC_Init(ADC1,&ADC_InitStructure); //第五步,开关控制,开启ADC,ADC_Cmd函数,最好在校准一下 ADC_Cmd(ADC1 , ENABLE); //校准 ADC_ResetCalibration(ADC1); while(ADC_GetResetCalibrationStatus(ADC1) == SET); ADC_StartCalibration(ADC1); while(ADC_GetCalibrationStatus(ADC1) == SET); } uint16_t AD_GetValue(void) { ADC_SoftwareStartConvCmd(ADC1 , ENABLE); while(ADC_GetFlagStatus(ADC1 , ADC_FLAG_EOC) == RESET); return ADC_GetConversionValue(ADC1); } -------------------AD.h----------------------------------------------------------------------- #ifndef _AD_H #define _AD_H void AD_Init(void); uint16_t AD_GetValue(void); #endif -------------------main.c--------------------------------------------------------------------- #include "stm32f10x.h" #include "OLED.h" #include "AD.h" #include "Delay.h" uint16_t ADValue; float Volatge; int main(void) { OLED_Init(); AD_Init(); OLED_ShowString(1,1,"ADValue:"); OLED_ShowString(2,1,"Volatge:0.00"); while(1) { ADValue = AD_GetValue(); Volatge = (float)ADValue /4095 * 3.3; OLED_ShowNum(1,9,ADValue,4); OLED_ShowNum(2,9,Volatge,1); OLED_ShowNum(2,11,(uint16_t)(Volatge * 100)%100,2); Delay_ms(100); } }
-
code show:
-------------------AD.c----------------------------------------------------------------------- //多通道 #include "stm32f10x.h" // Device header void AD_Init(void) { //第一步,开启RCC时钟,AD和GPIO的 RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //ADCCLK配置。72MHz / 6 = 12MHz RCC_ADCCLKConfig(RCC_PCLK2_Div6); //第二步,配置GPIO,配置为模拟输入模式 GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &GPIO_InitStructure); //第三步,配置多路开关 , 输入通道(这里选择了0,如果需要多个复制即可)。 //第四步,配置ADC转换器 ADC_InitTypeDef ADC_InitStructure; ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; //使用右对齐 ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; ADC_InitStructure.ADC_ContinuousConvMode = DISABLE; ADC_InitStructure.ADC_ScanConvMode = DISABLE; ADC_InitStructure.ADC_NbrOfChannel = 1; ADC_Init(ADC1,&ADC_InitStructure); //第五步,开关控制,开启ADC,ADC_Cmd函数,最好在校准一下 ADC_Cmd(ADC1 , ENABLE); //校准 ADC_ResetCalibration(ADC1); while(ADC_GetResetCalibrationStatus(ADC1) == SET); ADC_StartCalibration(ADC1); while(ADC_GetCalibrationStatus(ADC1) == SET); } uint16_t AD_GetValue(uint8_t ADC_Channel) { ADC_RegularChannelConfig(ADC1,ADC_Channel,1,ADC_SampleTime_55Cycles5); ADC_SoftwareStartConvCmd(ADC1 , ENABLE); while(ADC_GetFlagStatus(ADC1 , ADC_FLAG_EOC) == RESET); return ADC_GetConversionValue(ADC1); } -------------------AD.h----------------------------------------------------------------------- #ifndef _AD_H #define _AD_H void AD_Init(void); uint16_t AD_GetValue(uint8_t ADC_Channel); #endif -------------------main.c--------------------------------------------------------------------- #include "stm32f10x.h" #include "OLED.h" #include "AD.h" #include "Delay.h" uint16_t AD0,AD1,AD2,AD3; int main(void) { OLED_Init(); AD_Init(); OLED_ShowString(1,1,"AD0:"); OLED_ShowString(2,1,"AD1:"); OLED_ShowString(3,1,"AD2:"); OLED_ShowString(4,1,"AD3:"); while(1) { AD0 = AD_GetValue(ADC_Channel_0); AD1 = AD_GetValue(ADC_Channel_1); AD2 = AD_GetValue(ADC_Channel_2); AD3 = AD_GetValue(ADC_Channel_3); OLED_ShowNum(1, 5, AD0, 4); OLED_ShowNum(2, 5, AD1, 4); OLED_ShowNum(3, 5, AD2, 4); OLED_ShowNum(4, 5, AD3, 4); Delay_ms(100); } }