锐单电子商城 , 一站式电子元器件采购平台!
  • 电话:400-990-0325

ADC转换汇总(STM32、取平均、精度等)

时间:2022-08-27 14:00:01 ch2m光电传感器lem电流电压传感器la50

目录

一、电流检测ADC采样值处理的高效方法

二、ADC最大和最小的平均算法转换N次采样

三、STM32使用定时器触发ADC转换

四、ADC提高采样精度

五、高精度ADC注意转换设计

-----------------------------------------------------------------------------------------------------

一、电流检测AD采样值处理的高效方法

在编写电机控制软件的过程中,经常需要处理原因AD采样后的电流值。由于电流正负,电流传感器输出地的电压也以0为中点,而且一般AD输入只能是正电压,因此电流传感器的电压量需要通过增加或减少计算电路添加偏移值来输入AD,以保证进入AD值恒为正。

这里AD以TI的2812的片内AD例如,其输入范围为0~3V,电流传感器LEM的LA25NP为例,量程25A,通常使用的电路是将军LEM传感器的输出通过100欧元的电阻接地获得以0为中点的电压信号,然后在输入比例计算电路中添加1.5V的偏移量,这样,在满量范围内输入AD的电压信号始终保持在0~3V之内。当电流为0时送入AD的电压是1.5V

在程序中计算电流时,通常需要AD取回取样结果,然后减去1.5V偏移值,这样到一个符号数,然后计算。

今天在阅读TI在提供电机驱动库代码时,发现采用了高效的处理方法,代码非常简单,如下:

DatQ15 = AdcRegs.ADCRESULT0^0x8000;

2812的AD是12位的,AD采样结果存储在高12位。AD满量程时,ADCRESULT0中的值是0xfff0。

这个代码只是通过一个按位异或操作来计算的AD的值减去了1.5V偏移,变成符号数。

至于具体的原因,例如,当电压为3时V采样值为0xfff0、异位或运算后高位1变为0,其余不变,结果为7ff0.如果将最高位视为符号位,则有效位为11位。

-----------------------------------------------------------------------------------------------------

二、AD最大和最小的平均算法转换N次采样

  1. #include "STC15.H"
  2. #include "delay.h"
  3. #include "STCAD.H"
  4. #include "IO.C"

    void AD_Init() //AD初始化
    {
    P1M1=0xF0; //设置相应的I/O口为高阻 P1.4-P1.5-P1.6-P1.7
    P1M0=0x00;
    ADC_RES=0;
    ADC_RESL=0; //ADC寄存器清零转换结果
    P1ASF=0xF0; //设置相应的I/O口为ADC模拟通道 P1.4-P1.5-P1.6-P1.7
    ADC_CONTR |= ADC_POWER; //打开AD转换电源
    ADC_CONTR |= ADC_SPEEDH;//设置AD转换速度
    delay(1);
    }

    uint ADC_result(uchar x) //AD转换结果
    {
    uint result;
    ADC_CONTR &= 0xF8; //清通道
    ADC_CONTR |= x; ///切换通道,x为通道,如x=5,就是P1.5
    delay_us(30); ///开关通道延迟
    ADC_CONTR |= ADC_START; //开启AD转换
    delay_us(4);
    while(!(ADC_CONTR & ADC_FLAG)); //等待AD转换结束
    ADC_CONTR &= ~ADC_FLAG; //清除AD标志位转换结束
    result = ADC_RES << 2; //ADC高8位左移2位
    result = result | ADC_RESL; ///合成10位转换结果
    return result; //返回转换结果
    }

    uint U(uchar x) ///40次测量电压去除最大最小平均值
    {
    uint U[40],min,max,S;
    uchar i;

    for(i=0;i<40;i )
    {
    U[i]=ADC_result(x); //获取x通道ADC结果
    }

    for(i=1,min=U[0];i<40;i )
    {
    if(U[i]小于min) min=U[i];
    }//求最小值

    for(i=1,max=U[0];i<40;i )
    {
    if(U[i]>max)max=U[i];
    }///求最大值

    for(i=0,S=0;i<40;i )S =U[i];
    S=S-minmax;
        S /= 38 ;   //减去最大最小求平均
        return S;   //返回计算结果
    }

-----------------------------------------------------------------------------------------------------

三、STM32关于使用定时器触发ADC转换

以STM32 ADC的常规通道为例(注入通道类似):

配合上ADC外设的框图:

如上图,STM32 ADC的常规通道可以由以上6个信号触发任何一个,我们以使用TIM2_CH2触发ADC1,独立模式,每次仅测一条通道,则ADC的配置如下:(以下代码使用STM32固件库V3.5)

void ADC_Configuration(void)

{

    ADC_InitTypeDef ADC_InitStructure;

    ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;

    ADC_InitStructure.ADC_ScanConvMode = DISABLE;    //关闭通道扫描模式

    ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;

//注意不要使用持续转换模式,否则只要触发一次,

//后续的转换就会永不停歇(除非CONT清0),这样第一次以后的ADC,就不是由TIM2_CC2来触发了

    ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T2_CC2;   //配置TIM2_CC2为触发源

    ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;

    ADC_InitStructure.ADC_NbrOfChannel = 1;

    ADC_Init(ADC1, &ADC_InitStructure);

    RCC_ADCCLKConfig(RCC_PCLK2_Div6);   //配置时钟(12MHz),在RCC里面还应配置APB2=AHB时钟72MHz,

    ADC_RegularChannelConfig(ADC1, ADC_Channel_8, 1, ADC_SampleTime_1Cycles5);  

    ADC_Cmd(ADC1,ENABLE);

    ADC_ResetCalibration(ADC1);

    while(ADC_GetResetCalibrationStatus(ADC1));

    ADC_StartCalibration(ADC1);   //Start Calibration register

    while(ADC_GetCalibrationStatus(ADC1));   //waiting for finishing the calibration

    ADC_ExternalTrigConvCmd(ADC1, ENABLE);

//设置外部触发模式使能(这个“外部“其实仅仅是相对于ADC模块的外部,实际上还是在STM32内部)

}

这里再注意一点上面左图最顶上的那句话:当外部触发信号被选为ADC规则或注入转换时,只有它的上升沿可以启动转换。这跟下面的定时器2的正确配置关系很大。

void TIM2_Configuration(void)

{

    TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;

    TIM_OCInitTypeDef TIM_OCInitStructure;

    TIM_TimeBaseStructure.TIM_Period = 10000;   //设置100mS一次TIM2比较的周期

    TIM_TimeBaseStructure.TIM_Prescaler = 719;   //系统主频72M,这里分频720,相当于100K的定时器2时钟

//采集时间 = TIM_Period/(系统主频/TIM_Prescaler) = 10000/(72*10^6/720) = 100mS

    TIM_TimeBaseStructure.TIM_ClockDivision = 0x0;

    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;

    TIM_TimeBaseInit(TIM2, & TIM_TimeBaseStructure);

    TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;   //下面详细说明

    TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;//TIM_OutputState_Disable;

    TIM_OCInitStructure.TIM_Pulse = 5000;   //TIM_Pulse < TIM_Period,也可直接置入10000,TIM_Period = TIM_Pulse

    TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low;    //如果是PWM1要为Low,PWM2则为High

    TIM_OC2Init(TIM2, & TIM_OCInitStructure);

    TIM_Cmd(TIM2, ENABLE);

    TIM_InternalClockConfig(TIM2);

    TIM_OC2PreloadConfig(TIM2, TIM_OCPreload_Enable);

    TIM_UpdateDisableConfig(TIM2, DISABLE);

}

还是来引用参考手册的原图:(截图引自通用定时器一章)

上图中红蓝两个框中间部分,顶上是TIM2自动重装寄存器和计数器寄存器,下面4个Capture/compare x register是TIM2_CCRx寄存器。

要使用TIM2的CC2来触发ADC,看懂这个图是关键。

首先要明确,这个图的红框部分和蓝框部分,是不会同时工作的,红框是配置为输入捕捉模式才能生效,蓝框是配置为输出比较模式才能生效,通过配置TIM2_CCMR1_CC2S来控制TIM2_CC2究竟是处于哪种模式(CC2S=0为比较输出,>0为输入捕捉),请注意:这里蓝框的其中一个输出是TIMx_CH2,而TIM2_CH2又是ADC规则通道的触发源,也就是说如果要触发ADC,则需要每次比较匹配时,在TIM2_CH2上产生一次上升沿。

那么我们首先需要操作蓝框内的最左边部分也就是OC2REF,要使比较匹配时发生一次上升沿,(以定时器向上计数为例)就需要在TIM2_CNT时,通道2为低电平,TIM2_CNT>=TIM2_CCR2时,通道2为高电平。

从参考手册定时器一章4.7节的CCMR1寄存器中的0C2M[2:0]的介绍可以看出来,只有在PWM模式才能满足上面所说的条件,任何单纯的冻结、配置OC2REF为高或者为低、强制OC2REF为高或者为低,都无法满足要求,不少同学就是死在这个上面,以为是配置TIMING模式,实际上这样根本无法改变OC2REF的电平,就无从触发ADC了。

CCMR1_CCxS(x为1、2、3、4,决定是哪个通道)是选择为捕捉输入还是比较输出,这里我们需要配置为输出。

以上两段配置程序,可以以100ms的周期驱动AD转换一次,不再需要使用TIM和ADC中断资源。

总结:想要使用STM32的定时器触发ADC,必须将定时器配置为比较输出PWM模式,并且一定要注意TIMx_CHx输出上升沿才触发,若是在比较匹配的瞬时产生的不是上升沿而是下降沿,那么就不一定是在比较匹配的瞬间触发ADC了,特别是在类似于电机控制的应用中要注意这一点。

-----------------------------------------------------------------------------------------------------

四、AD过采样提高采样精度

过采样技术是一种以牺牲采样速度来提高ADC分辨率的技术。如果STM32的12位AD,每秒采集10个数据,即采样率为:10/秒。根据过采样技术,每提高1位ADC分辨率,需要增加4倍的采样率。从12位AD提高到14位AD,一共提高了2位,所以需要把采样率提高2 * 2 * 2 * 2 = 16倍。原来在100mS之内只采集一个数据,现在需要在100mS之内采集16个数据了。然后,我们把这16个数据累加,再把累加值右移2位,这样就得到STM32过采样之后的14位ADC。

需要注意的是,过采样技术会限制输入信号的频率。根据采样定律,采样率最少是输入信号的2倍才能将信号还原。当需要提高n位的ADC分辨率时,采样率又得提高4*n倍。STM32的12位ADC的最高采样率为1MHz,如果要达到14位的ADC分辨率,那么输入信号的频率就不能超过:1M/2/15 = 31.25KHz。

最后提醒:分辨率的提升到14位并不是精度也能提升14位。我自己试过提升到16位的分辨率,但是精度大概只有13、14位的样子。

STM32的精度不可能提高的太多,要提高只能在分辨率上想办法,提高分辨率间接提高精度,但是这是由一个度的,跟你的要采样的外部信号的频率、CPU的处理速度等等都是有关系的。 过采样只能提高分辨率,精度不是随便可以提高的。要不然0832不就能替代所有的AD芯片了。 

精度通常是指准确度。指测量值与实际值的差异性。影响精度的因素很多。如分辨力,线性度等。 

分辨率可以通过分辨力来理解。8bit的分辨力为1/256,10bit时为1/1024,但实际还要通过量程转换成具体的值,不能没有量纲或单位(量纲与单位是不同的概念)。 

分辨率通常用百分比来表示,而分辨力则用绝对值来表示。“5/256 =0.01953125V”指的是分辨力而不是分辨率。而这样的分辨能力仅仅是指理论能力而不是实际能力。因为实际能力还要包括非线性因素引起“干扰”。 

总结:分辨率容易提升到24位,但是精度能到24位的要求就很高了。市面上的16、24位AD转换芯片一般指的是分辨率,而不是精度。 

STM32的adc如果要使用在精度要求高的地方,如3级电子称、精准计量仪表的话,stm32就比较勉强了。建议换外置的ADC。

到底怎样使用过采样法来提高AD采样精度?以下的思路使用于任何单片机: 

比如设个定时器每个10us触发下STM32的ADC的采用,采到256个后将256个数据累加求和,如果当12位ADC用就除以256,13位用除以128,14位用除以64,15位用除以32,16位用除以16。得到结果后存放缓冲区中,再增加一段软件滤波程序就OK了! 

例如下面这段程序:

#define  VccTmpAdcVal   16384//14位ADC

VREF_VAL=VccVal*ADC_FilterChannel[inrefv]/VccTmpAdcVal ; //内部参考电压对应的电压值  VREF_VAL=3.3*内部基准电压的十六进制ADC值/16384

-----------------------------------------------------------------------------------------------------

五、高精度ADC转换设计注意

该模数ADC转换芯片使用的是MCP3221,关心的几个重要参数:

(1)分辨率12bit,高精度,满足大多数场合

(2)误差INL : ±2LSB(Integral Nonlinearity:积分非线性) ; DNL : ±1LSB(Differential Nonlinearity:微分非线性) ,主要看微分非线性这个参数

(3)Sampling switch resistor : Rs = 1K (内部采样的开关电阻)

(4)输入范围( VSS-0.3 ~ VDD+0.3 )V

第一个注意:

分辨率是12bit(2^12=4096),误差INL:±2LSB  ;     DNL :±1LSB ,为了后续更好的计算,VREF选择4.096V的一个基准电压源,这样INL:±2LSB = ±2mV    DNL:±1LSB = ±1mV,I2C读取到的数据,就不需要进行换算了,读出来的值直接是电压值,单位是mV(如果要换算,就涉及到除法运算,除不尽的时候,就会给结果带进了误差)。

第二个注意:

ADC内部采样的开关电阻Rs = 1K, 阻抗比较小,所以要求外部的输入阻抗Rss要比这个值小得多,小到认为可以忽略外部的输入阻抗,这样采集到的电压才更精准。

如何保证输入的阻抗极小呢?

一般在输入前端加运放跟随,做一级隔离缓冲处理,因运放具有输入阻抗极高,闭环时输出阻抗极小的特点。如上图,在MCP3221模拟输入前端加一级运放跟随WS72551EA-5/TR

此时需要考虑第三个注意:

运放的选择,如果要求测试的结果要达到文档上所标注的误差范围在±1mV内,那么选择运放时就有所考虑了,而不是随便选一个运放就行。这里看下WS72551EA-5/TR运放这个参数:

(1)首先尽量选择较小的失调电压Offset Voltage ,要在uV级别,如果这个参数在mV级别,那么测试结果与实际值会偏差比较大,根本达不到文档所说的  DNL:±1LSB = ±1mV内。

(2)偏置电流也选小点的,尽量选在pA级别,这样就保证该运放输入的阻抗非常高,比如输入的信号电压5V, 其输入阻抗 Z = Vs / IB = 5(V) / 10(pA) = 500GΩ,运放的输入阻抗越高,对前级电路的影响就越可以忽略不计。

满足以上几个要求,测试出来的精度肯定是跟文档描述的一致。

-----------------------------------------------------------------------------------------------------

锐单商城拥有海量元器件数据手册IC替代型号,打造电子元器件IC百科大全!

相关文章