CC2541藍牙學習——ADC


CC2541的ADC支持多達14位的模擬數字轉換與高達12位的有效位數。它包括一個模擬多路轉換器,具有多達8個各自可獨立配置的通道,一個參考電壓發生器。轉換結果通過DMA寫入存儲器。還具有若干運行模式。

ADC主要特性如下:

  1. 可選的抽取率,設置了7~12位的分辨率;
  2. 8個獨立輸入通道,可接受單端或差分信號;
  3. 參考電壓可選為內部,外部單端,外部差分,或AVDD5;
  4. 產生中斷請求;
  5. 轉換結束時的DMA觸發;
  6. 溫度傳感器輸入;
  7. 電池測量功能。

                                                                    圖1

P0引腳上的信號可以作為ADC輸入來使用。在下面,這些引腳叫做AIN0—AIN7引腳,輸入腳AIN0—AIN7與ADC連接。

輸入腳可配置成單端或差動輸入。如選擇差動輸入,包含成對輸入AIN0-AIN1,AIN2-AIN3,AIN4-AIN5和AIN6-AIN7;注意這些引腳既不能加載負電壓,也不能加載大於VDD的電壓。

除了輸入腳AIN0-AIN7外,片上的溫度傳感器也可以用來作為ADC溫度測量的輸入。如要實現這個功能,需設置寄存器TR0.ADCTM和ATEST.ATESTCTRL。

單端輸入AIN0至AIN7可代表通道號0至7,通道號8至11分別代表差動輸入AIN0-AIN1,AIN2-AIN3,AIN4-AIN5,AIN6-AIN7;通道12表示GND,通道13表示溫度傳感器,通道15表示AVDD5/3。這些值在ADCCON2.SCH和ADCCON3.SCH中設置。

我們看到ADCCON2和ADCCON3這兩個寄存器的定義基本相同,但是用法不同,ADCCON2用於ADC序列轉換的配置,而ADCCON3則用於單個ADC通道的配置。所謂ADC序列就是多個ADC通道按照次序分別轉換。注意:不是同時轉換的,從圖1我們也可以看出,ADC的模擬輸入接一個選擇器,同一時刻只能選擇一個通道接入進行ADC轉換

如果選擇片上的溫度傳感器作為ADC溫度測量的輸入,則需要通過配置寄存器TR0和ATEST來獲得片上溫度,不過這個溫度測量誤差很大,我們一般不用,這里也就不給出例程了。

啟用片內溫度采集配置寄存器:

1 TR0 |= 0x01;
2 ATEST |= 0x01;

 

1、ADC序列轉換

ADC序列轉換無需CPU的參與,ADC能夠完成一個序列的轉換,並通過DMA把結果寫入內存。

寄存器APCFG影響轉換序列,來自I/O引腳的8位模擬輸入不一定是程序設置的模擬輸入。如某一通道是序列的一部分,但在APCFG中相應模擬輸入是禁止的,那此通道將被跳過。當使用差動輸入時,兩個輸入腳在APCFG寄存器中必須被設置成模擬輸入。

ADCCON2.SCH用來定義ADC輸入的轉換序列。如ADCCON2.SCH被設為小於8,轉換序列包含一個通道(從0到ADCCON2.SCH中設置的通道號),當ADCCON2.SCH值設為8至12時,序列是差動輸入,從通道8至程序設置的通道號;當大於12時,序列包含只選擇的通道。

 

2、單個ADC轉換

除了序列轉換外,ADC可以通過編程執行單個轉換。通過寫入ADCCON3寄存器可以觸發一個轉換,轉換立即啟動,除非一個轉換序列正在進行中,這種情況下,當序列完成后,馬上執行單個轉換。

3、寄存器ADCCON1

ADC的數字轉換結果可以通過寄存器ADCCON1獲得,寄存器ADCCON1的定義如下圖所示。

  • ADCCON1.EOC:轉換結束狀態位,當轉換結束時設高電平,當讀取ADCH時低電平。
  • ADCCON1.ST位用來啟動序列轉換的,當這位設高電平、ADCCON1.STSEL是11且當前無轉換運行時序列啟動開始。當序列轉換結束時,這位自動清除為低電平。
  •  ADCCON1.STSEL位用來選擇哪個事件將啟動一個新的序列轉換。此項選擇有:外部引腳P2.0上升沿事件,之前序列的結束事件,定時器通道0比較事件,或ADCCON1.ST設1事件。

 

4、ADC轉換結果

數字轉換結果以2進制補碼形式表示的,最高位是符號位。

對於單端輸入配置,由於ADC輸入不能接負電壓,轉換結果總是正的當輸入信號等於參考電壓VREF時達到最大轉換結果。

對於差分輸入配置,ADC輸入電壓為兩個引腳的電壓之差,兩腳的輸入信號不同,結果可能是負的;當采樣率為512,模擬輸入Vconv=VREF時,12MSB的數字轉換結果為2047,當模擬輸入等於-VREF時,轉換結果為-2048。

通過讀ADCCON2.SCH位,知道正在轉換的是哪個通道,在序列轉換中,ADCL和ADCH中的結果是前一個通道ADC轉換的值。如轉換序列已結束,ADCCON2.SCH將有一個大於最后通道數一個以上的值,但如最后寫入ADCCON2.SCH中的通道數是12或更大,讀回的是相同的值。

 

5、ADC參考電壓

模數轉換的參考電壓可選擇於內部產生電壓,AVDD5腳電壓,應用於AIN7輸入腳的外部電壓,或應用於AIN6-AIN7輸入的差動電壓。內部參考電壓對於CC2541來說是1.25V,比較小,能轉換的最大模擬電壓最大也只能是1.25V,AVDD5腳電壓一般為3.3V,精度也不是很高。轉換結果的准確度依靠於參考電壓的穩定性和噪聲度,所以對於要求較高的ADC轉換建議從AIN7輸入腳接入高精度的參考電壓。

 

6、ADC轉換時間

ADC只能運行於32MHZ XOSC。執行一個轉換的時間依靠於被選擇的采樣率,一般上,轉換時間由以下公式所得:

Tconv=(decimation rate+16)*0.25us.

可見分辨率越高,轉換時間越長。

 

7、ADC中斷

只有單通道ADC轉換才有ADC中斷,序列ADC轉換沒有ADC中斷。

The ADC generates an interrupt when a single conversion triggered by writing to ADCCON3 has completed.No interrupt is generated when a conversion from the sequence is completed.

 

8、ADC DMA觸發

每完成一個序列轉換,ADC將產生一個DMA觸發。單獨轉換完成不產生DMA觸發。

在ADCCON2.SCH中設置8個通道,每個通道都有一個DMA觸發。當通道轉換中准備好一個采樣時,將激活一個DMA觸發。DMA觸發命名為ADC_CHsd,s是單端通道,d是差動通道。

另外,當ADC序列轉換通道中准備好一個新數據時,一個DMA觸發(ADC_CHALL)將激活。

 

單個ADC轉換讀取ADC值的程序如下:

 1 /******************************************************************************
 2 *函 數 名:InitADC
 3 *功    能:ADC初始化
 4 *入口參數:參考電壓 reference、轉換通道 channel、分辨率resolution
 5 *出口參數:ADC轉換結果
 6 ******************************************************************************/
 7 uint Read_advalue(uchar reference, uchar channel, uchar  resolution)
 8 {
 9   uint value; 
10   uchar tmpADCCON3 = ADCCON3;
11   
12   APCFG |= 1 << channel ; //設置ADC輸入通道,模擬I/O使能
13   
14   ADCCON3  = (reference | resolution | channel);
15   ADCIF = 0;                         //
16 
17   while(!ADCIF);               //等待 AD 轉換完成 
18   value =  ADCL >> 2;          //ADCL 寄存器低 2 位無效
19   value |= ((uint)ADCH << 6);  //連接AD轉換結果高位和低位 
20   
21 //根據分辨率獲得ADC轉換結果有效位 
22   switch(resolution)
23   {
24     case ADC_7_BIT:  value >>= 7;break;
25     case ADC_9_BIT:  value >>= 5;break;
26     case ADC_10_BIT: value >>= 4;break;
27     case ADC_12_BIT: value >>= 2;break;
28     default:;
29   }
30   
31   ADCCON3 = tmpADCCON3;
32   return (value);
33 }

主程序:采集VDD值。

 1 /******************************************************************************
 2 *程序入口函數
 3 ******************************************************************************/
 4 int main(void)
 5 { 
 6   uint vddvalue;       //ADC轉換值
 7 
 8   InitClock();         //32MHz時鍾
 9   InitUART();          //UART0串口初始化
10   
11   while(1)
12   {
13 //ADC參考電壓AVDD5引腳電源電壓:3.3V,分辨率12位,采集通道:VDD/3,VDD=3.3V
14     vddvalue = Read_advalue(ADC_REF_AVDD5, 0x0f, ADC_12_BIT);
15     vddvalue = (vddvalue*33) >> 11;
16     vddvalue = vddvalue*3;
17     buf[0] = vddvalue/10 + '0';
18     buf[1] = '.';
19     buf[2] =vddvalue%10 + '0';
20 
21     UartSendString(buf,strlen(buf));  //串口上傳采樣VDD值
22     Delay1ms(2000);                   //每隔2s上傳一次值
23   }
24 }

這里給出協議棧的adc轉換函數參照對比。

  1 #include "hal_adc.h"
  2 uint16 u16cvalu=HalAdcRead(HAL_ADC_CHANNEL_4,HAL_ADC_RESOLUTION_12);
  3 分辨率設置為12位時,從源碼可以看出,可用位是ADCH 8位+ADCH高4位,其中ADCH最高位是符號位,所以有11位的分辨率,0-2047
  4 默認基准電壓3.3V
  5 uint16 HalAdcRead (uint8 channel, uint8 resolution)
  6 {
  7   int16  reading = 0;
  8 
  9 #if (HAL_ADC == TRUE)
 10 
 11   uint8   i, resbits;
 12   uint8   adctemp;
 13   volatile  uint8 tmp;
 14   uint8  adcChannel = 1;
 15   uint8  reference;
 16 
 17   /* store the previously set reference voltage selection */
 18   reference = ADCCON3 & HAL_ADC_REF_BITS;
 19 
 20   /*
 21   * If Analog input channel is AIN0..AIN7, make sure corresponing P0 I/O pin is enabled.  The code
 22   * does NOT disable the pin at the end of this function.  I think it is better to leave the pin
 23   * enabled because the results will be more accurate.  Because of the inherent capacitance on the
 24   * pin, it takes time for the voltage on the pin to charge up to its steady-state level.  If
 25   * HalAdcRead() has to turn on the pin for every conversion, the results may show a lower voltage
 26   * than actuality because the pin did not have time to fully charge.
 27   */
 28   if (channel < 8)
 29   {
 30     for (i=0; i < channel; i++)
 31     {
 32       adcChannel <<= 1;
 33     }
 34   }
 35 
 36   /* Enable channel */
 37   ADCCFG |= adcChannel;
 38 
 39   /* Convert resolution to decimation rate */
 40   switch (resolution)
 41   {
 42     case HAL_ADC_RESOLUTION_8:
 43       resbits = HAL_ADC_DEC_064;
 44       break;
 45     case HAL_ADC_RESOLUTION_10:
 46       resbits = HAL_ADC_DEC_128;
 47       break;
 48     case HAL_ADC_RESOLUTION_12:
 49       resbits = HAL_ADC_DEC_256;
 50       break;
 51     case HAL_ADC_RESOLUTION_14:
 52     default:
 53       resbits = HAL_ADC_DEC_512;
 54       break;
 55   }
 56 
 57   /* read ADCL,ADCH to clear EOC */
 58   tmp = ADCL;
 59   tmp = ADCH;
 60 
 61   /* Setup Sample */
 62   adctemp = ADCCON3;
 63   adctemp &= ~(HAL_ADC_CHN_BITS | HAL_ADC_DEC_BITS | HAL_ADC_REF_BITS);
 64   adctemp |= channel | resbits | (reference);
 65 
 66   /* writing to this register starts the extra conversion */
 67   ADCCON3 = adctemp;
 68 
 69   /* Wait for the conversion to be done */
 70   while (!(ADCCON1 & HAL_ADC_EOC));
 71 
 72   /* Disable channel after done conversion */
 73   ADCCFG &= (adcChannel ^ 0xFF);
 74 
 75   /* Read the result */
 76   reading = (int16) (ADCL);
 77   reading |= (int16) (ADCH << 8);
 78 
 79   /* Treat small negative as 0 */
 80   if (reading < 0)
 81     reading = 0;
 82 
 83   switch (resolution)
 84   {
 85     case HAL_ADC_RESOLUTION_8:
 86       reading >>= 8;
 87       break;
 88     case HAL_ADC_RESOLUTION_10:
 89       reading >>= 6;
 90       break;
 91     case HAL_ADC_RESOLUTION_12:
 92       reading >>= 4;
 93       break;
 94     case HAL_ADC_RESOLUTION_14:
 95     default:
 96       reading >>= 2;
 97     break;
 98   }
 99 #else
100   // unused arguments
101   (void) channel;
102   (void) resolution;
103 #endif
104 
105   return ((uint16)reading);
106 }
View Code

 

調試結果:顯示VDD值3.3V。

 

關於程序注意以下幾點:

1、要配置一個端口0腳為一個ADC輸入,APCFG寄存器中相應的位必須設置為1。這個寄存器的默認值選擇端口0引腳為非ADC,即數字輸入輸出。APCFG寄存器的設置將覆蓋P0SEL的設置,所以無需再配置P0SEL,另外對於I/O口作為外設功能,都無需配置方向,即無需配置寄存器PxDIR。

 

2、對於單次ADC轉換的配置,只需要配置寄存器ADCCON3,無需配置寄存器ADCCON1和ADCCON2。對於判斷轉換是否結束,還有一種判斷方法:

1   ADCCON1 |=0X30;              //ADC啟動方式選擇為ADCCON1.ST=1事件
2   ADCCON1 |= 0x40;             //啟動轉換
3   while(!(ADCCON1 & 0x80));    //等待 AD 轉換完成 

ADCCON1.STSEL是用於啟動轉換序列的觸發方式的,對於單次ADC轉換,個人感覺這樣配置不好,以后對於單次ADC轉換,不采用這種判斷方式。

單次轉換判斷是否轉換結束:判斷ADC中斷標志ADCIF。

 

3、ADCH的最高位是符號位,對於單次測量,結果總是正的,所以符號位總是0。14位的ADC轉換值有效值並不是14位的。

有效分辨率如下:
00: 64 decimation rate (7 bits ENOB)----ADCH低7位
01: 128 decimation rate (9 bits ENOB)---ADCH低7位+ADCH高2位
10: 256 decimation rate (10 bits ENOB)--ADCH低7位+ADCH高3位
11: 512 decimation rate (12 bits ENOB)--ADCH低7位+ADCL高5位

例如:采集VDD/3值時,使用12位分辨率,參考電壓AVDD5:3.3V

VDD/3 = vddvalue*3.3/2^11
擴大10倍
VDD/3 = vddvalue*33/2^11
為什么是除以2^11而不是2^12,因為最高位是符號位,12位分辨率實際上只有11位。
VDD = (vddvalue*33/2^11) * 3

4、差分輸入可以用來做比較器。比如通道ADCCON3.ECH=1000,對應差分輸入AIN0-AIN1。如果要比較一個模擬信號和另一個模擬信號的大小關系,只需要將這兩個信號分別接入AIN0和AIN1,然后判斷ADCH的最高位,如果是1,則AIN0<AIN1,如果是0,則AIN0>=AIN1。

 

5、最大轉換電壓等於參考電壓,而參考電壓的選擇不能大於芯片的電源電壓,一般為3.3V。雖然差分輸入可以轉換負電壓,但是每一個模擬輸入引腳都必須是正電壓且小於電源電壓VDD,負電壓是指兩個輸入通道的差值。

 


免責聲明!

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



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