SAM4E單片機之旅——18、通過AFEC(ADC)獲取輸入的電壓


很多時候,一個電壓不僅僅需要定性(高電平或者低電平),而且要定量(了解具體電壓的數值)。這個時候就可以用到模數轉換器(ADC)了。這次的內容是測量開發板搭載的滑動變阻器(VR1)的電壓,然后把ADC轉換的結果通過UART打印出來。同時,也簡單介紹了校准的方法。

SAM4E芯片中,ADC是由AFEC管理的。同時,AFEC可以使用一個多路復用器以選擇需要轉換的信號的通道,也可以通過平均多次ADC轉換的結果以提高轉換精確度

 

一、 電路圖

image

通過順時針方向旋轉該變阻器,PB1引腳電壓將變大,其電壓變化范圍為0—3.3V。使用的AFEC為AFEC0,通道編號為5。

image

通過JP3可以選擇參考電壓的大小。默認情況下,參考電壓為3.3 V

需要注意的是,而在JP3短接2、3腳時,參考電壓為3.0 V。

 

二、 ADC電氣特性

image

該AFEC有效的時鍾范圍為1—20 MHz,最大采樣頻率是1 MHz。同時也需記下啟動、跟蹤、設置等時間,這在使用AFEC時會用到。另外,傳送時間在芯片手冊中沒有詳細說明,只說明將TRANSFER字段設置為1

由於需要使用較高波特率進行UART通信,所以將MCK設置為96 MHz。在此情況下,能設置的最高的AFEC時鍾頻率為16 MHz(將AFEC_MR的PRESCAL參數設置為2),即每個AFEC時鍾的周期為62.5 ns

由此可以計算出,從關閉狀態下,完全啟動AFEC最多需要512個AFEC時鍾。在實際應用中,這個數字可以減小。

 

三、 AFEC初始化

准備工作為將MCK設置為96 MHz,開啟UART並讓printf通過UART輸出。

  1. PMC及GPIO設置。

  2. AFEC工作模式。有兩個寄存器可以設置AFEC的工作模式:

    AFEC0->AFEC_MR = 
    		  AFEC_MR_TRGEN_DIS			// 關閉硬件觸發
    		| AFEC_MR_SLEEP				// 轉換完成后進入睡眠模式
    		| 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		// 進行 12bit 采樣
    		;
  3. 設置增益參數及關閉差分模式:

    AFEC0->AFEC_CGR = AFEC_CGR_GAIN5(0);
    AFEC0->AFEC_DIFFR &= ~((uint32_t)1 << 5); // 不使用差分模式
  4. 啟用通道:

    AFEC0->AFEC_CHER = AFEC_CHER_CH5;

 

四、 實現

  1. 轉換指定通道的輸入

    uint16_t GetADCValue(int ch)
    {
    	// 軟觸發以開始轉換
    	AFEC0->AFEC_CR = AFEC_CR_START;
    	// 等待轉換完成(通過查詢相應的EOC位判斷轉換是否完成)
    	while ((AFEC0->AFEC_ISR & (1<<ch) )== 0);
    	// 設置通道選擇寄存器,使AFEC_CDR顯示指定通道的轉換結果
    	AFEC0->AFEC_CSELR = AFEC_CSELR_CSEL(ch);
    
    	return AFEC0->AFEC_CDR;
    }
  2. 輪詢滑動變阻器的電壓,並在電壓波動超過指定閥值時打印出當前電壓。

    const int min_diff = 10;		// 閥值
    int diff;
    uint16_t adcv;				// ADC轉換的結果
    uint16_t last_adcv = ~0;
    
    while(1){
    	adcv = GetADCValue(5);
    	//判斷電壓波動是否超過閥值
    	diff = (int32_t)adcv - last_adcv;
    	if (!(diff > (-min_diff) && diff < min_diff))
    	{
    		last_adcv = adcv;
    		printf("%d\n\r", (int)adcv);
    	}
    	// 等待
    	for (volatile int i=0; i< 0xFFFF; ++i);
    }

 

五、 校准

在運行該示例時,發現當滑動變阻器VR1逆時鍾旋至極限,即PB1引腳電壓為0V時,ADC的輸出為2048左右。而當PB1電壓約為3.3 V的一半時,ADC輸出值約為4095——即達到輸出的最大值。

可以推測出存在一個約為2048的偏移誤差。這個誤差在一個ASF的示例中被提及:“AFEC內部的偏移為0x800……”。所以我們需要對此進行校准:

AFEC0->AFEC_CSELR = 5;
//AFEC內部偏移為 0x800
//該校准在參考電壓為3.3V 時有效
AFEC0->AFEC_COCR = AFEC_COCR_AOFF(0x800);

 

AFEC_COCR的寄存器是作用於AFEC內部的DAC的:

image

同時,通過該模塊圖也可以知道增益與偏移校准作用於輸入V的方式如下:

  • 偏移電壓:

    V_offset = ( offset / 4096 ) * V_ref

  • ADC進行轉換的電壓:

    V_adc_in = ( V – V_offset) * gain

  • 最后,將轉換的數值加上0x800。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM