三分鐘弄懂什么是ADC(三分鐘左右是什么概念)
在第 7 節(jié),我們討論了借助于單片機(jī)和傳感器,電腦也能獲取環(huán)境參數(shù),例如室內(nèi)的溫度和濕度等信息。
不過不知道大家注意到?jīng)]有,環(huán)境的溫濕度應(yīng)該是無時無刻都在變化的,而我們使用單片機(jī)采集的溫濕度值卻是離散的(大約1秒個溫度值),這其實(shí)就是將模擬信息數(shù)字化的過程。
使用ADC將模擬信號數(shù)字化
相當(dāng)一部分單片機(jī)都帶有 ADC 外設(shè),ADC 的功能就是將模擬信息數(shù)字化。恰好我使用的這款 51 單片機(jī)就有 ADC 功能,本節(jié)將介紹該模塊。目的是讓我們的電腦具備測量電壓的能力。
ADC 的全稱是 Analog-to-Digital Converter,即“模擬到數(shù)字轉(zhuǎn)換器”,它可以將連續(xù)不斷變化的模擬信號轉(zhuǎn)換為離散的數(shù)字信號,供計算機(jī)進(jìn)一步處理。
將模擬信號數(shù)字化之后,才能使用計算機(jī)處理之,因?yàn)橛嬎銠C(jī)本身就是數(shù)字電路組成的運(yùn)算機(jī)器。其實(shí)說將模擬信號“轉(zhuǎn)換”為離散信號并不合適,更恰當(dāng)?shù)恼f法應(yīng)該是 ADC 從模擬信號中取出“一部分”信息,請看下面右圖的黑點(diǎn)即為 ADC 采集的數(shù)字信號。
這么看來,ADC的重要參數(shù)有兩個:采樣頻率和精度。采樣頻率決定了 ADC 從模擬信號中取數(shù)據(jù)的“密集”程度,一般來說肯定越密集越好,因?yàn)檫@樣更能還原信號的特性。精度則決定了取數(shù)據(jù)的時的精確性。
以我的 51 單片機(jī)為例,它有 8 路 10 位的 ADC,采樣頻率為 250K/s。所以它能從每秒的模擬信號中取出 25 萬個數(shù)字信號,也就相當(dāng)于在坐標(biāo)系中用 25 萬個點(diǎn)描繪出 1 秒的信號。
精度為 10 位,也就是說它利用 1~1024(2的十次方)的數(shù)字表示信號,我的 51 單片機(jī) ADC 的參考電壓信號為 5V,所以它能夠表示的最小電壓為 5V/1024 約為 5mV。
C語言編程單片機(jī),實(shí)現(xiàn)ADC采樣
現(xiàn)在知道了什么是 ADC,怎么使用它呢?請繼續(xù)往下看。我使用的這款 51 單片機(jī)自帶的 ADC 模塊結(jié)構(gòu)如下圖所示:
可以看出,最終得到的數(shù)字信號其實(shí)是經(jīng)過逐次比較的來的。下圖是 ADC 相關(guān)寄存器的信息:
所以,在 keil4 中可以寫出如下C語言代碼:
sfr ADC_CONTR = 0xbc; sfr ADC_RES = 0xbd; // 高 8 位結(jié)果 sfr ADC_LOW2 = 0xbe; // 低 2 位結(jié)果 sfr P1ASF = 0x9d; //
我的這款 51 單片機(jī)的 ADC 轉(zhuǎn)換通道與 P1 口復(fù)用,上電復(fù)位后 P1 口為弱上拉型 IO 口,我們可以通過 C語言編程設(shè)置這 8 路的任意一路做 ADC 轉(zhuǎn)換。
void adc_init() { P1ASF = 0xff; // 8 個通道都開 ADC_RES = 0; ADC_CONTR = ADC_POWER|ADC_SPEEDLL; delay_about_100ms(2); }
上面的C語言代碼中,我們將 P1ASF 賦值為 0xff,表示 P1 的 8 個 IO 口都可以作為 ADC 采樣口。然后延時一段時間,等待 ADC 模塊初始化。
因?yàn)槲沂褂玫倪@款 51 單片機(jī)是一個 8 位單片機(jī),傳送 10 位的 ADC 值需要兩次,當(dāng) AUXR1.1/ADRJ = 0 時,ADC 轉(zhuǎn)換結(jié)果寄存器格式如下:
當(dāng) AUXR1.1/ADRJ = 1 時,ADC 轉(zhuǎn)換結(jié)果寄存器格式如下:
這么看來,獲取一次 ADC 的采樣值高 8 位的 C語言代碼可以如下寫:
// 獲取高 8 位的 adc 值 BYTE get_adc_h8bit(BYTE ch) { ADC_CONTR = ADC_POWER|ADC_SPEEDLL|ADC_START|ch; _nop_();_nop_();_nop_();_nop_(); // 等待轉(zhuǎn)換完成 while(!(ADC_CONTR & ADC_FLAG)); ADC_CONTR &= ~ADC_FLAG; return ADC_RES; }
然后將之與余下 2 位 ADC 值組合一下,就得到了一次完整的ADC采樣值:
// 獲取 10 位 adc WORD get_adc_res(BYTE ch) { WORD res = 0; res = get_adc_h8bit(ch); res <<= 2; res |= ADC_LOW2; return res; }
使用電腦測量電壓值
上面一小部分介紹了單片機(jī)的 ADC 模塊使用方法,結(jié)合之前介紹的單片機(jī)的串口 printf,我們已經(jīng)能夠把外界的電壓值轉(zhuǎn)換為 1~1024 之間的數(shù)值并傳送到電腦了,但是如何將之轉(zhuǎn)換為電壓值呢?
其實(shí)很簡單,我的這款單片機(jī) ADC 模塊的參考電壓為 5V,假設(shè) ADC 采集的數(shù)值為 n,那么對應(yīng)的電壓值為:
U = n*5V / 1024
如此一來,C語言控制程序可以如下寫:
void main() { init_uart(9600); adc_init(); while(1){ delay_about_100ms(2); printf("adc: %0.2f
", 5.0*((float)get_adc_res(0))/1024.0); } }
使用電腦測量電壓
如上圖,為了方便測試,將可變電阻和定電阻串聯(lián),將單片機(jī)的 P10 口與中間相連,即可在電腦端的串口調(diào)試助手得到電壓信息:
使用電壓表測量該點(diǎn)的電壓值,發(fā)現(xiàn)的確在 3.05V 附近:
現(xiàn)在調(diào)節(jié)可變電阻,發(fā)現(xiàn)串口傳來的電壓值也隨之改變:
至此就實(shí)現(xiàn)了使用電腦測量電壓,相信大家也應(yīng)該明白了 ADC 的功能。