SAM4E單片機之旅——18、通過(guò)AFEC(ADC)獲取輸入的電壓
很多時(shí)候,一個(gè)電壓不僅僅需要定性(高電平或者低電平),而且要定量(了解具體電壓的數值)。這個(gè)時(shí)候就可以用到模數轉換器(ADC)了。這次的內容是測量開(kāi)發(fā)板搭載的滑動(dòng)變阻器(VR1)的電壓,然后把ADC轉換的結果通過(guò)UART打印出來(lái)。同時(shí),也簡(jiǎn)單介紹了校準的方法。
本文引用地址:http://dyxdggzs.com/article/201704/346682.htmSAM4E芯片中,ADC是由AFEC管理的。同時(shí),AFEC可以使用一個(gè)多路復用器以選擇需要轉換的信號的通道,也可以通過(guò)平均多次ADC轉換的結果以提高轉換精確度。
一、 電路圖

通過(guò)順時(shí)針?lè )较蛐D該變阻器,PB1引腳電壓將變大,其電壓變化范圍為0—3.3V。使用的AFEC為AFEC0,通道編號為5。

通過(guò)JP3可以選擇參考電壓的大小。默認情況下,參考電壓為3.3 V。
需要注意的是,而在JP3短接2、3腳時(shí),參考電壓為3.0 V。
二、 ADC電氣特性

該AFEC有效的時(shí)鐘范圍為1—20 MHz,最大采樣頻率是1 MHz。同時(shí)也需記下啟動(dòng)、跟蹤、設置等時(shí)間,這在使用AFEC時(shí)會(huì )用到。另外,傳送時(shí)間在芯片手冊中沒(méi)有詳細說(shuō)明,只說(shuō)明將TRANSFER字段設置為1。
由于需要使用較高波特率進(jìn)行UART通信,所以將MCK設置為96 MHz。在此情況下,能設置的最高的AFEC時(shí)鐘頻率為16 MHz(將AFEC_MR的PRESCAL參數設置為2),即每個(gè)AFEC時(shí)鐘的周期為62.5 ns。
由此可以計算出,從關(guān)閉狀態(tài)下,完全啟動(dòng)AFEC最多需要512個(gè)AFEC時(shí)鐘。在實(shí)際應用中,這個(gè)數字可以減小。
三、 AFEC初始化
準備工作為將MCK設置為96 MHz,開(kāi)啟UART并讓printf通過(guò)UART輸出。
PMC及GPIO設置。
AFEC工作模式。有兩個(gè)寄存器可以設置AFEC的工作模式:
AFEC0->AFEC_MR =
AFEC_MR_TRGEN_DIS // 關(guān)閉硬件觸發(fā)
| AFEC_MR_SLEEP // 轉換完成后進(jìn)入睡眠模式
| AFEC_MR_PRESCAL(2) // AFEC CLK = 96M / 6 = 16 M
| AFEC_MR_STARTUP_SUT512 // MAX 32 us
| AFEC_MR_SETTLING_AST3 // MIN 100 ns
| AFEC_MR_ANACH_ALLOWED
| AFEC_MR_TRACKTIM(2) // MIN 160 ns
| AFEC_MR_TRANSFER(1)
| AFEC_MR_USEQ_NUM_ORDER
;
AFEC0->AFEC_EMR =
AFEC_EMR_RES_NO_AVERAGE // 進(jìn)行 12bit 采樣
;
設置增益參數及關(guān)閉差分模式:
AFEC0->AFEC_CGR = AFEC_CGR_GAIN5(0);
AFEC0->AFEC_DIFFR &= ~((uint32_t)1 << 5); // 不使用差分模式
啟用通道:
1AFEC0->AFEC_CHER = AFEC_CHER_CH5;
四、 實(shí)現
轉換指定通道的輸入
uint16_t GetADCValue(int ch)
{
// 軟觸發(fā)以開(kāi)始轉換
AFEC0->AFEC_CR = AFEC_CR_START;
// 等待轉換完成(通過(guò)查詢(xún)相應的EOC位判斷轉換是否完成)
while ((AFEC0->AFEC_ISR & (1<<CH) )="=" 0);< p>
// 設置通道選擇寄存器,使AFEC_CDR顯示指定通道的轉換結果
AFEC0->AFEC_CSELR = AFEC_CSELR_CSEL(ch);
return AFEC0->AFEC_CDR;
}
輪詢(xún)滑動(dòng)變阻器的電壓,并在電壓波動(dòng)超過(guò)指定閥值時(shí)打印出當前電壓。
const int min_diff = 10; // 閥值
int diff;
uint16_t adcv; // ADC轉換的結果
uint16_t last_adcv = ~0;
while(1){
adcv = GetADCValue(5);
//判斷電壓波動(dòng)是否超過(guò)閥值
diff = (int32_t)adcv - last_adcv;
if (!(diff > (-min_diff) && diff < min_diff))
{
last_adcv = adcv;
printf("%dnr", (int)adcv);
}
// 等待
for (volatile int i=0; i< 0xFFFF; ++i);
}
五、 校準
在運行該示例時(shí),發(fā)現當滑動(dòng)變阻器VR1逆時(shí)鐘旋至極限,即PB1引腳電壓為0V時(shí),ADC的輸出為2048左右。而當PB1電壓約為3.3 V的一半時(shí),ADC輸出值約為4095——即達到輸出的最大值。
可以推測出存在一個(gè)約為2048的偏移誤差。這個(gè)誤差在一個(gè)ASF的示例中被提及:“AFEC內部的偏移為0x800……”。所以我們需要對此進(jìn)行校準:
AFEC0->AFEC_CSELR = 5;
//AFEC內部偏移為 0x800
//該校準在參考電壓為3.3V 時(shí)有效
AFEC0->AFEC_COCR = AFEC_COCR_AOFF(0x800);
AFEC_COCR的寄存器是作用于A(yíng)FEC內部的DAC的:

同時(shí),通過(guò)該模塊圖也可以知道增益與偏移校準作用于輸入V的方式如下:
偏移電壓:
V_offset = ( offset / 4096 ) * V_ref
ADC進(jìn)行轉換的電壓:
V_adc_in = ( V – V_offset) * gain
最后,將轉換的數值加上0x800。
評論