文章目录

  • ADC简介
  • 逐次逼近型ADC
  • ADC框图
  • 转换模式
  • 数据对齐
  • 转换时间
  • 校准
  • ADC基本结构
  • ADC单通道工程
  • 代码:
  • ADC简介

    STM32的ADC(Analog-Digital Converter)模拟-数字转换器是一种逐次逼近型模拟数字转换器,可以将引脚上连续变化的模拟电压转换为内存中存储的数字变量,建立模拟电路到数字电路的桥梁。拥有18个输入通道,可测量16个外部通道和2个内部信号源。各通道的A/D转换可以单次、连续、扫描或间断模式执行。 ADC的结果可以左对齐或右对齐方式存储在16位数据寄存器中。

    模拟看门狗特性允许应用程序检测输入电压是否超出用户定义的高/低阀值。

    输入电压范围:0-3.3V,转换结果范围:0~4095

    在STM32F103C8T6 ADC资源:ADC1、ADC2,10个外部输入通道

    逐次逼近型ADC


    这个一个经典的逐次逼近型ADC,有8个输入通道,会在通道选择开关进行选择,通过地址锁存和译码进行锁定要输出的信号。利用ADDA,ADDB,ADDC进行锁存,ALE进行译码。

    接着到比较器,它将输入信号与DAC(数值模拟转换器)的输出进行比较,在开始转换之前,DAC会输出一个初始值,然后与输入信号进行比较,比较结果会被送到一个控制逻辑电路上,控制逻辑电路根据比较结果调整ADC的输出值,这个过程会重复进行,直到ADC的输出与输入信号精度足够接近。每次调整DAC的输出,都使其更加接近于输入信号的值。当DAC的输出与输入信号的差异在可接受范围内时,转换结束。

    逐次逼近型寄存器就是将调整DAC输出的值,通过二分查找的方法,找到接近输入信号的值

    最后将最终值放入三态锁存寄存器,就可以进行输出了。

    上面的CLOCK是ADC的时钟,通过它可以控制ADC的运行速度和转换精度。由于转换需要一定时间,可通过它控制转换速度。还可以实现与外部时钟同步。

    START是运行控制位,EOC是转换结束标志位。

    ADC框图



    我们先从输入口看,大体上与传统的逐次逼近型ADC无差异,这里有16个外部通道和两个内部资源通道。接着会通过数据选择器,可以到注入通道或者规则通道。

    注入通道最多可以有4个输入通道涌入,而规则通道可以有16个输入通道涌入
    这里的模拟数字转换器原理就是逐次逼近型ADC的原理。

    对于规则通道寄存器,只能存储一个结果,所以如果有多个通道进行转换的话,那么先存储的结果会被后来的结果覆盖过去,这有可能造成结果丢失;这里的DMA请求就会解决这种后果,通过对寄存器地址的移动,让数据存储在不同的地址,这样就不会数据丢失,具体下一章讲解。
    那注入通道就是一次可以存储4个结果,注入通道还有一些具体的内容,这里不展开叙述。
    ADCCLK就是时钟,可控制采样时间和转换时间;

    最后汇集到地址数据总线上,进行输出。

    左下角是触发转换的部分,对应逐次逼近型的START信号;对于STM32,有两种触发方式,一种是软件触发,通过在程序中进行编写代码,进行启动;另一种是硬件触发,就是图中的触发源;有定时器各个通道和定时器主模式的输出,还有外部中断引脚触发转换。

    模拟看门狗会根据比较的结果,在一定范围内进行判断,一旦超出所在范围,那么将会产生看门狗事件;

    转换结束后,规则通道的信号和注入通道的信号都会产生标志位,标志位可以触发中断使能,使其中断;

    转换模式

    在ADC中,有两种转换模式,可以搭配扫描模式一同使用;
    单次转换模式下, ADC只执行一次转换。连续转换模式中,当前面ADC转换一结束马上就启动另一次转换。扫描模式用来扫描一组模拟通道。

    单转换,非扫描模式

    每一次转换都需要进行一次触发,转换结束后会置出一个结束标志位;当进行下一次转换时,又需要进行重新触发和置出结束标志位。

    连续转换,非扫描模式

    连续转换,只需要在一开始进行转换触发,那么接下来的每一次转换都不需要进行转换触发;
    且转换一次后,会迅速进入下一次转换,每一次EOC会被标志,这里可以理解为转换完成后EOC自动标志了。

    单次转换,扫描模式

    扫描模式会对所选通道都进行扫描,由于是单次转换,后来的通道内容会将前面的通道内容进行覆盖,所以如图中所示,到最后只有通道6的内容进行输出;

    连续转换,扫描模式

    同样的道理,到最后只有通道6的内容会进行输出;
    所以扫描模式都会与DMA进行搭配,让数据不产生丢失的情况

    数据对齐


    对于规则通道来说,输出结果只有12位有效,而数据存储器有16位,所以这里就会产生两种方式进行存储;
    右对齐:数据高位补0,这是我们常用的方式;
    左对齐:数据低位补0,这样操作会使数据扩大16倍;

    转换时间

    AD转换的步骤:采样,保持,量化,编码

    STM32 ADC的总转换时间为:
    TCONV = 采样时间 + 12.5个ADC周期

    例如:当ADCCLK=14MHz,采样时间为1.5个ADC周期
    TCONV = 1.5 + 12.5 = 14个ADC周期 = 1μs

    校准

    ADC有一个内置自校准模式。校准可大幅减小因内部电容器组的变化而造成的准精度误差。在
    校准期间,在每个电容器上都会计算出一个误差修正码(数字值),这个码用于消除在随后的转换
    中每个电容器上产生的误差。
    建议在每次上电后执行一次校准;
    启动校准前, ADC必须处于关电状态超过至少两个ADC时钟周期。

    ADC基本结构


    通过输入端口到AD转换器,AD转换器需要触发控制和时钟进行初始化。转换结束后会产生标志位;接着将数据结果储存到AD数据寄存器中。该结构需要开关进行控制启动。

    ADC单通道工程

    接线方式:

    通过对电位器的旋转,在OLED显示屏上显示数字转换后的结果。

    代码:

    OLED代码所取处

    AD.h

    #ifndef __AD_H__
    #define __AD_H__
    
    void AD_Init();
    uint16_t AD_GetValue();
    
    #endif
    
    

    AD.c

    #include "stm32f10x.h"                  // Device header
    
    
    void AD_Init()
    {
    	//开启外设时钟
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE);
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
        //配置ADC时钟
        RCC_ADCCLKConfig(RCC_PCLK2_Div6);  // 72M/6=12MHz
    	//引脚初始化
        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规则通道配置其序列器对应等级和采样时间
        ADC_RegularChannelConfig(ADC1,ADC_Channel_0,1,ADC_SampleTime_55Cycles5);
        //ADC结构体成员
        ADC_InitTypeDef ADC_InitStructure;
        ADC_InitStructure.ADC_ContinuousConvMode=DISABLE; //指定通道模式为连续转换或者单转换
        ADC_InitStructure.ADC_DataAlign=ADC_DataAlign_Right; //数据对齐方式
        ADC_InitStructure.ADC_ExternalTrigConv=ADC_ExternalTrigConv_None; //启动规则通道模拟电压到数字转换的外部触发器
        ADC_InitStructure.ADC_Mode=ADC_Mode_Independent; //配置ADC为独立模式或者双模式
        ADC_InitStructure.ADC_NbrOfChannel=1;
        ADC_InitStructure.ADC_ScanConvMode=DISABLE; //选择是否为扫描模式
        ADC_Init(ADC1,&ADC_InitStructure);
        //ADC运行控制
        ADC_Cmd(ADC1,ENABLE);
        //重置所选ADC校准寄存器
        ADC_ResetCalibration(ADC1);
        //获取ADC复位状态,复位后为0
        while(ADC_GetResetCalibrationStatus(ADC1));
        //开始校准
        ADC_StartCalibration(ADC1);
        //获取ADC所选标准位状态,校准需要时间,校准好后置0
        while(ADC_GetCalibrationStatus(ADC1));
    }
    
    uint16_t AD_GetValue()
    {
        //启动ADC软件转换,触发方式
        ADC_SoftwareStartConvCmd(ADC1,ENABLE);
        //检查ADC是否已有标志位,还没有就为SET,有为RESET(EOC)
        while(ADC_GetFlagStatus(ADC1,ADC_FLAG_EOC)==RESET);
        //返回一个转换结果
        return ADC_GetConversionValue(ADC1);
    }
    
    

    main.c

    #include "stm32f10x.h"                  // Device header
    #include "OLED.h"
    #include "AD.h"
    
    float V;
    int main()
    {
    	OLED_Init();
    	AD_Init();
        OLED_ShowString(1,1,"Value:");
        //显示电压
        OLED_ShowString(2,1,"Volatge:0.00");
        while(1)
        {
            V=(float)(AD_GetValue()/4095*3.3);
            OLED_ShowNum(1,7,AD_GetValue(),4);
            OLED_ShowNum(2,9,V,1);
            OLED_ShowNum(2,11,(uint16_t)(V*100)%100,2);
        }
    }
    
    

    数字范围:0-4095
    电压范围:0-3.3V
    对于显示屏上的波动效果,是正常效果。由于转换总时间在1/12*(55.5+12.5)=5.6微妙;
    转换速度是非常快的,而我们又在一个循环中不断显示结果,每次输出结果是由逐次逼近型ADC进行比较输出的,所以不可能每次比较值都非常精准,多多少少会有些误差的波动。

    物联沃分享整理
    物联沃-IOTWORD物联网 » STM32 ADC模数转换详解

    发表评论