2020年9月4日 星期五

ADC two point calibration

使用MCU時常會有不準確的問題造成量測不精準的狀況可以透過兩點式校正ADC的方法ADCGain errorOffset error校正回來,取得需要的精確度。

要進行ADC兩點校正方法不難,首先在MCU的部分需要有VREF輸入可以使用,在不透過人工使用Calibration Source的情況下,利用ATL431B Grade(0.5%)輸出2.5V(VREF)ADC參考電壓,然後再利用ATL431輸出的2.5V電壓做90%*VREF10%*VREF兩個電壓點分別進入AN0AN1,利用AN0AN1兩點電壓做校正,假設ADC的解析度為12 bit2點校正實際方式如下:

/*

VREF = 2.5V

The two calibration points are chosen at V1 = 2.5*10k/(10k+100k); V2 = 2.5*100k/(10k+100k)

The ideal ADC output values at V1 and V2 are represented as Ci1 and Ci2.

Ci1 = V1 * 4096 / 2.5 = 372; Ci2 = V2 * 4096 / 2.5 = 3724

Assume Ca1 = 404, Ca2 = 3847

The actual ADC output values at V1 and V2 are represented as Ca1 and Ca2.

The gain and offset error will be calculated using the equation of a straight line     y = mx + b, Where m is the slope of the line and b is the offset.

The gain error can be calculated as the slope of the actual ADC output divided by the slope of the ideal ADC output.

Gain Error = (Ca2 – Ca1) / (Ci2 – Ci1) = (3847 – 404) / (3724 – 372) = 1.027(positive gain error)

b = y – mx

Offset error = Cal – (Gain error * Ci1) = 404 – (1.027 * 372) = 22(positive offset error)

GAINCORR(Gain correction) = 4096 / Gain error = 4096 / 1.027 = 3988

OFFSETCORR = offset error = 22

Adc result = (Conversion value – OFFSETCORR) * (GAINCORR/4096)

Ca1 = (404 – 22) * (3988 / 4096) = 372

Ca2 = (3847 – 22) * (3988 / 4096) = 3724

*/    

#define CI1 372

#define CI2 3724

 unsigned long int Ca1, Ca2;

long int Ci1 = CI1, Ci2 = CI2;

unsigned int GainError;

int OffsetError;

       

Ca1 = Adc_Read(ACS_AN1, VBG_DIS);

Ca2 = Adc_Read(ACS_AN2, VBG_DIS); 

       

/* y = mx + b, m = slope = (y2-y1) / (x2-x1), y2 = Ca2, y1 = Ca1, x2 = Ci2, x1 =  Ci1*/

GainError = (unsigned int)(((Ca2-Ca1) << 12) / (Ci2 - Ci1)); // scale to 4096

/* b = y - mx */

OffsetError = (int)(Ca1 - (Ci1 * GainError >> 12));

OffsetCorr = OffsetError;

       

/* GainCorr = 4096 * (1/GainError) = 4096 * 4096 / GainError */

GainCorr = (unsigned int)(4096ul * 4096 / GainError);


void MeasureVoltage(void)

{

        static unsigned int SumOfMovAvg = 0;

        static unsigned int MovAvg_Buffer[8] = {0};  // Moving average buffer

        static unsigned char Index = 0;                       // Moving average index

        unsigned char cnt = 0;

        unsigned long int Temp;

    unsigned int result;

               

    MovAvg_Buffer[Index++] = Adc_Read(ACS_AN0, VBG_DIS);

        if(Index == 8)

        {

                Index = 0;

                FLAGbits.MovingAvgOutput = 1;

        }

       

        SumOfMovAvg = 0;

        if(FLAGbits.MovingAvgOutput)

        {

                for(cnt = 0; cnt < 8; cnt++)

                        SumOfMovAvg += MovAvg_Buffer[cnt];                                       

                Temp = (SumOfMovAvg >> 3);

        }

        else

        {

                for(cnt = 0; cnt < Index; cnt++)

                        SumOfMovAvg += MovAvg_Buffer[cnt];                                       

                Temp =  MovAvg_Buffer[Index-1]; //Temp = (SumOfMovAvg / Index);     

        }      

        result = (unsigned int)((unsigned long int)(Temp - OffsetCorr) * GainCorr >> 12);

        // result is the ADC output after two point calibration

}

STM32於IAR 9.3以後的版本將uart導向至printf

首先,請先參考如以下IAR提供的"在IAR Embedded Workbench中实现打印输出技術資料" https://www.iar.com/cn/knowledge/support/technical-notes/general/implementing-printf-ou...