ADC转换汇总(STM32、取平均、精度等)
目錄
一、電流檢測ADC采樣值處理的高效方法
二、ADC轉換N次采樣去最大最小求平均算法
三、STM32關于使用定時器觸發ADC轉換
四、ADC過采樣提高采樣精度
五、高精度ADC轉換設計注意
附錄1、LSB
------------------------------------------------------------------------------------------------------------------------
一、電流檢測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的偏移,并變成了有符號數。
至于具體為什么,舉例說明,當電壓為3V時,采樣值是0xfff0,異或運算后高位的1變成了0,其余位不變,其結果是7ff0,如果將最高位看做符號位,那么有效位是11位。
------------------------------------------------------------------------------------------------------------------------
二、AD轉換N次采樣去最大最小求平均算法
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轉換結果寄存器清0
????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-min-max;
????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
------------------------------------------------------------
1、第一個注意
分辨率是12bit(2^12=4096),誤差INL:±2LSB,DNL:±1LSB。為了后續更好的計算,VREF選擇4.096V的一個基準電壓源,這樣INL:±2LSB = ±2mV,DNL:±1LSB = ±1mV,I2C讀取到的數據,就不需要進行換算了,讀出來的值直接是電壓值,單位是mV(如果要換算,就涉及到除法運算,除不盡的時候,就會給結果帶進了誤差)。
------------------------------------------------------------
2、第二個注意
ADC內部采樣的開關電阻Rs = 1K, 阻抗比較小,所以要求外部的輸入阻抗Rss要比這個值小得多,小到認為可以忽略外部的輸入阻抗,這樣采集到的電壓才更精準。
如何保證輸入的阻抗極小呢?
一般在輸入前端加運放跟隨,做一級隔離緩沖處理,因運放具有輸入阻抗極高,閉環時輸出阻抗極小的特點。如上圖,在MCP3221模擬輸入前端加一級運放跟隨WS72551EA-5/TR(SOT-23-5)。
------------------------------------------------------------
3、此時需要考慮第三個注意
運放的選擇,如果要求測試的結果要達到文檔上所標注的誤差范圍在±1mV內,那么選擇運放時就有所考慮了,而不是隨便選一個運放就行。這里看下WS72551EA-5/TR運放這個參數:
(1)首先盡量選擇較小的失調電壓Offset Voltage ,要在uV級別,如果這個參數在mV級別,那么測試結果與實際值會偏差比較大,根本達不到文檔所說的? DNL:±1LSB = ±1mV內。
(2)偏置電流也選小點的,盡量選在pA級別,這樣就保證該運放輸入的阻抗非常高,比如輸入的信號電壓5V, 其輸入阻抗 Z = Vs / IB = 5(V) / 10(pA) = 500GΩ,運放的輸入阻抗越高,對前級電路的影響就越可以忽略不計。
滿足以上幾個要求,測試出來的精度肯定是跟文檔描述的一致。
-----------------------------------------------------------------------------------------------------------------------
附錄1、LSB
Articles on Internet and books show how to calculate the Least Significant Bit (LSB), but they take into consideration either the voltage reference (Vref) or the full scale (FS) of the ADC or DAC. ?Many times this leads to confusion, as a few messages I received from my readers show. Therefore, this article shows both ways of defining the LSB, so that people will have a clear understanding how to treat an ADC’s (Analog-to-Digital-Converter) or DAC’s (Digital-to-Analog-Converter) LSB.
What is an LSB? The LSB is the smallest level that an ADC can convert, or is the smallest increment a DAC outputs. ?Both converters are used at the boundaries between the analog and digital realms, making it possible for the analog circuits to talk to the digital ones and backwards.
增益誤差是數據轉換器的增益誤差,代表實際傳輸函數的斜率與理想傳輸函數的斜率的差別。
增益誤差通常用LSB或滿量程范圍的百分比表示。增益誤差可以利用硬件或軟件校準,是滿量程誤差減去失調誤差。
失調誤差是指在輸入為零電壓時,采集獲得的數字量并不為零,它與理想轉移函數的零點總是差一個固定的量,這個量就是失調誤差。失調誤差是由信號調理電路、ADC內部轉移電路和電源電壓等因素造成的。
LSB(LeastSignificant Bit)意為最低有效位;MSB(MostSignificant Bit)意為最高有效位,若MSB=1,則表示數據為負值,若MSB=0,則表示數據為正。
當選擇模數轉換器(ADC)時,最低有效位(LSB)這一參數的含義是什么?有位工程師告訴我某某生產商的某款12位轉換器只有7個可用位。也就是說,所謂12位的轉換器實際上只有7位。他的結論是根據器件的失調誤差和增益誤差參數得出的,這兩個參數的最大值如下:
失調誤差 =±3LSB,
增益誤差 =±5LSB,
乍一看,覺得他似乎是對的。從上面列出的參數可知最差的技術參數是增益誤差(±5 LSB)。進行簡單的數學運算,12位減去5位分辨率等于7位,對嗎?果真如此的話,ADC生產商為何還要推出這樣的器件呢?增益誤差參數似乎表明只要購買成本更低的8位轉換器就可以了,但看起來這又有點不對勁了。正如您所判斷的,上面的說法是錯誤的。
讓我們重新來看一下LSB的定義。考慮一個12位串行轉換器,它會輸出由1或0組成的12位數串。通常,轉換器首先送出的是最高有效位(MSB)(即LSB + 11)。有些轉換器也會先送出LSB。在下面的討論中,我們假設先送出的是MSB(如圖1所示),然后依次送出MSB-1 (即 LSB + 10)和MSB -2(即LSB + 9)并依次類推。轉換器最終送出MSB -11(即LSB)作為位串的末位。
LSB這一術語有著特定的含義,它表示的是數字流中的最后一位,也表示組成滿量程輸入范圍的最小單位。對于12位轉換器來說,LSB的值相當于模擬信號滿量程輸入范圍除以212 或 4,096的商。如果用真實的數字來表示的話,對于滿量程輸入范圍為4.096V的情況,一個12位轉換器對應的LSB大小為1mV。但是,將LSB定義為4096個可能編碼中的一個編碼對于我們的理解是有好處的。
讓我們回到開頭的技術指標,并將其轉換到滿量程輸入范圍為4.096V的12位轉換器中:
失調誤差 = ±3LSB =±3mV,
增益誤差 =±5LSB = ±5mV,
這些技術參數表明轉換器轉換過程引入的誤差最大僅為8mV(或 8個編碼)。這絕不是說誤差發生在轉換器輸出位流的LSB、LSB-1、LSB-2、LSB-3、LSB-4、LSB-5、LSB-6和 LSB-7 八個位上,而是表示誤差最大是一個LSB的八倍(或8mV)。準確地說,轉換器的傳遞函數可能造成在4,096個編碼中丟失最多8個編碼。丟失的只可能是最低端或最高端的編碼。例如,誤差為+8LSB ((+3LSB失調誤差) + (+5LSB增益誤差)) 的一個12位轉換器可能輸出的編碼范圍為0 至 4,088。丟失的編碼為4088至4095。相對于滿量程這一誤差很小僅為其0.2%。與此相對,一個誤差為-3LSB((-3LSB失調誤差)(-5LSB增益誤差))的12位轉換器輸出的編碼范圍為3至4,095。此時增益誤差會造成精度下降,但不會使編碼丟失。丟失的編碼為0、1和2。這兩個例子給出的都是最壞情況。在實際的轉換器中,失調誤差和增益誤差很少會如此接近最大值。
在實際應用中,由于ADC失調或增益參數的改進而使性能提升的程度微不足道,甚至可以忽略。但是,對于那些將精度作為一項設計目標的設計人員來說,這種假設太過絕對。利用固件設計可以很容易地實現數字校準算法。但更重要的是,電路的前端放大/信號調理部分通常會產生比轉換器本身更大的誤差。
?MSB指二進制中最高值的比特。在16比特的數字音頻中,其第1個比特便對16bit的字的數值有最大的影響。例如,在十進制的15389這一數字中,相當于萬數那1行(1)的數字便對數值的影響最大;比較與之相反的“最低有效位”(LSB)。
總結:
“精度”是用來描述物理量的準確程度,其反應的是測量值與真實值之間的誤差;而“分辨率”是用來描述刻度劃分的,其反應的是數值讀取過程中所能讀取的最小變化值。
ADC的分辨率=測量電壓范圍/(2^AD位數-1),精度取決于LSB失調誤差與增益誤差。
-----------------------------------------------------------------------------------------------------------------------
總結
以上是生活随笔為你收集整理的ADC转换汇总(STM32、取平均、精度等)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 设置input隐藏并用js控制显示和隐藏
- 下一篇: Apollo简易制作地图