一、ADC簡介
ADC支持 14 位的模擬數字轉換,具有多達12 位的 ENOB(有效數字位)。它包括一個模擬多路轉換器,具有多達8 個各自可配置的通道,以及一個參考電壓發生器。轉換結果通過DMA寫入存儲器。還具有若干運行模式。
二、A/D轉換的基本工作原理
將時間上連續變化的模擬量轉化為脈沖有無的數字量,這一過程就叫做數字化,實現數字化的關鍵設備是ADC。
ADC:數模轉換器,將時間和幅值連續的模擬量轉化為時間和幅值離散的數字量,A/D轉換一般要經過采樣、保持、量化和編碼4個過程。
三、CC2530的A/D轉換模塊
ADC的主要特性如下:
● 可選的抽取率,這也設置了分辨率(7 到 12 位)
● 8 個獨立的輸入通道,可接受單端或差分信號
● 參考電壓可選為內部單端、外部單端、外部差分或 AVDD5
● 產生中斷請求
● 轉換結束時的 DMA 觸發
● 溫度傳感器輸入
● 電池測量功能
四、一些關於ADC的概念
<1> 序列ADC轉換:可以按序列進行多通道的ADC轉換,並把結果通過DMA傳送到存儲器,而不需要CPU任何參與。
<2> 單通道ADC轉換:在程序設計中,通過寫ADCCON3寄存器觸發單通道ADC轉換,一旦寄存器被寫入,轉換立即開始。
<3> 參考電壓:內部生成的電壓、AVDD5引腳、適用於AIN7輸入引腳的外部電壓,或者 適用於AIN6~AIN7輸入引腳的差分電壓。
<4> 轉換結果:數字轉換結果以2的補碼形式表示。對於單端,結果總是正的。對於差分配置,兩個引腳之間的差分被轉換,可以是負數。 當ADCCON1.EOC設置為1時,數字轉換結果可以獲得,且結果總是駐留在ADCH和ADCL寄存器組合的MSB段中。
<5> 中斷請求:通過寫ADCCON3觸發一個單通道轉換完成時,將產生一個中斷,而完成 一個序列轉換時,是不產生中斷的。當每完成一個序列轉換,ADC將產生 一個DMA觸發。
<6> 寄存器:ADC有兩個數據寄存器:ADCL和ADCH;三個控制寄存器:ADCCON1、ADCCON2、ADCCON3;分別用來配置ADC並返回轉換結果。
五、ADC模塊的信號輸入
端口0引腳可以配置為ADC輸入端,依次為AIN0~AIN7:
<1> 可以把輸入配置為單端輸入或差分輸入。
<2> 在選擇差分輸入的情況下,差分輸入對:AIN0~AIN1、AIN2~AIN3、AIN4~AIN5、AIN6~AIN7。
<3>除了輸入引腳 AIN0-AIN7,片上溫度傳感器的輸出也可以選擇作為 ADC的輸入,用於溫度測量。
<4> 可以將一個對應AVDD5/3的電壓作為ADC輸入,實現電池電壓監測。
<5> 負電壓和大於VDD的電壓都不能用於這些引腳。
<6> 單端電壓輸入AIN0~AIN7,以通道號碼0~7表示;四個差分輸入對則以 通道號碼8~11表示;溫度傳感器的通道號碼為14;AVDD5/3電壓輸入的通道號碼為15。
題目:定時采集電壓數據發送到上位機
將光照度傳感器接到的Zigbee小模塊上,每隔1秒以單通道的傳送到上位機。上位機與CC2530的 串口0相連,系統時鍾為傳送到上位機。上位機與CC2530的 串口0相連,系統時鍾為16MHz,波特率為9600BPS,發送數據采用查詢的方式。數據幀有4個字節,格式如下: 0xFA (幀頭) ADCH ADCL 0xAF (幀尾)
思路:
1.初始化定時器1,實現0.1秒定時。
1 void Init_Timer1() 2 { 3 T1CC0L = 0xd4; //設置最大計數值的低8位 4 T1CC0H = 0x30; //設置最大計數值的高8位 5 T1CCTL0 |= 0x04; //開啟通道0的輸出比較模式 6 T1IE = 1; //使能定時器1中斷 7 T1OVFIM = 1; //使能定時器1溢出中斷 8 EA = 1; //使能總中斷 9 T1CTL = 0x0e; //分頻系數是128,模模式 10 }
2.在定時中斷函數中實現1秒定時。
1 unsigned char count = 0; 2 unsigned char F_time = 0; 3 /*================定時器1服務函數====================*/ 4 #pragma vector = T1_VECTOR 5 __interrupt void Timer1_Sevice() 6 { 7 T1STAT &= ~0x01; //清除定時器1通道0中斷標志 8 count++; 9 if(count == 10) //定時1秒到 10 { 11 F_time = 1; 12 count = 0; 13 } 14 }
3.按照參數要求初始化串口0。
1 void Init_Uart0() 2 { 3 PERCFG = 0x00; //串口0的引腳映射到位置1,即P0_2和P0_3 4 P0SEL = 0x0C; //將P0_2和P0_3端口設置成外設功能 5 U0BAUD = 59; //16MHz的系統時鍾產生9600BPS的波特率 6 U0GCR = 9; 7 U0UCR |= 0x80; //禁止流控,8位數據,清除緩沖器 8 U0CSR |= 0xC0; //選擇UART模式,使能接收器 9 UTX0IF = 0; //清除TX發送中斷標志 10 URX0IF = 0; //清除RX接收中斷標志 11 URX0IE = 1; //使能URAT0的接收中斷 12 EA = 1; //使能總中斷 13 }
4.設計字節數組發送函數。
unsigned char dat[4]; /*===================UR0發送字符串函數==================*/ void UR0SendString(unsigned char *str, unsigned char count) { while(count--) { U0DBUF = *str++; //將要發送的1字節數據寫入U0DBUF while(!UTX0IF); //等待TX中斷標志,即數據發送完成 UTX0IF = 0; } }
5.初始化ADC (單通道采集)。
配置APCFG寄存器
當使用ADC時,端口0的引腳必須配置為ADC模擬輸入。要配置一個端口0引腳為一個ADC輸入,APCFG寄存器中相應的位必須設置為1。這個寄存器的默認值是0,選擇端口0為非模擬輸入,即作為數字I/O端口。
注意:APCFG寄存器的設置將覆蓋P0SEL的設置。
主要對端口的功能進行選擇,設置其傳輸方向,並將端口設置為模擬輸入。
1 void Init_ADC0() 2 { 3 P0SEL |= 0x01; //P0_0端口設置為外設功能 4 P0DIR &= ~0x01; //P0_0端口設置為輸入端口 5 APCFG |= 0x01; //P0_0作為模擬I/O使用 6 }
6.實現數據采集並發送到上位機。
配置ADCCON3寄存器
單通道的ADC轉換,只需將控制字寫入ADCCON3寄存器即可。
例子:ADCCON3 = (0x80 | 0x10 | 0x00); //參考電壓選擇AVDD5引腳,256 抽取率,AINO通道0
首先將ADCIF標志位清0,接着對ADCCON3寄存器設置,該寄存器一旦被寫入,轉換立即開啟;然后等待ADCIF置1,這時候轉換完成,讀取數據即可。
1 /*===================讀取ADC的數據====================*/ 2 void Get_ADC0_Value() 3 { 4 ADCIF = 0; 5 //參考電壓選擇AVDD5引腳,256抽取率,AIN0通道0 6 ADCCON3 = (0x80 | 0x10 | 0x00); 7 while(!ADCIF); //等待A/D轉換完成, 8 dat[0] = 0xaf; 9 dat[1] = ADCH; //讀取ADC數據低位寄存器 10 dat[2] = ADCL; //讀取ADC數據高位寄存器 11 dat[3] = 0xfa; 12 }
完整代碼:

1 #include "ioCC2530.h" 2 /*===============定時器1初始化函數==================*/ 3 void Init_Timer1() 4 { 5 T1CC0L = 0xd4; //設置最大計數值的低8位 6 T1CC0H = 0x30; //設置最大計數值的高8位 7 T1CCTL0 |= 0x04; //開啟通道0的輸出比較模式 8 T1IE = 1; //使能定時器1中斷 9 T1OVFIM = 1; //使能定時器1溢出中斷 10 EA = 1; //使能總中斷 11 T1CTL = 0x0e; //分頻系數是128,模模式 12 } 13 unsigned char count = 0; 14 unsigned char F_time = 0; 15 /*================定時器1服務函數====================*/ 16 #pragma vector = T1_VECTOR 17 __interrupt void Timer1_Sevice() 18 { 19 T1STAT &= ~0x01; //清除定時器1通道0中斷標志 20 count++; 21 if(count == 10) //定時1秒到 22 { 23 F_time = 1; 24 count = 0; 25 } 26 } 27 /*===================UR0初始化函數====================*/ 28 void Init_Uart0() 29 { 30 PERCFG = 0x00; //串口0的引腳映射到位置1,即P0_2和P0_3 31 P0SEL = 0x0C; //將P0_2和P0_3端口設置成外設功能 32 U0BAUD = 59; //16MHz的系統時鍾產生9600BPS的波特率 33 U0GCR = 9; 34 U0UCR |= 0x80; //禁止流控,8位數據,清除緩沖器 35 U0CSR |= 0xC0; //選擇UART模式,使能接收器 36 UTX0IF = 0; //清除TX發送中斷標志 37 URX0IF = 0; //清除RX接收中斷標志 38 URX0IE = 1; //使能URAT0的接收中斷 39 EA = 1; //使能總中斷 40 } 41 unsigned char dat[4]; 42 /*===================UR0發送字符串函數==================*/ 43 void UR0SendString(unsigned char *str, unsigned char count) 44 { 45 while(count--) 46 { 47 U0DBUF = *str++; //將要發送的1字節數據寫入U0DBUF 48 while(!UTX0IF); //等待TX中斷標志,即數據發送完成 49 UTX0IF = 0; 50 } 51 } 52 /*===================ADC初始化函數====================*/ 53 void Init_ADC0() 54 { 55 P0SEL |= 0x01; //P0_0端口設置為外設功能 56 P0DIR &= ~0x01; //P0_0端口設置為輸入端口 57 APCFG |= 0x01; //P0_0作為模擬I/O使用 58 } 59 /*===================讀取ADC的數據====================*/ 60 void Get_ADC0_Value() 61 { 62 ADCIF = 0; 63 //參考電壓選擇AVDD5引腳,256抽取率,AIN0通道0 64 ADCCON3 = (0x80 | 0x10 | 0x00); 65 while(!ADCIF); //等待A/D轉換完成, 66 dat[0] = 0xaf; 67 dat[1] = ADCH; //讀取ADC數據低位寄存器 68 dat[2] = ADCL; //讀取ADC數據高位寄存器 69 dat[3] = 0xfa; 70 } 71 /*=======================主函數======================*/ 72 void main() 73 { 74 Init_Uart0(); 75 Init_Timer1(); 76 Init_ADC0(); 77 while(1) 78 { 79 if(F_time == 1) //定時1秒時間到 80 { 81 Get_ADC0_Value(); //進行A/D轉換並讀取數據 82 UR0SendString(dat,4); //向上位機發送數據 83 F_time = 0; //定時1秒標志清0 84 } 85 } 86 }