上一篇我們已經(jīng)講了ADC0809的原理與簡化電路,仔細(xì)檢查電路的正確性,尤其不能有短路現(xiàn)象?,F(xiàn)在我們將它實際接上S52板子,靜態(tài)電流為4mA,其中LED用了1mA,也就是說ADC0809靜態(tài)電流為3mA左右。
將ADC0809板插上S52板,數(shù)據(jù)口D0-D7我接的是P0,CLK接P1.0,OE、EOC、ST-ALE分別接P1.1、P1.2、P1.3,Vcc和GND接S52板上的電源和地。
下面講程序:
程序分為三個部分:主程序、LCD顯示、ADC0809轉(zhuǎn)換。
左邊的項目框里有三個程序文件:主程序ADC0809m.C、LCD顯示程序12864put.c、ADC0809轉(zhuǎn)換程序ADC0809C.asm。嗯?。。。最后一個文件是匯編文件?是的!KEIL允許同時加入C程序和匯編程序一塊兒編譯。我們先來看主程序:
#include <AT89X52.H>
#define uchar unsigned char
extern void LcmClear( void ); //清屏,外部函數(shù)
extern void LcmInit( void ); //初始化,外部函數(shù)
extern void LcmPutstr( uchar row,uchar y,uchar * str ); //在設(shè)定位置顯示字符串
extern uchar adc0809conv(void); //
uchar * uchartostr(unsigned char unm); //將char值轉(zhuǎn)成字符串
uchar str[4]; //定義四個字節(jié)的數(shù)組,用來存放將數(shù)值轉(zhuǎn)成的字符
//****************************
//將char值轉(zhuǎn)成字符串函數(shù)
//****************************
uchar * uchartostr(uchar unm)
{
uchar x00,xx,x0,x,n; //定義百位,十位,個位變量
x00=unm/100;
xx=unm%100;
x0=xx/10;
x=xx%10;
n=0;
if(x00!=0)
{ str[n]=x00+48; //值加48即為字符
n++;
}
if(!(x00==0&x0==0))
{ str[n]=x0+48;
n++;
}
str[n]=x+48;
n++;
str[n]='\0';
return str;
}
//****************
// 主函數(shù)
//****************
void Main( void )
{ uchar aa; //定義一個臨時字符變量
/* T2 set */
TR2=0x0; //停止T2定時器
TR0=0x0; //停止T0定時器
T2MOD=0x02; //0010(B) 設(shè)置T2為P1.0口輸出方波模式
C_T2=0; //用內(nèi)部時鐘計數(shù)
TL2=0xfd;
TH2=0xff;
RCAP2L=0xfd;
RCAP2H=0xff;
TMOD=0x01; //設(shè)置T0為1定時模式(16位計數(shù))
TH0=0;
TL0=0;
TR2=1; //打開T2定時器,開始輸出脈沖
aa=adc0809conv(); //啟動一次ADC0809轉(zhuǎn)換并將值交給aa
LcmInit(); //初始化LCD
LcmClear(); //LCD清屏
LcmPutstr( 2,28,"ADC0809 TEST" );
LcmPutstr( 4,59,uchartostr(aa) ); //在第四行第59列輸出ADC0809轉(zhuǎn)換的值
LcmPutstr( 7,42,"TXZ001@" );
while(1)
{
}
}
下面我們再來看ADC0809轉(zhuǎn)換函數(shù):
NAME ADC0809C
?PR?adc0809conv?ADC0809C SEGMENT CODE
?DT?adc0809conv?ADC0809C SEGMENT DATA OVERLAYABLE
PUBLIC adc0809conv
RSEG ?DT?adc0809conv?ADC0809C
?adc0809conv?BYTE:
put?040: DS 1
RSEG ?PR?adc0809conv?ADC0809C
adc0809conv: ;程序從這里開始
USING 0
st bit P1.3 ;設(shè)置ST接P1.3
eoc bit P1.2 ;設(shè)置EOC接P1.2
oe bit P1.1 ;設(shè)置OE接P1.1
port equ P0 ;設(shè)置數(shù)據(jù)讀取PORT接P0
setb TR0 ;啟動T0定時器,用來計數(shù)(我是用T0來計算轉(zhuǎn)換一次需要多長時間)
clr oe ;初始化ADC0809,OE置0
clr st ;初始化ADC0809,ST置0
setb eoc ;初始化ADC0809,EOC置1
mov port,#0 ;先擇通道0數(shù)據(jù)交給P0口
setb st ;這三句將ST給出一個正脈沖來啟動轉(zhuǎn)換
nop ;
clr st ;
mov r7,#10 ;這兩行是用來稍做延時
djnz r7,$ ;
wait1: jb eoc,wait1 ;這兩行是來檢測EOC由低到高發(fā)出了上升沿,以表示轉(zhuǎn)換結(jié)束
wait2: jnb eoc,wait2 ;
mov port,#0FFh ;將P0口復(fù)位,以便下一步讀取數(shù)據(jù)
setb oe ;將OE口置1,允許轉(zhuǎn)換后的數(shù)據(jù)讀出
clr TR0 ;停止T0計時器(T0是從0開始計數(shù)的,到這兒轉(zhuǎn)換結(jié)束停止計數(shù))
MOV R7,port ;將轉(zhuǎn)換的數(shù)據(jù)交給主調(diào)用程序的變量aa
?C0001:
RET ;返回
END
匯編程序有點(diǎn)亂,沒關(guān)系,下一篇我會專門講混合編程。
那個LCD顯示函數(shù)就不在這兒列出了,前面都已講過也列出了程序。
下圖是本程序?qū)嶋H測量一節(jié)AA電池的實例圖:
可以看到,它的值為64,因為我的ADC0809參考電壓為5V,那么8位精度的轉(zhuǎn)換是將5v分為255份那么每份就是5÷255=0.0196v。我測量出一節(jié)電池的64值就為64×0.0196=1.25v。
調(diào)試注意點(diǎn):由于8個模擬測量通道的輸入阻抗很高,在程序運(yùn)行時如果8個模擬端是懸空的,模擬端的電位是隨周圍環(huán)境變化的,那測量出的很可能是亂跳的隨機(jī)值而并非你程序或電路問題。要避免這種情況的干擾,最好先用10K的電阻將模擬端接地。等你測量出每次都為0時,再改變模擬端的電位試驗測量的正確性。
隨便說說轉(zhuǎn)換速度的問題。
ADC0809的轉(zhuǎn)換速度跟脈沖頻率有關(guān),它的允許范圍為10KHZ--1.28M,我們是用T2定時器來做脈沖輸出的,頻率就由公式 晶振頻率/(4×(65536-(RCAP2H,RCAP2L)),還記得上一篇我給出過的這個公式嗎?我的晶振是12MHZ,那么要給出1MHZ的脈沖就要在RCAP2里給65533的值,這樣12M÷4×3=1MHZ。同理,要輸出10KHZ的脈沖就要給65236的值。在主程序里:
TL2=0xfd ;這是計數(shù)器里的初值,F(xiàn)FFD就是65533,也就是輸出1MHZ的脈沖
TH2=0xff ;
RCAP2L=0xfd ;這是重載器,也一樣給上65533的值。
RCAP2H=0xff ;
如果要想輸出10KHZ的脈沖上面就要給上65236的值,也就是FED4。
在主程序里我還用了T0計數(shù)器:
TMOD=0x01; //設(shè)置T0為1定時模式(16位計數(shù))
TH0=0;
TL0=0;
我給的初值為0,但我沒有在主程序里啟動它。而是在ADC0809轉(zhuǎn)換函數(shù)里才啟動和停止:
setb TR0 ;啟動T0定時器,用來計數(shù)(我是用T0來計算轉(zhuǎn)換一次需要多長時間)
。。。。
clr TR0 ;停止T0計時器(T0是從0開始計數(shù)的,到這兒轉(zhuǎn)換結(jié)束停止計數(shù))
這樣我就可以看它計數(shù)的值來知道一次轉(zhuǎn)換需要多長時間了。將轉(zhuǎn)換函數(shù)的最后一句:
MOV R7,port 換成 MOV R7,TL0 或 MOV R7,TH0 就會在LCD上顯示出轉(zhuǎn)換所用的時間了,因為晶振為12MHZ,一個脈沖就是一微秒。實際測試ADC0809在1MHZ時鐘時轉(zhuǎn)換一次為83微秒,而在10KHZ時鐘下轉(zhuǎn)換一次需要1769微秒也就是1.769毫秒,比ADC0804轉(zhuǎn)換速度要慢很多,ADC0804為22微秒。
怎么樣,單片機(jī)好玩吧!