STM32 ADC模块详解及应用指南

stm32ADC:

  • STM32ADC简介:
  • 逐次逼近型ADC原理(以ADC0809为例):
  • 输入通道选择:
  • AD转换:
  • 逐次逼近转换过程:
  • 输出:
  • 其他:
  • STM32ADC:
  • 框图:
  • 规则组与注入组:
  • 规则组:
  • 注入组:
  • 模拟看门狗:
  • ADC基本结构:
  • 输入通道:
  • 双ADC(待续):
  • 转换模式:
  • 扫描模式:
  • 间断模式模式(待续):
  • 单次转换模式:
  • 连续转换模式:
  • 实例
  • 触发控制:
  • 数据对齐:
  • 转换时间:
  • 校准:
  • ADC配置实例:
  • 实例:
  • STM32ADC简介:

    • ADC(Analog-Digital Converter)模拟-数字转换器
    • ADC可以将引脚上连续变化的模拟电压转换为内存中存储的数字变量,建立模拟电路到数字电路的桥梁。[^1]

    • ADC(模拟-数字转换器)是模拟到数字的桥梁。
    • DAC(数字 — 模拟转换器):可以将数字变量转换为模拟电压,适用在波形生成等领域。
    • PWM:PWM也可以将数字变量转换为模拟电压,在某些情况下可以代替DAC,但同时PWM只有完全导通和完全断开两种状态,在两种状态下没有功率损耗,所以直流电机调速等大功率场合下,适用PWM。

    • 12位逐次逼近型ADC,1us转换时间。

    • 分辨率:一般用多少位来表示,12位AD值,它的表示范围就是0一2^12-1,量化结果的范围是0一4095。位数越高,量化结果越精细,对应分辨率越高

    • 输入电压范围:0一3.3V,转换结果范围:0一4095。

    ADC的输入电压,一般是要求在芯片供电的正负极之间变化的

    • 18个输入通道,可测量16个外部和2个内部信号源

    • 16个外部信号源:16个GPIO口,在引脚上直接接模拟信号,不需要任何外部电路,引脚直接测量电压。
    • 2个内部信号源:内部温度传感器和内部参考电压

    • 内部温度传感器:温度传感器可以测量CPU的温度。
    • 内部参考电压: 内部参考电压是一个1.2v的基准电压,这个基准电压是不随外部供电电压变化而变化的。所以>>如果你的芯片供电电压不是标准的3.3v,那外部电压的测量的电压可能不准。这时就可以读取这个基准电压进>>行校准,就可以得到正确的电压值。

    • 规则组和注入组两个转换单元
    • 模拟看门狗自动监测输入电压范围

    • 模拟看门狗可以检测指定的某些通道,当AD值高于它设定的上阈值或低于下阈值时,它就会申请中断,就可以直接在中断函数里执行操作,无需手动取值,进行判断。

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

    逐次逼近型ADC原理(以ADC0809为例):

    请添加图片描述

    输入通道选择:

    • IN0~IN7:八路选择通道,通过通道选择开关,输入到AD转换部分进行转换。
    • 地址锁存和译码:把通道号放在这ADDA~ADDC三个引脚上,再锁存,就可以打开对应通道。

    ADC转换是一个很快的过程,给一个开始信号,几us就可以转换完成。所以,如果想转换多个信号,不必设计多个AD转换器,只要设计一个AD转换器加一个多路选择开关就行了。

    STM32有18个输入通道,对应到这里,就是一个18路输入的多路开关。

    AD转换:

    • 比较器:它可以判断两个输入电压的大小关系,输出高低电平指示谁大谁小。它的两个输入端,一个是待测的电压,另一个是DAC的电压输出端。
    • DAC: 给它一个数据,它就可以输出数据对应的电压。DAC内部是使用加权电阻网络实现的转换,详见(待续)。
    • 逐次逼近寄存器SAR:负责电压调节(也就是DAC的输入)。

    逐次逼近转换过程:

    请添加图片描述


    为了最快找到未知电压的编码,通常我们会使用二分法来寻找:比如这里是8位为的ADC,那编码就是0~255,第一次比较的时候,我们给DAC输入255的一半,进行比较,那就是128,然后再看谁大谁下,如果DAC电压大了,第二次比较的时候,就再给128的一半64,如果还大,第三次比较的时候,给32,如果这次DAC电压小了,那四次就给64-32中间的值,这样依次继续下去,就可以得到电压的编码。把这个过程用二进制表示,就可以发现,这些数是二进制数的每一位的位权,这个判断过程,相当于是对二进制数从高位到低位依次判断是一还是零的过程。
    • 对于8位的ADC,从高位到低位依次判断八次就可以找到未知电压的编码了,对于12位的ADC,就需要判断12次。

    输出:

    • 八位三态锁存缓冲器: 在AD转换结束后,通过这里输出,八位有八个输出,十二位有十二个输出。

    其他:

    • EOC:转换结束信号。
    • START:开始转换,给一个输入脉冲,开始转换。
    • CLOCK: ADC时钟,因为ADC内部是一位一位判断的,需要时钟的驱动。
    • VREF+和VREF-: DAC和ADC参考电压,决定DAC最大值的对应电压,DAC的参考电压也决定了ADC的输入范围,所以它也是ADC的参考电压。
    • VCC和GND:整个芯片的供电,一般VCC和VREF+接在一起,GND和VREF-接在一起。所以一般情况下,ADC输入电压的范围和ADC的供电是一样的。

    STM32ADC:

    框图:

    • VREF+在内部已接VDDA,VREF-在内部已接VSSA

    ADCCLK来源:

    规则组与注入组:

    • 有16个多路通道。可以把转换组织成两组:规则组和注入组。在任意多个通道上以任意顺序进
    行的一系列转换构成成组转换。例如,可以如下顺序完成转换:通道3、通道8、通道2、通道
    2、通道0、通道2、通道2、通道15。
    ● 规则组由多达16个转换组成。规则通道和它们的转换顺序在ADC_SQRx寄存器中选择。规
    则组中转换的总数应写入ADC_SQR1寄存器的L[3:0]位中。
    ● 注入组由多达4个转换组成。注入通道和它们的转换顺序在ADC_JSQR寄存器中选择。注入
    组里的转换总数目应写入ADC_JSQR寄存器的L[1:0]位中。
    如果ADC_SQRx或ADC_JSQR寄存器在转换期间被更改,当前的转换被清除,一个新的启动脉
    冲将发送到ADC以转换新选择的组

    规则组:

    最多可以选中16个通道,通道的转换结果会被覆盖,在一个组转换完成后,只有序列中最后一个通道的转换完成可被读取,所以通常与DMA搭配使用。
    示意图:
    请添加图片描述

    注入组:

    最多可以选中4个通道,通道的转换结果会存放在对应的寄存器里,在一个组转换完成后,每一个通道的转换结果都可以被读取。
    示意图:请添加图片描述

    模拟看门狗:

    里面可以存一个阈值高限和一个阈值低限,如果启动了模拟看门狗,那看门狗就会看住它看门的通道,一旦超过了阈值范围,它就会乱叫,申请一个模拟看门狗中断。

    如果被ADC转换的模拟电压低于低阀值或高于高阀值,AWD模拟看门狗状态位被设置。阀值位
    于ADC_HTR和ADC_LTR寄存器的最低12个有效位中。通过设置ADC_CR1寄存器的AWDIE位
    以允许产生相应中断。
    阀值独立于由ADC_CR2寄存器上的ALIGN位选择的数据对齐模式。比较是在对齐之前完成的

    请添加图片描述

    ADC基本结构:

    • 输入通道: 16个GPIO口外加两个内部通道。
    • AD转换器:里面有两个组,一个规则组,一个注入组,规则组最多可以选中16个通道,注入组最多可以选中4个通道。
    • AD数据寄存器:AD转换器转换后的结果存放在这里,其中规则组只有一个寄存器,注入组有四个。
    • 触发控制:这个提供了START信号,可以选择软件触发和硬件触发。
    • RCC: ADC逐次比较就是由这个时钟驱动的。
    • 模拟看门狗:用于检测转换结果的范围。

    输入通道:

    • c8t6的外部通道只有前十个。(详见这里)
    • 只有ADC1有通道16和17。

    双ADC(待续):

    转换模式:

    扫描模式:

    此模式用来扫描一组模拟通道。
    扫描模式可通过设置ADC_CR1寄存器的SCAN位来选择。一旦这个位被设置,ADC扫描所有被
    ADC_SQRX寄存器(对规则通道)或ADC_JSQR(对注入通道)选中的所有通道。在每个组的每个
    通道上执行单次转换。在每个转换结束时,同一组的下一个通道被自动转换。如果设置了CONT
    位,转换不会在选择组的最后一个通道上停止,而是再次从选择组的第一个通道继续转换。
    如果设置了DMA位,在每次EOC后,DMA控制器把规则组通道的转换数据传输到SRAM中。而
    注入通道转换的数据总是存储在ADC_JDRx寄存器中。

    • 扫描模式主要用于简化对多个模拟通道的连续采样操作。在扫描模式下,ADC能够按照预设的通道顺序自动进行一系列的转换,而无需在每次转换后重新配置通道。

    示意图(以规则组为例,注入组同理):
    请添加图片描述

    间断模式模式(待续):
    单次转换模式:

    单次转换模式下,ADC只执行一次转换。该模式既可通过设置ADC_CR2寄存器的ADON位(只
    适用于规则通道)启动也可通过外部触发启动(适用于规则通道或注入通道),这时CONT位为0。
    一旦选择通道的转换完成:
    ● 如果一个规则通道被转换:
    ─ 转换数据被储存在16位ADC_DR寄存器中
    ─ EOC(转换结束)标志被设置
    ─ 如果设置了EOCIE,则产生中断。
    ● 如果一个注入通道被转换:
    ─ 转换数据被储存在16位的ADC_DRJ1寄存器中
    ─ JEOC(注入转换结束)标志被设置
    ─ 如果设置了JEOCIE位,则产生中断。然后ADC停止。

    • 单次转换模式是一种专用于执行单次ADC转换操作的工作模式,尤其适用于只需从特定模拟通道获取单次数据值的应用场景。
    示意图(以规则组为例):
    请添加图片描述

    连续转换模式:

    在连续转换模式中,当前面ADC转换一结束马上就启动另一次转换。此模式可通过外部触发启
    动或通过设置ADC_CR2寄存器上的ADON位启动,此时CONT位是1。
    每个转换后:
    ● 如果一个规则通道被转换:
    ─ 转换数据被储存在16位的ADC_DR寄存器中
    ─ EOC(转换结束)标志被设置
    ─ 如果设置了EOCIE,则产生中断。
    ● 如果一个注入通道被转换:
    ─ 转换数据被储存在16位的ADC_DRJ1寄存器中
    ─ JEOC(注入转换结束)标志被设置
    ─ 如果设置了JEOCIE位,则产生中断。

    • 连续转换模式允许ADC在无需外部触发的情况下连续不断地进行数据转换。
    请添加图片描述

    实例

    以上的模式可以两两组合使用(扫描模式+连续转换或单次转换模式)下面是一些实例。



    触发控制:

    数据对齐:

    转换时间:

    校准:

    ADC配置实例:

    ADC配置基本步骤:

    第一步:开启GPIO和ADC的RCC时钟并将ADCCLK分配器配置一下。
    第二步:配置GPIO,将需要用到的GPIO配置为模拟输入模式。
    第三步:配置多路开关,将通道接入到规则组列表里。
    第四步:配置ADC转换器。
    第五步:开启ADC。

    ADC时钟配置函数:

    /**
      * @brief  配置ADC时钟(ADCCLK)
      * @param  RCC_PCLK2: 配置ADC的时钟预分频器。 被分频的时钟是APB2时钟(PCLK2)。
      *   该参数可以是下列值之一:
      *     @arg RCC_PCLK2_Div2: ADC时钟 = PCLK2/2
      *     @arg RCC_PCLK2_Div4: ADC时钟 = PCLK2/4
      *     @arg RCC_PCLK2_Div6: ADC时钟= PCLK2/6
      *     @arg RCC_PCLK2_Div8: ADC时钟 = PCLK2/8
      * @retval None
      */
    void RCC_ADCCLKConfig(uint32_t RCC_PCLK2)
    

    ADC规则组通道配置函数:

    /**
      * @brief  设置指定 ADC 的规则组通道,设置它们的转化顺序和采样时间
      * @param  ADCx: x 可以是 1 或者 2 来选择 ADC 外设 ADC1 或 ADC2
      * @param  ADC_Channel: 被设置的 ADC 通道
      *   这个参数可以是下列值之一:
      *     @arg ADC_Channel_0: 选择 ADC 通道 0
      *     @arg ADC_Channel_1: 选择 ADC 通道 1
      *     @arg ADC_Channel_2: 选择 ADC 通道 2
      *     @arg ADC_Channel_3: 选择 ADC 通道 3 
      *     @arg ADC_Channel_4: 选择 ADC 通道 4 
      *     @arg ADC_Channel_5: 选择 ADC 通道 5
      *     @arg ADC_Channel_6: 选择 ADC 通道 6
      *     @arg ADC_Channel_7: 选择 ADC 通道 7
      *     @arg ADC_Channel_8: 选择 ADC 通道 8
      *     @arg ADC_Channel_9: 选择 ADC 通道 9
      *     @arg ADC_Channel_10: 选择 ADC 通道 10
      *     @arg ADC_Channel_11: 选择 ADC 通道 11
      *     @arg ADC_Channel_12: 选择 ADC 通道 12
      *     @arg ADC_Channel_13: 选择 ADC 通道 13
      *     @arg ADC_Channel_14: 选择 ADC 通道 14
      *     @arg ADC_Channel_15: 选择 ADC 通道 15
      *     @arg ADC_Channel_16: 选择 ADC 通道 16
      *     @arg ADC_Channel_17: ADC 选择 ADC 通道
      * @param  Rank: 规则组采样顺序。取值范围 1 到 16。
      * @param  ADC_SampleTime: 指定 ADC 通道的采样时间值(时间越长越稳定)
      *   这个参数可以是下列值之一:
      *     @arg ADC_SampleTime_1Cycles5: 采样时间为 1.5 周期
      *     @arg ADC_SampleTime_7Cycles5: 采样时间为 7.5 周期
      *     @arg ADC_SampleTime_13Cycles5: 采样时间为 13.5 周期
      *     @arg ADC_SampleTime_28Cycles5: 采样时间为 28.5 周期	
      *     @arg ADC_SampleTime_41Cycles5: 采样时间为 41.5 周期	
      *     @arg ADC_SampleTime_55Cycles5: 采样时间为 55.5 周期	
      *     @arg ADC_SampleTime_71Cycles5: 采样时间为 71.5 周期	
      *     @arg ADC_SampleTime_239Cycles5: 采样时间为 239.5 周期	
      * @retval None
      */
    void ADC_RegularChannelConfig(ADC_TypeDef* ADCx, uint8_t ADC_Channel, uint8_t Rank, uint8_t ADC_SampleTime)
    

    ADC初始化函数:

    /**
      * @brief  根据 ADC_InitStruct 中指定的参数初始化外设 ADCx 的寄存器。
      * @param  ADCx: x 可以是 1 或者 2 来选择 ADC 外设 ADC1 或 ADC2。
      * @param  ADC_InitStruct: 指向结构 ADC_InitTypeDef 的指针,包含了指定外设 ADC 的配置信息
      * @retval None
      */
    void ADC_Init(ADC_TypeDef* ADCx, ADC_InitTypeDef* ADC_InitStruct)
    

    ADC初始化结构体:

    typedef struct
    {
      uint32_t ADC_Mode;//设置 ADC 工作在独立或者双 ADC 模式。
      FunctionalState ADC_ScanConvMode;//规定了模数转换工作在扫描模式(多通道)还是单次(单通道)模式。可以设置这个参数为 ENABLE 或者 DISABLE。
      FunctionalState ADC_ContinuousConvMode; //规定了模数转换工作在连续还是单次模式。可以设置这个参数为 ENABLE或者 DISABLE
      uint32_t ADC_ExternalTrigConv;//定义了使用外部触发来启动规则通道的模数转换
      uint32_t ADC_DataAlign;//规定了 ADC 数据向左边对齐还是向右边对齐               
      uint8_t ADC_NbrOfChannel;//规定了顺序进行规则转换的 ADC 通道的数目。           
    }ADC_InitTypeDef;
    

    复位校准函数

    /**
      * @brief  重置指定的 ADC 的校准寄存器
      * @param  ADCx: x 可以是 1 或者 2 来选择 ADC 外设 ADC1 或 ADC2。
      * @retval None
      */
    void ADC_ResetCalibration(ADC_TypeDef* ADCx)
    
    /**
      * @brief  获取 ADC 重置校准寄存器的状态
      * @param  ADCx: x 可以是 1 或者 2 来选择 ADC 外设 ADC1 或 ADC2。
      * @retval ADC 重置校准寄存器的新状态(SET 或者 RESET)。
      */
    FlagStatus ADC_GetResetCalibrationStatus(ADC_TypeDef* ADCx)
    

    校准函数

    /**
      * @brief  开始指定 ADC 的校准
      * @param  ADCx: x 可以是 1 或者 2 来选择 ADC 外设 ADC1 或 ADC2
      * @retval None
      */
    void ADC_StartCalibration(ADC_TypeDef* ADCx)
    
    /**
      * @brief  获取指定 ADC 的校准状态
      * @param  ADCx: x 可以是 1 或者 2 来选择 ADC 外设 ADC1 或 ADC2
      * @retval ADC 校准的新状态(SET 或者 RESET)
      */
    FlagStatus ADC_GetCalibrationStatus(ADC_TypeDef* ADCx)
    

    转换函数

    /**
      * @brief  使能或者失能指定的 ADC 的软件转换启动功能
      * @param  ADCx:x 可以是 1 或者 2 来选择 ADC 外设 ADC1 或 ADC2
      * @param  NewState: 指定 ADC 的软件转换启动新状态这个参数可以取:ENABLE 或者 DISABLE
      * @retval None
      */
    void ADC_SoftwareStartConvCmd(ADC_TypeDef* ADCx, FunctionalState NewState)
    

    标志位读取:

    /**
      * @brief  检查制定 ADC 标志位置 1 与否
      * @param  ADCx: x 可以是 1 或者 2 来选择 ADC 外设 ADC1 或 ADC2
      * @param  ADC_FLAG: 指定需检查的标志位 
      *   This parameter can be one of the following values:
      *     @arg ADC_FLAG_AWD: 模拟看门狗标志位
      *     @arg ADC_FLAG_EOC: 转换结束标志位
      *     @arg ADC_FLAG_JEOC: 注入组转换结束标志位
      *     @arg ADC_FLAG_JSTRT: 注入组转换开始标志位
      *     @arg ADC_FLAG_STRT: 规则组转换开始标志位
      * @retval 指定ADC标志位的最新状态 (SET 或 RESET).
      */
    FlagStatus ADC_GetFlagStatus(ADC_TypeDef* ADCx, uint8_t ADC_FLAG)
    

    转换结果读取

    /**
      * @brief  返回常规通道的最后一次ADCx转换结果数据。
      * @param  ADCx: 其中x可以是1、2或3来选择ADC外设。
      * @retval 转换结果。
      */
    uint16_t ADC_GetConversionValue(ADC_TypeDef* ADCx)
    
    实例:
    void AD_Init()
    {
    开启GPIO和ADC的RCC时钟并将ADCCLK分配器配置一下。//
    	RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE);
    	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
    	
    	RCC_ADCCLKConfig(RCC_PCLK2_Div6); //72M/6=12M
    ///配置GPIO,将需要用到的GPIO配置为模拟输入模式。//	
    	GPIO_InitTypeDef GPIO_InitStruct;
    	GPIO_InitStruct.GPIO_Mode=GPIO_Mode_AIN;
    	GPIO_InitStruct.GPIO_Pin=GPIO_Pin_0;
    	GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
    	GPIO_Init(GPIOA,&GPIO_InitStruct);
    ///配置多路开关,将通道接入到规则组列表里。//		
    	ADC_RegularChannelConfig(ADC1,ADC_Channel_0,1,ADC_SampleTime_55Cycles5);//将通道1放在规则组列表第一个位置里,采样时间为55.5个周期。
    配置ADC转换器。///	
    	ADC_InitTypeDef ADC_InitStructure;
    	ADC_InitStructure.ADC_Mode=ADC_Mode_Independent;//让ADC1工作在独立模式
    	ADC_InitStructure.ADC_DataAlign=ADC_DataAlign_Right;//ADC 数据右对齐
    	ADC_InitStructure.ADC_ExternalTrigConv=ADC_ExternalTrigConv_None;//由软件触发启动
    	ADC_InitStructure.ADC_ContinuousConvMode=DISABLE;//让ADC工作在单次模式
    	ADC_InitStructure.ADC_ScanConvMode=DISABLE;//不使用扫描模式
    	ADC_InitStructure.ADC_NbrOfChannel=1;//在非扫描模式下无效
    	ADC_Init(ADC1,&ADC_InitStructure);//使用参数初始化
    /开启ADC/
    	ADC_Cmd(ADC1,ENABLE);
    /校准
    	ADC_ResetCalibration(ADC1);//开始ADC1复位校准
    	while(ADC_GetResetCalibrationStatus(ADC1) == SET){}//确定ADC1复位校准是否结束
    	ADC_StartCalibration(ADC1);//开始ADC1校准
    	while(ADC_GetCalibrationStatus(ADC1) == SET){}//确定ADC1校准是否结束
    }
    /读取
    uint16_t AD_GetValue()
    {
    	ADC_SoftwareStartConvCmd(ADC1,ENABLE);//开始转换
    	while(ADC_GetFlagStatus(ADC1,ADC_FLAG_EOC)== RESET){}//确定转换是否结束
    	return ADC_GetConversionValue(ADC1);//读取转换结果
    }
    

    作者:冯雪娟_00

    物联沃分享整理
    物联沃-IOTWORD物联网 » STM32 ADC模块详解及应用指南

    发表评论