6.2 模數(shù)轉(zhuǎn)換的ADC實(shí)驗(yàn)
6.2.1、實(shí)例功能
AVR的模數(shù)轉(zhuǎn)換器ADC具有下列特點(diǎn):
在本實(shí)例中,我們將編寫程序?qū)崿F(xiàn)將模數(shù)轉(zhuǎn)換后獲得的電壓值通過單片機(jī)的串口發(fā)送到計(jì)算機(jī),然后通過計(jì)算機(jī)上的串口助手顯示測(cè)量的電壓值。
本實(shí)例共有3個(gè)功能模塊,分別描述如下:
● 單片機(jī)系統(tǒng):使用單片機(jī)的串口實(shí)現(xiàn)將模數(shù)轉(zhuǎn)換后獲得的電壓值通過串口發(fā)送到計(jì)算機(jī)。
● 外圍電路:RS232電平轉(zhuǎn)換電路,DB9串行接口插座,模擬電壓輸入采集電路。
● 軟件程序:進(jìn)一步熟悉單片機(jī)的串行通信,并掌握單片機(jī)的模數(shù)轉(zhuǎn)換的方法。
6.2.2、器件和原理
關(guān)于串行接口的原理已接單片機(jī)與計(jì)算機(jī)的串口的連接在上一實(shí)例中進(jìn)行了描述,在本實(shí)例中不再重復(fù)。
本實(shí)例只介紹ATmega16單片機(jī)如何通過內(nèi)置的模數(shù)轉(zhuǎn)換模塊采集外界輸入的模擬電壓。
1、ATmega16單片機(jī)的模數(shù)轉(zhuǎn)換器ADC介紹
由于單片機(jī)只能處理數(shù)字信號(hào),所以外部的模擬信號(hào)量需要轉(zhuǎn)變成數(shù)字量才能進(jìn)一步的由單片機(jī)進(jìn)行處理。ATmega16內(nèi)部集成有一個(gè)10位逐次比較(successive approximation)ADC電路。因此使用AVR可以非常方便的處理輸入的模擬信號(hào)量。
ATmega16的ADC與一個(gè)8通道的模擬多路選擇器連接,能夠?qū)σ訮ORTA作為ADC輸入引腳的8路單端模擬輸入電壓進(jìn)行采樣,單端電壓輸入以0V(GND)為參考。另外還支持16種差分電壓輸入組合,其中2種差分輸入方式(ADC1,ADC0和ACD3,ADC2)帶有可編程增益放大器,能在A/D轉(zhuǎn)換前對(duì)差分輸入電壓進(jìn)行0dB(1×),20dB(10×)或46dB(200×)的放大。還有七種差分輸入方式的模擬輸入通道共用一個(gè)負(fù)極(ADC1),此時(shí)其它任意一個(gè)ADC引腳都可作為相應(yīng)的正極。若增益為1×或10×,則可獲得8位的精度。如果增益為200×,那么轉(zhuǎn)換精度為7位。
AVR的ADC功能單元由獨(dú)立的專用模擬電源引腳AVcc供電。AVcc和Vcc的電壓差別不能大于±0.3V。ADC轉(zhuǎn)換的參考電源可采用芯片內(nèi)部的2.56V參考電源,或采用AVcc,也可使用外部參考電源。使用外部參考電源時(shí),外部參考電源由引腳ARFE接入。使用內(nèi)部電壓參考源時(shí),可以通過在AREF引腳外部并接一個(gè)電容來提高ADC的抗噪性能。
ADC功能單元包括采樣保持電路,以確保輸入電壓在ADC轉(zhuǎn)換過程中保持恒定。ADC通過逐次比較(successive approximation)方式,將輸入端的模擬電壓轉(zhuǎn)換成10位的數(shù)字量。最小值代表地,最大值為AREF引腳上的電壓值減1個(gè)LSB。可以通過ADMUX寄存器中REFSn位的設(shè)置,選擇將芯片內(nèi)部參考電源(2.56V)或AVcc連接到AREF,作為A/D轉(zhuǎn)換的參考電壓。這時(shí),內(nèi)部電壓參考源可以通過外接于AREF引腳的電容來穩(wěn)定,以改進(jìn)抗噪特性。
模擬輸入通道和差分增益的選擇是通過ADMUX寄存器中的MUX位設(shè)定的。任何一個(gè)ADC的輸入引腳,包括地(GND)以及內(nèi)部的恒定能隙(fixed bandgap)電壓參考源,都可以被選擇用來作為ADC的單端輸入信號(hào)。而ADC的某些輸入引腳則可選擇作為差分增益放大器的正、負(fù)極輸入端。當(dāng)選定了差分輸入通道后,差分增益放大器將兩輸入通道上的電壓差按選定增益系數(shù)放大,然后輸入到ADC中。若選定使用單端輸入通道,則增益放大器無效。
通過設(shè)置ADCSRA寄存器中的ADC使能位ADEN來使能ADC。在ADEN沒有置“1”前,參考電壓源和輸入通道的選定將不起作用。當(dāng)ADEN位清“0”后,ADC將不消耗能量,因此建議在進(jìn)入節(jié)電休眠模式前將ADC關(guān)掉。
ADC將10位的轉(zhuǎn)換結(jié)果放在ADC數(shù)據(jù)寄存器中(ADCH和ADCL)。默認(rèn)情況下,轉(zhuǎn)換結(jié)果為右端對(duì)齊(RIGHT ADJUSTED)的。但可以通過設(shè)置ADMUX寄存器中ADLAR位,調(diào)整為左端對(duì)齊(LEFT ADJUSTED)。如果轉(zhuǎn)換結(jié)果是左端對(duì)齊,并且只需要8位的精度,那么只需讀取ADCH寄存器的數(shù)據(jù)作為轉(zhuǎn)換結(jié)果就達(dá)到要求了。否則,必須先讀取ADCL寄存器,然后再讀取ADCH寄存器,以保證數(shù)據(jù)寄存器中的內(nèi)容是同一次轉(zhuǎn)換的結(jié)果。因?yàn)橐坏〢DCL寄存器被讀取,就阻斷了ADC對(duì)ADC數(shù)據(jù)寄存器的操作。這就意味著,一旦指令讀取了ADCL,那么必須緊接著讀取一次ADCH;如果在讀取ADCL和讀取ADCH的過程中正好有一次ADC轉(zhuǎn)換完成,ADC的2個(gè)數(shù)據(jù)寄存器的內(nèi)容是不會(huì)被更新的,該次轉(zhuǎn)換的結(jié)果將丟失。只有當(dāng)ADCH寄存器被讀取后,ADC才可以繼續(xù)對(duì)ADCL和ADCH寄存器操作更新。
ADC有自己的中斷,當(dāng)轉(zhuǎn)換完成時(shí)中斷將被觸發(fā)。盡管在順序讀取ADCL和ADCH寄存器過程中,ADC對(duì)ADC數(shù)據(jù)寄存器的更新被禁止,轉(zhuǎn)換的結(jié)果丟失,但仍會(huì)觸發(fā)ADC中斷。
2、ATmwga16單片機(jī)的模數(shù)轉(zhuǎn)換器ADC相關(guān)的I/O寄存器
1.ADC多路復(fù)用器選擇寄存器—ADMUX
REFS1、REFS2用于選擇ADC的參考電壓源,見表6.2.1。如果這些位在ADC轉(zhuǎn)換過程中被改變,新的選擇將在該次ADC轉(zhuǎn)換完成后(ADCSRA中的ADIF被置位)才生效。一旦選擇內(nèi)部參考源(AVcc、2.56V)為ADC的參考電壓后,AREF引腳上不得施加外部的參考電源,只能與GND之間并接抗干擾電容。
表6.2.1 ADC參考電源選擇 |
||
REFS1 |
REFS0 |
ADC參考電源 |
0 |
0 |
外部引腳AREF,斷開內(nèi)部參考源連接 |
0 |
1 |
AVcc,AREF外部并接電容 |
1 |
0 |
保留 |
1 |
1 |
內(nèi)部2.56V,AREF外部并接電容 |
ADLAR位決定轉(zhuǎn)換結(jié)果在ADC數(shù)據(jù)寄存器中的存放形式。寫“1”到ADLAR位,將使轉(zhuǎn)換結(jié)果左對(duì)齊(LEFT ADJUST);否則,轉(zhuǎn)換結(jié)果為右對(duì)齊(RIGHT ADJUST)。無論ADC是否正在進(jìn)行轉(zhuǎn)換,改變ADLAR位都將會(huì)立即影響ADC數(shù)據(jù)寄存器。
這5個(gè)位用于對(duì)連接到ADC的輸入通道和差分通道的增益進(jìn)行選擇設(shè)置,詳見表6.2.2。注意,只有轉(zhuǎn)換結(jié)束后(ADCSRA的ADIF是“1”),改變這些位才會(huì)有效。
表6.2.2 ADC輸入通道和增益選擇 |
||||
MUX[4:0] |
單端輸入 |
差分正極輸入 |
差分負(fù)極輸入 |
增益 |
00000 |
ADC0 |
N/A |
||
00001 |
ADC1 |
|||
00010 |
ADC2 |
|||
00011 |
ADC3 |
|||
00100 |
ADC4 |
|||
00101 |
ADC5 |
|||
00110 |
ADC6 |
|||
00111 |
ADC7 |
|||
01000 |
N/A |
ADC0 |
ADC0 |
10× |
01001 |
ADC1 |
ADC0 |
10× |
|
01010 |
ADC0 |
ADC0 |
200× |
|
01011 |
ADC1 |
ADC0 |
200× |
|
01100 |
ADC2 |
ADC2 |
10× |
|
01101 |
ADC3 |
ADC2 |
10× |
|
01110 |
ADC2 |
ADC2 |
200× |
|
01111 |
ADC3 |
ADC2 |
200× |
|
10000 |
ADC0 |
ADC1 |
1× |
|
10001 |
ADC1 |
ADC1 |
1× |
|
10010 |
ADC2 |
ADC1 |
1× |
|
10011 |
ADC3 |
ADC1 |
1× |
|
10100 |
ADC4 |
ADC1 |
1× |
|
10101 |
ADC5 |
ADC1 |
1× |
|
10110 |
ADC6 |
ADC1 |
1× |
|
10111 |
ADC7 |
ADC1 |
1× |
|
11000 |
ADC0 |
ADC2 |
1× |
|
11001 |
ADC1 |
ADC2 |
1× |
|
11010 |
ADC2 |
ADC2 |
1× |
|
11011 |
ADC3 |
ADC2 |
1× |
|
11100 |
ADC4 |
ADC2 |
1× |
|
11101 |
ADC5 |
ADC2 |
1× |
|
11110 |
1.22V(VBG) |
N/A |
||
11111 |
0V(GND) |
本實(shí)例中我們需要設(shè)置ADC的參考電壓源為AVcc,即REFS0設(shè)置為1,ADC默認(rèn)轉(zhuǎn)換結(jié)果為右對(duì)齊,我們不需要改變,模擬通道選擇ADC0通道單端輸入,即MUX4:0。
2.ADC控制和狀態(tài)寄存器A—ADCSRA
該位寫入“1”時(shí)使能ADC,寫入“0”關(guān)閉ADC。如在ADC轉(zhuǎn)換過程中將ADC關(guān)閉,該次轉(zhuǎn)換隨即停止。
在單次轉(zhuǎn)換模式下,置該位為“1”,將啟動(dòng)一次轉(zhuǎn)換。在自由連續(xù)轉(zhuǎn)換模式下,該位寫入“1”將啟動(dòng)第一次轉(zhuǎn)換。先置位ADEN位使能ADC,再置位ADSC;或置位ADSC的同時(shí)使能ADC,都會(huì)使能ADC開始進(jìn)行第一次轉(zhuǎn)換。第一次ADC轉(zhuǎn)換將需要25個(gè)ADC時(shí)鐘周期,而不是常規(guī)轉(zhuǎn)換的13個(gè)ADC時(shí)鐘周期,這是因?yàn)榈谝淮无D(zhuǎn)換需要完成對(duì)ADC的初始化。
在ADC轉(zhuǎn)換的過程中,ADSC將始終讀出為“1”。當(dāng)轉(zhuǎn)換完成時(shí),它將轉(zhuǎn)變?yōu)椤?”。強(qiáng)制寫入“0”是無效的。
當(dāng)該位被置為“1”時(shí),允許ADC工作在自動(dòng)轉(zhuǎn)換觸發(fā)工作模式下。在該模式下,在觸發(fā)信號(hào)的上升沿時(shí)ADC將自動(dòng)開始一次ADC轉(zhuǎn)換過程。ADC的自動(dòng)轉(zhuǎn)換觸發(fā)信號(hào)源由SFIOR寄存器中的ADTS位選擇確定。
當(dāng)ADC轉(zhuǎn)換完成并且ADC數(shù)據(jù)寄存器被更新后該位被置位。如果ADIE位(ADC轉(zhuǎn)換結(jié)束中斷允許)和SREG寄存器中的I位被置“1”,ADC中斷服務(wù)程序?qū)⒈粓?zhí)行。ADIF在執(zhí)行相應(yīng)的中斷處理向量時(shí)被硬件自動(dòng)清零。此外,ADIF位可以通過寫入邏輯“1”來清零。
當(dāng)該位和SREG寄存器中的I位同時(shí)被置位時(shí),允許ADC轉(zhuǎn)換完成中斷。
這些位決定了XTAL時(shí)鐘與輸入到ADC的ADC時(shí)鐘之間分頻數(shù),見表6.2.3。
表6.2.3 ADC時(shí)鐘分頻 |
|
ADPS[2:0] |
分 頻 系 數(shù) |
000 |
2 |
001 |
2 |
010 |
4 |
011 |
8 |
100 |
16 |
101 |
32 |
110 |
64 |
111 |
128 |
本實(shí)例中我們需要使能ADC,即ADEN設(shè)置為1,我們不用自動(dòng)轉(zhuǎn)換,也不需要中斷,所以,ADTE、ADIE位不需要設(shè)置。在通常情況下,ADC的逐次比較轉(zhuǎn)換電路要達(dá)到最大精度時(shí),需要50kHz~200kHz之間的采樣時(shí)鐘。本例中使用的時(shí)鐘是12M的,所以要將時(shí)鐘64分頻,分頻后ADC頻率為188KHz,即時(shí)鐘分頻選擇ADPS[2:0]=6。
3.ADC數(shù)據(jù)寄存器—ADCL和ADCH
當(dāng)ADC轉(zhuǎn)換完成后,可以讀取ADC寄存器的ADC0-ADC9得到ADC的轉(zhuǎn)換的結(jié)果。如果是差分輸入,轉(zhuǎn)換值為二進(jìn)制的補(bǔ)碼形式。一旦開始讀取ADCL后,ADC數(shù)據(jù)寄存器就不能被ADC更新,直到ADCH寄存器被讀取為止。因此,如果結(jié)果是左對(duì)齊(ADLAR=1),且不需要大于8位的精度的話,僅僅讀取ADCH寄存器就足夠了。否則,必須先讀取ADCL寄存器,再讀取ADCH寄存器。ADMUX寄存器中的ADLAR位決定了從ADC數(shù)據(jù)寄存器中讀取結(jié)果的格式。如果ADLAR位為“1”,結(jié)果將是左對(duì)齊;如果ADLAR位為“0”(默認(rèn)情況),結(jié)果將是右對(duì)齊。
4.特殊功能I/O寄存器—SFIOR
當(dāng)ADCSRA寄存器中的ADATE為“1”,允許ADC工作在自動(dòng)轉(zhuǎn)換觸發(fā)工作模式時(shí),這3位的設(shè)置用于選擇ADC的自動(dòng)轉(zhuǎn)換觸發(fā)源。如果禁止了ADC的自動(dòng)轉(zhuǎn)換觸發(fā)(ADATE為“0”),這3個(gè)位的設(shè)置值將不起任何作用。
表10-6 ADC自動(dòng)轉(zhuǎn)換觸發(fā)源的選擇 |
|
ADTS[2:0] |
觸 發(fā) 源 |
000 |
連續(xù)自由轉(zhuǎn)換 |
001 |
模擬比較器 |
010 |
外部中斷0 |
011 |
T/C0比較匹配 |
100 |
T/C0溢出 |
101 |
T/C1比較匹配B |
110 |
T/C1溢出 |
111 |
T/C1輸入捕捉 |
本例中我們不使用自動(dòng)轉(zhuǎn)換功能,所以該寄存器可以不必設(shè)置。
6.2.3、電路
本實(shí)例的電路包括232電平轉(zhuǎn)換電路和電阻分壓電路,這兩種電路在前面的實(shí)例中均做過介紹,這里不再重復(fù)。
1、電路原理
在本實(shí)例中利用MAX3232芯片使單片機(jī)輸出的TTL電平轉(zhuǎn)換為標(biāo)準(zhǔn)的RS232電平,從而使計(jì)算機(jī)能夠識(shí)別。同時(shí)將計(jì)算機(jī)輸出的RS232電平轉(zhuǎn)換為單片機(jī)可以識(shí)別的TTL電平。
利用電位器產(chǎn)生電阻分壓電路,從而產(chǎn)生變化的模擬電壓加到單片機(jī)的模擬信號(hào)采集端口,供單片機(jī)采集。
2、電路連接
電路中MAX3232芯片的9、10引腳分別連接單片機(jī)的PD0、PD1端口,MAX3232的13、14引腳分別連接計(jì)算機(jī)串口線的3、2腳。
電位器RP2的動(dòng)片引腳連接單片機(jī)的模擬信號(hào)采集通道PA0(ADC0)。
3、特別說明
本學(xué)習(xí)板采用的是串口插座是公頭的,所以與計(jì)算機(jī)相連的串口連接線應(yīng)該是交叉串口線,而不是串口延長線。
6.2.4、程序設(shè)計(jì)
1、程序功能
程序的功能是通過單片機(jī)的串行接口,將單片機(jī)采集到的模擬電壓值發(fā)送到計(jì)算機(jī)中,通過計(jì)算機(jī)上的串口助手顯示采集的電壓值。
● 單片機(jī)串行接收中斷的編程
在本例中,我們用到了單片機(jī)的串行接收中斷,需要編寫串行接收中斷服務(wù)程序,通過查詢WINAVR(GCC)的中斷庫函數(shù)手冊(cè),可以查找到ATmega16單片機(jī)串行接收中斷的中斷向量為USART_RXC_vect。據(jù)此我們可以編寫串行接收中斷服務(wù)程序,如下:
//接收中斷函數(shù)
ISR(USART_RXC_vect )
{
unsigned char Rev;
Rev = UDR; //從USART I/O數(shù)據(jù)寄存器-UDR中讀出數(shù)據(jù)
Usart_PutChar(Rev); //將接收到的數(shù)據(jù)發(fā)送
}
在中斷服務(wù)程序中,我們首先把單片機(jī)串口接收到的數(shù)據(jù)放入變量Rev中,然后調(diào)用上一實(shí)例中編寫的串行接口字節(jié)發(fā)送函數(shù)將變量Rev中的數(shù)據(jù)發(fā)送到計(jì)算機(jī)。
2、 單片機(jī)與計(jì)算機(jī)串行通信結(jié)果的觀察
在觀察本例運(yùn)行結(jié)果時(shí),我們同樣要用到串口助手,本例中,單片機(jī)發(fā)送串口數(shù)據(jù)采用的波特率是9600bps,數(shù)據(jù)格式是8位數(shù)據(jù)位,1位停止位,無奇偶校驗(yàn)。在串口助手里面,我們也要將波特率和數(shù)據(jù)格式設(shè)置成一樣的。
3、函數(shù)說明
本實(shí)例用到了6個(gè)函數(shù),分別是:
void Port_Init(void); //端口初始化配置
void Usart_Init(void); //USART寄存器設(shè)置
void AD_Init(void); //AD初始化
void Usart_PutChar(unsigned char cTXData); //字節(jié)發(fā)送函數(shù)
void Usart_PutString(unsigned char *pcString); // 字符串發(fā)送數(shù)據(jù)
unsigned int AD_GetData(void); //AD轉(zhuǎn)換函數(shù)
4、使用WINAVR開發(fā)環(huán)境,在本例中我們使用的是外部12M的晶振,所以需要將MAKEFILE文件中的時(shí)鐘頻率修改為12M。另外在程序燒錄到單片機(jī)的時(shí)候,熔絲位也要選擇為外部12M晶振(注意是晶振,不是外部振蕩器,一定不要選擇錯(cuò)了,否則會(huì)導(dǎo)致單片機(jī)不能再燒寫程序)。
5、程序代碼
[code="CSHARP"]
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h> //中斷函數(shù)頭文件
//常量聲明
#define BAUD 9600 //波特率設(shè)置值
//全局變量聲明
unsigned int ADData; //AD轉(zhuǎn)換獲得的數(shù)據(jù)
//函數(shù)聲明
void Port_Init(void); //端口初始化配置
void Usart_Init(void); //USART寄存器設(shè)置
void AD_Init(void); //AD初始化
void Usart_PutChar(unsigned char cTXData); //字節(jié)發(fā)送函數(shù)
void Usart_PutString(unsigned char *pcString); // 字符串發(fā)送數(shù)據(jù)
unsigned int AD_GetData(void); //AD轉(zhuǎn)換函數(shù)
int main(void)
{
unsigned char Delay3s;
Port_Init();
Usart_Init();
AD_Init();
Usart_PutString("AD轉(zhuǎn)換測(cè)試程序");
Usart_PutString("測(cè)得ADC0通道的電壓值為:");
sei(); //使能全局中斷
while(1)
{
ADData = (int)((long)AD_GetData() * 5010 / 1024); //將獲得的AD值轉(zhuǎn)換為電壓值
//單位為mv。
Usart_PutChar(ADData / 1000 + 0x30); //得到電壓值的千位并發(fā)送
Usart_PutChar('.'); //發(fā)送小數(shù)點(diǎn)
Usart_PutChar(ADData % 1000 / 100 + 0x30); //得到電壓值的百位并發(fā)送
Usart_PutChar(ADData % 100 / 10 + 0x30); //得到電壓值的十位并發(fā)送
Usart_PutChar(ADData % 10 + 0x30); //得到電壓值的個(gè)位并發(fā)送
Usart_PutChar('V'); //發(fā)送電壓符號(hào)“V”
Usart_PutChar(0x0d); //
Usart_PutChar(0x0a); // AD值發(fā)送結(jié)束,回車換行
for(Delay3s = 0;Delay3s < 30;Delay3s++) //延時(shí)3S
{
_delay_ms(90);
}
}
}
//端口狀態(tài)初始化設(shè)置函數(shù)
void Port_Init()
{
PORTA = 0X00;
DDRA = 0x00; //ADC通道設(shè)置為輸入口,高阻態(tài)
}
//USART寄存器配置函數(shù)
void Usart_Init()
{
UCSRA = 0X00;
UCSRC |= (1<<URSEL) | (1 << UCSZ1) | (1 << UCSZ0); //異步,數(shù)據(jù)格式8,N,1
//UCSRC寄存器與UBRRH寄存器共用相同的I/O地址,寫 UCSRC 時(shí), URSEL 應(yīng)設(shè)置為 1。
UBRRL = (F_CPU / BAUD / 16 - 1) % 256; //波特率設(shè)置
UBRRH = (F_CPU / BAUD / 16 - 1) / 256;
UCSRB |= (1 << RXCIE) | (1 << RXEN) | (1 << TXEN); //發(fā)送使能
}
//字節(jié)發(fā)送函數(shù)
void Usart_PutChar(unsigned char cTXData)
{
while( !(UCSRA & (1 << UDRE)) ); //只有數(shù)據(jù)寄存器為空時(shí)才能發(fā)送數(shù)據(jù)
UDR = cTXData; //發(fā)送數(shù)據(jù)送USART I/O數(shù)據(jù)寄存器-UDR
}
//接收中斷函數(shù)
ISR(USART_RXC_vect )
{
unsigned char Rev;
Rev = UDR; //從USART I/O數(shù)據(jù)寄存器-UDR中讀出數(shù)據(jù)
Usart_PutChar(Rev); //將接收到的數(shù)據(jù)發(fā)送
}
void Usart_PutString(unsigned char *pcString)
{
while (*pcString)
{
Usart_PutChar(*pcString++);
}
Usart_PutChar(0x0D);
Usart_PutChar(0x0A); //結(jié)尾發(fā)送回車換行
}
//AD轉(zhuǎn)換初始化函數(shù)
void AD_Init()
{
ADMUX |= (1 << REFS0); //ADC參考電壓為AVcc,ADC結(jié)果右對(duì)齊,選擇通道ADC0
ADCSRA |= (1 << ADEN) | (1 << ADPS2) | (1 << ADPS1); //使能AD轉(zhuǎn)換,ADC時(shí)鐘64分頻
}
//AD轉(zhuǎn)換函數(shù)
unsigned int AD_GetData()
{
ADCSRA |= (1 << ADSC); //開始AD轉(zhuǎn)換
while(!(ADCSRA & (1 << ADIF))); //等待轉(zhuǎn)換完成
ADCSRA |= (1 << ADIF); //清零ADC中斷標(biāo)志位
return ADC; //返回ADC值
}
[/code]
1.預(yù)分頻與轉(zhuǎn)換時(shí)間
在通常情況下,ADC的逐次比較轉(zhuǎn)換電路要達(dá)到最大精度時(shí),需要50kHz~200kHz之間的采樣時(shí)鐘。在要求轉(zhuǎn)換精度低于10位的情況下,ADC的采樣時(shí)鐘可以高于200kHz,以獲得更高的采樣率。
ADC模塊中包含一個(gè)預(yù)分頻器的ADC時(shí)鐘源,它可以對(duì)大于100KHz的系統(tǒng)時(shí)鐘進(jìn)行分頻,以獲得合適的ADC時(shí)鐘提供ADC使用。預(yù)分頻器的分頻系數(shù)由ADCSRA寄存器中的ADPS位設(shè)置的。一旦寄存器ADCSRA中的ADEN位置“1”(ADC開始工作),預(yù)分頻器就啟動(dòng)開始計(jì)數(shù)。ADEN位為“1”時(shí),預(yù)分頻器將一直工作;ADEN位為“0”時(shí),預(yù)分頻器一直處在復(fù)位狀態(tài)。
AVR的ADC完成一次轉(zhuǎn)換的時(shí)間見表6.2.5。從表中可以看出,完成一次ADC轉(zhuǎn)換通常需要13-14個(gè)ADC時(shí)鐘。而啟動(dòng)ADC開始第一次轉(zhuǎn)換到完成的時(shí)間需要25個(gè)ADC時(shí)鐘,這是因?yàn)橐獙?duì)ADC單元的模擬電路部分進(jìn)行初始化。
表6.2.5 ADC轉(zhuǎn)換和采樣保持時(shí)間 |
||
轉(zhuǎn) 換 形 式 |
采樣保持時(shí)間 |
完 成 轉(zhuǎn) 換 總 時(shí) 間 |
啟動(dòng)ADC后的第一次轉(zhuǎn)換 |
13.5個(gè)ADC時(shí)鐘 |
25個(gè)ADC時(shí)鐘 |
正常轉(zhuǎn)換,單端輸入 |
1.5個(gè)ADC時(shí)鐘 |
13個(gè)ADC時(shí)鐘 |
自動(dòng)觸發(fā)方式 |
2個(gè)ADC時(shí)鐘 |
13.5個(gè)ADC時(shí)鐘 |
正常轉(zhuǎn)換,差分輸入 |
1.5/2.5個(gè)ADC時(shí)鐘 |
13/14個(gè)ADC時(shí)鐘 |
當(dāng)ADCSRA寄存器中的ADSC位置位,啟動(dòng)ADC轉(zhuǎn)換時(shí),A/D轉(zhuǎn)換將在隨后ADC時(shí)鐘的上升沿開始。一次正常的A/D轉(zhuǎn)換開始時(shí),需要1.5個(gè)ADC時(shí)鐘周期的采樣保持時(shí)間(ADC首次啟動(dòng)后需要13.5個(gè)ADC時(shí)鐘周期的采樣保持時(shí)間)。當(dāng)一次A/D轉(zhuǎn)換完成后,轉(zhuǎn)換結(jié)果寫入ADC數(shù)據(jù)寄存器,ADIF(ADC中斷標(biāo)志位)將被置位。在單次轉(zhuǎn)換模式下,ADSC也同時(shí)被清零。用戶程序可以再次置位ADSC位,新的一次轉(zhuǎn)換將在下一個(gè)ADC時(shí)鐘的上升沿開始。
當(dāng)ADC設(shè)置為自動(dòng)觸發(fā)方式時(shí),觸發(fā)信號(hào)的上升沿將啟動(dòng)一次ADC轉(zhuǎn)換。轉(zhuǎn)換完成的結(jié)果將一直保持到下一次觸發(fā)信號(hào)的上升沿出現(xiàn),然后開始新的一次ADC轉(zhuǎn)換。這就保證了使ADC每隔一定的時(shí)間間隔進(jìn)行一次轉(zhuǎn)換。在這種方式下,ADC需要2個(gè)ADC時(shí)鐘周期的采樣保持時(shí)間。
在自由連續(xù)轉(zhuǎn)換模式下,一次轉(zhuǎn)換完畢后馬上開始一次新的轉(zhuǎn)換,此時(shí),ADSC位一直保持為“1”。
2.ADC輸入通道和參考電源的選擇
寄存器ADMUX中的MUXn和REFS1、REFS0位實(shí)際上是一個(gè)緩沖器,該緩沖器與一個(gè)MCU可以隨機(jī)讀取的臨時(shí)寄存器相連通。采用這種結(jié)構(gòu),保證了ADC輸入通道和參考電源只能在ADC轉(zhuǎn)換過程中的安全點(diǎn)被改變。在ADC轉(zhuǎn)換開始前,通道和參考電源可以不斷被更新,一旦轉(zhuǎn)換開始,通道和參考電源將被鎖定,并保持足夠時(shí)間,以確保ADC轉(zhuǎn)換的正常進(jìn)行。在轉(zhuǎn)換完成前的最后一個(gè)ADC時(shí)鐘周期(ADCSRA的ADIF位置“1”時(shí)),通道和參考電源又開始重新更新。注意,由于A/D轉(zhuǎn)換開始于置位ADSC后的第一個(gè)ADC時(shí)鐘的上升沿,因此,在置位ADSC后的一個(gè)ADC時(shí)鐘周期內(nèi)不要將一個(gè)新的通道或參考電源寫入到ADMUX寄存器中。
改變差分輸入通道時(shí)需特別當(dāng)心。一旦確定了差分輸入通道,增益放大器需要125μs的穩(wěn)定時(shí)間。所以在選擇了新的差分輸入通道后的125μs內(nèi)不要啟動(dòng)A/D轉(zhuǎn)換,或?qū)⑦@段時(shí)間內(nèi)轉(zhuǎn)換結(jié)果丟棄。通過改變ADMUX中的REFS1、REFS0來更改參考電源后,第一次差分轉(zhuǎn)換同樣要遵循以上的時(shí)間處理過程。
在單次轉(zhuǎn)換模式下,總是在開始轉(zhuǎn)換前改變通道設(shè)置。盡管輸入通道改變發(fā)生在ADSC位被寫入“1”后的1個(gè)ADC時(shí)鐘周期內(nèi),然而,最簡單的方法是等到轉(zhuǎn)換完成后,再改變通道選擇。
在連續(xù)轉(zhuǎn)換模式下,總是在啟動(dòng)ADC開始第一次轉(zhuǎn)換前改變通道設(shè)置。盡管輸入通道改變發(fā)生在ADSC位被寫入“1”后的1個(gè)ADC時(shí)鐘周期內(nèi),然而,最簡單的方法是等到第一次轉(zhuǎn)換完成后再改變通道的設(shè)置。然而由于此時(shí)新一次的轉(zhuǎn)換已經(jīng)自動(dòng)開始,所以,當(dāng)前這次的轉(zhuǎn)換結(jié)果仍反映前一通道的轉(zhuǎn)換值,而下一次的轉(zhuǎn)換結(jié)果將為新設(shè)置通道的值。
ADC的參考電壓(VREF)決定了A/D轉(zhuǎn)換的范圍。如果單端通道的輸入電壓超過VREF,將導(dǎo)致轉(zhuǎn)換結(jié)果接近于0x3FF。ADC的參考電壓VREF可以選擇為AVCC或芯片內(nèi)部的2.56V參考源,或者為外接在AREF引腳上的參考電壓源。
AVCC通過一個(gè)無源開關(guān)連接到ADC。內(nèi)部2.56V參考源是由內(nèi)部能隙參考源(VBC)通過內(nèi)部的放大器產(chǎn)生的。注意,無論選用什么內(nèi)部參考電源,外部AREF引腳都是直接與ADC相連的,因此,可以通過外部在AREF引腳和地之間并接一個(gè)電容,使內(nèi)部參考電源更加穩(wěn)定和抗噪??梢酝ㄟ^使用高阻電壓表測(cè)量AREF引腳,來獲得參考電源VREF的電壓值。由于VREF是一個(gè)高阻源,因此,只有容性負(fù)載可以連接到該引腳。
如果將一個(gè)外部固定的電壓源連接到AREF引腳,那就不能使用任何的內(nèi)部參考電源,否則就會(huì)使外部電壓源短路。外部參考電源的范圍應(yīng)在2.0V到AVCC-0.2V之間。參考電源改變后的第一次ADC轉(zhuǎn)換結(jié)果可能不太準(zhǔn)確,建議拋棄該次轉(zhuǎn)換結(jié)果。
3.ADC轉(zhuǎn)換結(jié)果
A/D轉(zhuǎn)換結(jié)束后(ADIF = 1),在ADC數(shù)據(jù)寄存器(ADCL和ADCH)中可以取得轉(zhuǎn)換的結(jié)果。對(duì)于單端輸入的A/D轉(zhuǎn)換,其轉(zhuǎn)換結(jié)果為:
ADC =(VIN×1024)/ VREF
其中VIN表示選定的輸入引腳上的電壓,VREF表示選定的參考電源的電壓。0x000表示輸入引腳的電壓為模擬地,0x3FF表示輸入引腳的電壓為參考電壓值減去一個(gè)LSB。
對(duì)于差分轉(zhuǎn)換,其結(jié)果為:
ADC=(VPOS-VNEG) ×GAIN×512/VREF
例:若差分輸入通道選擇為ADC3-ADC2,10倍增益,參考電壓2.56V,左端對(duì)齊(ADMUX=0xED),ADC3引腳上電壓300mV,ADC2引腳上電壓500mV。
則ADCR =(300-500)×10×512 / 2560 = -400 = 0x270
ADCL=0x00,ADCH=0x9C。
若結(jié)果為右端對(duì)齊時(shí)(ADLAR=“0”),則ADCL=0x70,ADCH=0x02。
附錄2、ADC應(yīng)用設(shè)計(jì)的深入討論
盡管AVR內(nèi)部集成了10位的ADC,但是在實(shí)際應(yīng)用中,要想真正實(shí)現(xiàn)10位精度,比較穩(wěn)定的ADC的話,并不象上一節(jié)中的例子那么簡單。需要進(jìn)一步從硬件、軟件等方面進(jìn)行綜合的、細(xì)致的考慮。下面介紹一些在ADC設(shè)計(jì)應(yīng)用中應(yīng)該考慮的幾個(gè)要點(diǎn)。
1.AVcc的穩(wěn)定性。
AVcc是提供給ADC工作的電源,如果AVcc不穩(wěn)定,就會(huì)影響ADC的轉(zhuǎn)換精度。在圖10-5中,系統(tǒng)電源通過一個(gè)LC濾波后接入AVcc,這樣就能很好的抑制掉系統(tǒng)電源中的高頻躁聲,提高了AVcc的穩(wěn)定性。另外在要求比較高的場(chǎng)合使用ADC時(shí),PA口上的那些沒被用做ADC輸入的端口盡量不要作為數(shù)字I/O口使用。因?yàn)镻A口的工作電源是由AVcc提供的,如果PA口上有比較大的電流波動(dòng),也會(huì)影響AVcc的穩(wěn)定。
2.參考電壓VREF的選擇確定
在實(shí)際應(yīng)用中,要根據(jù)輸入測(cè)量電壓的范圍選擇正確的參考電壓VREF,以求得到比較好的轉(zhuǎn)換精度。ADC的參考電壓VREF還決定了A/D轉(zhuǎn)換的范圍。如果單端通道的輸入電壓超過VREF,將導(dǎo)致轉(zhuǎn)換結(jié)果全部接近于0x3FF,因此ADC的參考電壓應(yīng)稍大于模擬輸入電壓的最高值。
ADC的參考電壓VREF可以選擇為AVCC,或芯片內(nèi)部的2.56V參考源,或者為外接在AREF引腳上的參考電壓源。外接參考電壓應(yīng)該穩(wěn)定,并大于2.0V(芯片的工作電壓為1.8V時(shí),外接參考電壓應(yīng)大于1.0V)。要求比較高的場(chǎng)合,建議在AREF引腳外接標(biāo)準(zhǔn)參考電壓源來作為ADC的參考電源。
3. ADC通道帶寬和輸入阻抗
不管使用單端輸入轉(zhuǎn)換還是差分輸入轉(zhuǎn)換方式,所有模擬輸入口的輸入電壓應(yīng)在AVcc-GNG之間。
在單端ADC轉(zhuǎn)換方式時(shí),ADC通道的輸入頻率帶寬取決于ADC轉(zhuǎn)換時(shí)鐘頻率。一次常規(guī)的ADC轉(zhuǎn)換需要13個(gè)ADC時(shí)鐘,當(dāng)ADC轉(zhuǎn)換時(shí)鐘為1MHz時(shí),一秒種內(nèi)ADC采樣轉(zhuǎn)換的次數(shù)約77K。根據(jù)采樣定理,此時(shí)ADC通道的帶寬為38.5KHz。
差分方式ADC轉(zhuǎn)換的帶寬是由芯片內(nèi)部的差分放大器的帶寬決定,為4KHz。
AVR的ADC輸入阻抗典型值為100MΩ,為保證測(cè)量的準(zhǔn)確,被測(cè)信號(hào)源的輸出阻抗要盡可能的低,應(yīng)在10K以下。
4. ADC采樣時(shí)鐘的選擇
通常條件下,AVR的ADC逐次比較電路要達(dá)到轉(zhuǎn)換的最大精度,需要一個(gè)50K~200KHz的采樣時(shí)鐘。一次正常的ADC轉(zhuǎn)換過程需要13個(gè)采樣時(shí)鐘,假定ADC采樣時(shí)鐘為200KHz,那么最高的采樣速率為200K/13=15.384K。因此根據(jù)采樣定理,理論上被測(cè)模擬信號(hào)的最高頻率為7.7K!
盡管可以設(shè)置ADC的采樣時(shí)鐘為1M,但并不能提高ADC轉(zhuǎn)換精度,反而會(huì)降低轉(zhuǎn)換精度(受逐次比較硬件電路的限制),因此AVR的ADC不能完成高速ADC的任務(wù)。如果所需的轉(zhuǎn)換精度低于10位,那么采樣時(shí)鐘可以高于200KHz,以達(dá)到更高的采樣頻率。
ADC采樣時(shí)鐘的選擇方式為:給出或估計(jì)被測(cè)模擬信號(hào)的最高頻率fs,取采樣頻率為fs的4-10倍,再乘上13為ADC采樣時(shí)鐘頻率,該頻率應(yīng)在50K~200KHz之間。 如果該頻率大于200KHz,則ADC的10位精度不能保證。如果該頻率小于50Khz,則可選擇50K~200KHz之間的數(shù)值。
5.模擬噪聲的抑制
器件外部和內(nèi)部的數(shù)字電路會(huì)產(chǎn)生電磁干擾,并會(huì)影響模擬測(cè)量的精度。如果ADC轉(zhuǎn)換精度要求很高,可以采用以下的技術(shù)來降低噪聲的影響:
(1)使模擬信號(hào)的通路盡可能的短。模擬信號(hào)連線應(yīng)從模擬地的布線盤上通過,并使它們盡可能遠(yuǎn)離高速開關(guān)數(shù)字信號(hào)線。
(2)AVR的AVcc引腳應(yīng)該通過LC網(wǎng)絡(luò)與數(shù)字端電源Vcc相連。
(3)采用ADC噪聲抑制器功能來降低來自MCU內(nèi)部的噪聲。
(4)如果某些ADC引腳是作為通用數(shù)字輸出口使用,那么在ADC轉(zhuǎn)換過程中,不要改變這些引腳的狀態(tài)。
6.ADC的校正
由于AVD內(nèi)部ADC部分的放大器非線性等客觀原因,ADC的轉(zhuǎn)換結(jié)果會(huì)有誤差的。如果要獲得高精度的ADC轉(zhuǎn)換,還需要對(duì)ADC結(jié)果進(jìn)行校正。具體的方法請(qǐng)參考AVR應(yīng)用筆記AVR120(avr_app_120.pdf),在這篇應(yīng)用設(shè)計(jì)參考中詳細(xì)介紹了誤差的種類,以及校正方案。
7.ADC精度的提高
在有了上述幾點(diǎn)的保證后,通過軟件的手段也能適當(dāng)?shù)奶岣逜DC的精度。如采用多次測(cè)量取平均,軟件濾波算法等。在AVR應(yīng)用筆記AVR121(avr_app_121.pdf)中介紹了一種使用過采樣算法的軟件實(shí)現(xiàn),可以將ADC的精度提高到11位或更高,當(dāng)然這是在花費(fèi)更多的時(shí)間基礎(chǔ)上實(shí)現(xiàn)的。