ADC(Analog-Digital Converter)模拟-数字转换器。
ADC可以将引脚上连续变化的模拟电压转换为内存中存储的数字变量,建立模拟电路到数字电路的桥梁。
12位逐次逼近型ADC,1us转换时间。
输入电压范围:0~3.3V,转换结果范围:0~4095。
18个输入通道,可测量16个外部和2个内部信号源。
规则组和注入组两个转换单元。
模拟看门狗自动监测输入电压范围。
STM32F103C8T6 ADC资源:ADC1、ADC2,10个外部输入通道。
逐次逼近型ADC

ADC框图

ADC基本结构

输入通道





触发控制

数据对齐
数据右对齐:

数据左对齐

转换时间
AD转换的步骤:采样,保持,量化,编码。
STM32 ADC的总转换时间为:
TCONV = 采样时间 + 12.5个ADC周期
例如:当ADCCLK=14MHz,采样时间为1.5个ADC周期
TCONV = 1.5 + 12.5 = 14个ADC周期 = 1μs
校准
ADC有一个内置自校准模式。校准可大幅减小因内部电容器组的变化而造成的准精度误差。校准期间,在每个电容器上都会计算出一个误差修正码(数字值),这个码用于消除在随后的转换中每个电容器上产生的误差。建议在每次上电后执行一次校准。启动校准前, ADC必须处于关电状态超过至少两个ADC时钟周期。
相关库函数
//stm32f10x_rcc.h
void RCC_ADCCLKConfig(uint32_t RCC_PCLK2);//用来配置ADCCLK分频器
void ADC_Cmd(ADC_TypeDef* ADCx, FunctionalState NewState);//给ADC上电的
void ADC_DMACmd(ADC_TypeDef* ADCx, FunctionalState NewState);//开启DMA输出信号的,如果使用DMA转运数据,则需要此函数
以下四个函数为控制校准的函数,在ADC初始化完成之后,依次调用即可。
void ADC_ResetCalibration(ADC_TypeDef* ADCx);
FlagStatus ADC_GetResetCalibrationStatus(ADC_TypeDef* ADCx);
void ADC_StartCalibration(ADC_TypeDef* ADCx);
FlagStatus ADC_GetCalibrationStatus(ADC_TypeDef* ADCx);
ADC软件开始转换控制,用于软件触发的函数。
void ADC_SoftwareStartConvCmd(ADC_TypeDef* ADCx, FunctionalState NewState);
ADC获取软件触发状态,没啥用。
FlagStatus ADC_GetSoftwareStartConvStatus(ADC_TypeDef* ADCx);
判断转换是否结束
FlagStatus ADC_GetFlagStatus(ADC_TypeDef* ADCx, uint8_t ADC_FLAG);
间断模式:
void ADC_DiscModeChannelCountConfig(ADC_TypeDef* ADCx, uint8_t Number);
void ADC_DiscModeCmd(ADC_TypeDef* ADCx, FunctionalState NewState);
ADC规则组通道配置
void ADC_RegularChannelConfig(ADC_TypeDef* ADCx, uint8_t ADC_Channel, uint8_t Rank, uint8_t ADC_SampleTime);
ADC外部触发转换控制
void ADC_ExternalTrigConvCmd(ADC_TypeDef* ADCx, FunctionalState NewState);
读取转换结果
uint16_t ADC_GetConversionValue(ADC_TypeDef* ADCx);
AD单通道转换代码示例:
//AD.c代码
#include "stm32f10x.h" // Device header
void AD_Init(void)
{
//开启RCC时钟 GPIO、ADC、ADC的分频器
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
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);
//配置多路开关、将左边通道接入右边规则组
ADC_RegularChannelConfig(ADC1,ADC_Channel_0,1,ADC_SampleTime_55Cycles5);
//配置ADC转换器
ADC_InitTypeDef ADC_InitSturct;
ADC_InitSturct.ADC_Mode=ADC_Mode_Independent;
ADC_InitSturct.ADC_DataAlign=ADC_DataAlign_Right;
ADC_InitSturct.ADC_ExternalTrigConv=ADC_ExternalTrigConv_None;
ADC_InitSturct.ADC_ContinuousConvMode=DISABLE;
ADC_InitSturct.ADC_ScanConvMode=DISABLE;
ADC_InitSturct.ADC_NbrOfChannel=1;
ADC_Init(ADC1,&ADC_InitSturct);
//中断、模拟看门狗可在此配置
//开关控制 ADC_CMD
ADC_Cmd(ADC1,ENABLE);
//校准
ADC_ResetCalibration(ADC1);
while(ADC_GetCalibrationStatus(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);//大约等待6.5微秒
//读取数据
return ADC_GetConversionValue(ADC1);
}
//main.c代码
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "OLED.h"
#include "AD.h"
uint16_t ADValue;
float Voltage;
int main(void)
{
OLED_Init();
AD_Init();
OLED_ShowString(1,1,"ADValue:");
OLED_ShowString(2,1,"Voltage:0.00v");
while(1)
{
ADValue=AD_GetValue();
Voltage=(float)ADValue/4095*3.3;
OLED_ShowNum(1,9,ADValue,4);
OLED_ShowNum(2,9,Voltage,1);
OLED_ShowNum(2,11,(uint16_t)(Voltage*100)%100,2);
Delay_ms(100);
}
}