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);
        
    }
}