覺得這份資料對初學者很有用,希望對初學的人有所幫助。
14. 4×4矩陣式鍵盤識別技術
1. 實驗任務
如圖4.14.2所示,用AT89S51的并行口P1接4×4矩陣鍵盤,以P1.0-P1.3作輸入線,以P1.4-P1.7作輸出線;在數碼管上顯示每個按鍵的“0-F”序號。對應的按鍵的序號排列如圖4.14.1所示
圖4.14.1
2. 硬件電路原理圖
圖4.14.2
3. 系統板上硬件連線
(1. 把“單片機系統“區域中的P3.0-P3.7端口用8芯排線連接到“4X4行列式鍵盤”區域中的C1-C4 R1-R4端口上;
(2. 把“單片機系統”區域中的P0.0/AD0-P0.7/AD7端口用8芯排線連接到“四路靜態數碼顯示模塊”區域中的任一個a-h端口上;要求:P0.0/AD0對應著a,P0.1/AD1對應著b,……,P0.7/AD7對應著h。
4. 程序設計內容
(1. 4×4矩陣鍵盤識別處理
(2. 每個按鍵有它的行值和列值 ,行值和列值的組合就是識別這個按鍵的編碼。矩陣的行線和列線分別通過兩并行接口和CPU通信。每個按鍵的狀態同樣需變成數字量“0”和“1”,開關的一端(列線)通過電阻接VCC,而接地是通過程序輸出數字“0”實現的。鍵盤處理程序的任務是:確定有無鍵按下,判斷哪一個鍵按下,鍵的功能是什么;還要消除按鍵在閉合或斷開時的抖動。兩個并行口中,一個輸出掃描碼,使按鍵逐行動態接地,另一個并行口輸入按鍵狀態,由行掃描值和回饋信號共同形成鍵編碼而識別按鍵,通過軟件查表,查出該鍵的功能。
5. 程序框圖
圖4.14.3
6. 匯編源程序 KEYBUF EQU 30H ORG 00H START: MOV KEYBUF,#2 WAIT: MOV P3,#0FFH CLR P3.4 MOV A,P3 ANL A,#0FH XRL A,#0FH JZ NOKEY1 LCALL DELY10MS MOV A,P3 ANL A,#0FH XRL A,#0FH JZ NOKEY1 MOV A,P3 ANL A,#0FH CJNE A,#0EH,NK1 MOV KEYBUF,#0 LJMP DK1 NK1: CJNE A,#0DH,NK2 MOV KEYBUF,#1 LJMP DK1 NK2: CJNE A,#0BH,NK3 MOV KEYBUF,#2 LJMP DK1 NK3: CJNE A,#07H,NK4 MOV KEYBUF,#3 LJMP DK1 NK4: NOP DK1: MOV A,KEYBUF MOV DPTR,#TABLE MOVC A,@A+DPTR MOV P0,A
DK1A: MOV A,P3 ANL A,#0FH XRL A,#0FH JNZ DK1A NOKEY1: MOV P3,#0FFH CLR P3.5 MOV A,P3 ANL A,#0FH XRL A,#0FH JZ NOKEY2 LCALL DELY10MS MOV A,P3 ANL A,#0FH XRL A,#0FH JZ NOKEY2 MOV A,P3 ANL A,#0FH CJNE A,#0EH,NK5 MOV KEYBUF,#4 LJMP DK2 NK5: CJNE A,#0DH,NK6 MOV KEYBUF,#5 LJMP DK2 NK6: CJNE A,#0BH,NK7 MOV KEYBUF,#6 LJMP DK2 NK7: CJNE A,#07H,NK8 MOV KEYBUF,#7 LJMP DK2 NK8: NOP DK2: MOV A,KEYBUF MOV DPTR,#TABLE MOVC A,@A+DPTR MOV P0,A
DK2A: MOV A,P3 ANL A,#0FH XRL A,#0FH JNZ DK2A NOKEY2: MOV P3,#0FFH CLR P3.6 MOV A,P3 ANL A,#0FH XRL A,#0FH JZ NOKEY3 LCALL DELY10MS MOV A,P3 ANL A,#0FH XRL A,#0FH JZ NOKEY3 MOV A,P3 ANL A,#0FH CJNE A,#0EH,NK9 MOV KEYBUF,#8 LJMP DK3 NK9: CJNE A,#0DH,NK10 MOV KEYBUF,#9 LJMP DK3 NK10: CJNE A,#0BH,NK11 MOV KEYBUF,#10 LJMP DK3 NK11: CJNE A,#07H,NK12 MOV KEYBUF,#11 LJMP DK3 NK12: NOP DK3: MOV A,KEYBUF MOV DPTR,#TABLE MOVC A,@A+DPTR MOV P0,A
DK3A: MOV A,P3 ANL A,#0FH XRL A,#0FH JNZ DK3A NOKEY3: MOV P3,#0FFH CLR P3.7 MOV A,P3 ANL A,#0FH XRL A,#0FH JZ NOKEY4 LCALL DELY10MS MOV A,P3 ANL A,#0FH XRL A,#0FH JZ NOKEY4 MOV A,P3 ANL A,#0FH CJNE A,#0EH,NK13 MOV KEYBUF,#12 LJMP DK4 NK13: CJNE A,#0DH,NK14 MOV KEYBUF,#13 LJMP DK4 NK14: CJNE A,#0BH,NK15 MOV KEYBUF,#14 LJMP DK4 NK15: CJNE A,#07H,NK16 MOV KEYBUF,#15 LJMP DK4 NK16: NOP DK4: MOV A,KEYBUF MOV DPTR,#TABLE MOVC A,@A+DPTR MOV P0,A
DK4A: MOV A,P3 ANL A,#0FH XRL A,#0FH JNZ DK4A NOKEY4: LJMP WAIT DELY10MS: MOV R6,#10 D1: MOV R7,#248 DJNZ R7,$ DJNZ R6,D1 RET TABLE: DB 3FH,06H,5BH,4FH,66H,6DH,7DH,07H DB 7FH,6FH,77H,7CH,39H,5EH,79H,71H END 7. C語言源程序 #include <AT89X51.H> unsigned char code table[]={0x3f,0x06,0x5b,0x4f, 0x66,0x6d,0x7d,0x07, 0x7f,0x6f,0x77,0x7c, 0x39,0x5e,0x79,0x71}; unsigned char temp; unsigned char key; unsigned char i,j;
void main(void) { while(1) { P3=0xff; P3_4=0; temp=P3; temp=temp & 0x0f; if (temp!=0x0f) { for(i=50;i>0;i--) for(j=200;j>0;j--); temp=P3; temp=temp & 0x0f; if (temp!=0x0f) { temp=P3; temp=temp & 0x0f; switch(temp) { case 0x0e: key=7; break; case 0x0d: key=8; break; case 0x0b: key=9; break; case 0x07: key=10; break; } temp=P3; P1_0=~P1_0; P0=table[key]; temp=temp & 0x0f; while(temp!=0x0f) { temp=P3; temp=temp & 0x0f; } } }
P3=0xff; P3_5=0; temp=P3; temp=temp & 0x0f; if (temp!=0x0f) { for(i=50;i>0;i--) for(j=200;j>0;j--); temp=P3; temp=temp & 0x0f; if (temp!=0x0f) { temp=P3; temp=temp & 0x0f; switch(temp) { case 0x0e: key=4; break; case 0x0d: key=5; break; case 0x0b: key=6; break; case 0x07: key=11; break; } temp=P3; P1_0=~P1_0; P0=table[key]; temp=temp & 0x0f; while(temp!=0x0f) { temp=P3; temp=temp & 0x0f; } } }
P3=0xff; P3_6=0; temp=P3; temp=temp & 0x0f; if (temp!=0x0f) { for(i=50;i>0;i--) for(j=200;j>0;j--); temp=P3; temp=temp & 0x0f; if (temp!=0x0f) { temp=P3; temp=temp & 0x0f; switch(temp) { case 0x0e: key=1; break; case 0x0d: key=2; break; case 0x0b: key=3; break; case 0x07: key=12; break; } temp=P3; P1_0=~P1_0; P0=table[key]; temp=temp & 0x0f; while(temp!=0x0f) { temp=P3; temp=temp & 0x0f; } } }
P3=0xff; P3_7=0; temp=P3; temp=temp & 0x0f; if (temp!=0x0f) { for(i=50;i>0;i--) for(j=200;j>0;j--); temp=P3; temp=temp & 0x0f; if (temp!=0x0f) { temp=P3; temp=temp & 0x0f; switch(temp) { case 0x0e: key=0; break; case 0x0d: key=13; break; case 0x0b: key=14; break; case 0x07: key=15; break; } temp=P3; P1_0=~P1_0; P0=table[key]; temp=temp & 0x0f; while(temp!=0x0f) { temp=P3; temp=temp & 0x0f; } } } } }
15. 定時計數器T0作定時應用技術(一)
1. 實驗任務
用AT89S51單片機的定時/計數器T0產生一秒的定時時間,作為秒計數時間,當一秒產生時,秒計數加1,秒計數到60時,自動從0開始。硬件電路如下圖所示
2. 電路原理圖
圖4.15.1
3. 系統板上硬件連線
(1. 把“單片機系統”區域中的P0.0/AD0-P0.7/AD7端口用8芯排線連接到“四路靜態數碼顯示模塊”區域中的任一個a-h端口上;要求:P0.0/AD0對應著a,P0.1/AD1對應著b,……,P0.7/AD7對應著h。
(2. 把“單片機系統”區域中的P2.0/A8-P2.7/A15端口用8芯排線連接到“四路靜態數碼顯示模塊”區域中的任一個a-h端口上;要求:P2.0/A8對應著a,P2.1/A9對應著b,……,P2.7/A15對應著h。
4. 程序設計內容
AT89S51單片機的內部16位定時/計數器是一個可編程定時/計數器,它既可以工作在13位定時方式,也可以工作在16位定時方式和8位定時方式。只要通過設置特殊功能寄存器TMOD,即可完成。定時/計數器何時工作也是通過軟件來設定TCON特殊功能寄存器來完成的。
現在我們選擇16位定時工作方式,對于T0來說,最大定時也只有65536us,即65.536ms,無法達到我們所需要的1秒的定時,因此,我們必須通過軟件來處理這個問題,假設我們取T0的最大定時為50ms,即要定時1秒需要經過20次的50ms的定時。對于這20次我們就可以采用軟件的方法來統計了。
因此,我們設定TMOD=00000001B,即TMOD=01H
下面我們要給T0定時/計數器的TH0,TL0裝入預置初值,通過下面的公式可以計算出
TH0=(216-50000) / 256
TL0=(216-50000) MOD 256
當T0在工作的時候,我們如何得知50ms的定時時間已到,這回我們通過檢測TCON特殊功能寄存器中的TF0標志位,如果TF0=1表示定時時間已到。
5.程序框圖
圖4.15.2
6. 匯編源程序(查詢法) SECOND EQU 30H TCOUNT EQU 31H ORG 00H START: MOV SECOND,#00H MOV TCOUNT,#00H MOV TMOD,#01H MOV TH0,#(65536-50000) / 256 MOV TL0,#(65536-50000) MOD 256 SETB TR0 DISP: MOV A,SECOND MOV B,#10 DIV AB MOV DPTR,#TABLE MOVC A,@A+DPTR MOV P0,A MOV A,B MOVC A,@A+DPTR MOV P2,A WAIT: JNB TF0,WAIT CLR TF0 MOV TH0,#(65536-50000) / 256 MOV TL0,#(65536-50000) MOD 256 INC TCOUNT MOV A,TCOUNT CJNE A,#20,NEXT MOV TCOUNT,#00H INC SECOND MOV A,SECOND CJNE A,#60,NEX MOV SECOND,#00H NEX: LJMP DISP NEXT: LJMP WAIT TABLE: DB 3FH,06H,5BH,4FH,66H,6DH,7DH,07H,7FH,6FH END 7. C語言源程序(查詢法) #include <AT89X51.H>
unsigned char code dispcode[]={0x3f,0x06,0x5b,0x4f, 0x66,0x6d,0x7d,0x07, 0x7f,0x6f,0x77,0x7c, 0x39,0x5e,0x79,0x71,0x00}; unsigned char second; unsigned char tcount;
void main(void) { TMOD=0x01; TH0=(65536-50000)/256; TL0=(65536-50000)%256; TR0=1; tcount=0; second=0; P0=dispcode[second/10]; P2=dispcode[second%10]; while(1) { if(TF0==1) { tcount++; if(tcount==20) { tcount=0; second++; if(second==60) { second=0; } P0=dispcode[second/10]; P2=dispcode[second%10]; } TF0=0; TH0=(65536-50000)/256; TL0=(65536-50000)%256; } } } 1. 匯編源程序(中斷法) SECOND EQU 30H TCOUNT EQU 31H ORG 00H LJMP START ORG 0BH LJMP INT0X START: MOV SECOND,#00H MOV A,SECOND MOV B,#10 DIV AB MOV DPTR,#TABLE MOVC A,@A+DPTR MOV P0,A MOV A,B MOVC A,@A+DPTR MOV P2,A MOV TCOUNT,#00H MOV TMOD,#01H MOV TH0,#(65536-50000) / 256 MOV TL0,#(65536-50000) MOD 256 SETB TR0 SETB ET0 SETB EA SJMP $ INT0X: MOV TH0,#(65536-50000) / 256 MOV TL0,#(65536-50000) MOD 256 INC TCOUNT MOV A,TCOUNT CJNE A,#20,NEXT MOV TCOUNT,#00H INC SECOND MOV A,SECOND CJNE A,#60,NEX MOV SECOND,#00H NEX: MOV A,SECOND MOV B,#10 DIV AB MOV DPTR,#TABLE MOVC A,@A+DPTR MOV P0,A MOV A,B MOVC A,@A+DPTR MOV P2,A NEXT: RETI
TABLE: DB 3FH,06H,5BH,4FH,66H,6DH,7DH,07H,7FH,6FH END 2. C語言源程序(中斷法) #include <AT89X51.H>
unsigned char code dispcode[]={0x3f,0x06,0x5b,0x4f, 0x66,0x6d,0x7d,0x07, 0x7f,0x6f,0x77,0x7c, 0x39,0x5e,0x79,0x71,0x00}; unsigned char second; unsigned char tcount;
void main(void) { TMOD=0x01; TH0=(65536-50000)/256; TL0=(65536-50000)%256; TR0=1; ET0=1; EA=1; tcount=0; second=0; P0=dispcode[second/10]; P2=dispcode[second%10]; while(1); }
void t0(void) interrupt 1 using 0 { tcount++; if(tcount==20) { tcount=0; second++; if(second==60) { second=0; } P0=dispcode[second/10]; P2=dispcode[second%10]; } TH0=(65536-50000)/256; TL0=(65536-50000)%256; }
16. 定時計數器T0作定時應用技術(二)
1. 實驗任務
用AT89S51的定時/計數器T0產生2秒鐘的定時,每當2秒定時到來時,更換指示燈閃爍,每個指示閃爍的頻率為0.2秒,也就是說,開始L1指示燈以0.2秒的速率閃爍,當2秒定時到來之后,L2開始以0.2秒的速率閃爍,如此循環下去。0.2秒的閃爍速率也由定時/計數器T0來完成。
2. 電路原理圖
圖4.16.1
3. 系統板硬件連線
(1. 把“單片機系統”區域中的P1.0-P1.3用導線連接到“八路發光二極管指示模塊”區域中的L1-L4上
4. 程序設計內容
(1. 由于采用中斷方式來完成,因此,對于中斷源必須它的中斷入口地址,對于定時/計數器T0來說,中斷入口地址為000BH,因此在中斷入口地方加入長跳轉指令來執行中斷服務程序。書寫匯編源程序格式如下所示: ORG 00H LJMP START ORG 0BH ;定時/計數器T0中斷入口地址 LJMP INT_T0 START: NOP ;主程序開始 . . INT_T0: PUSH ACC ;定時/計數器T0中斷服務程序 PUSH PSW . . POP PSW POP ACC RETI ;中斷服務程序返回 END
(2. 定時2秒,采用16位定時50ms,共定時40次才可達到2秒,每50ms產生一中斷,定時的40次數在中斷服務程序中完成,同樣0.2秒的定時,需要4次才可達到0.2秒。對于中斷程序,在主程序中要對中斷開中斷。
(3. 由于每次2秒定時到時,L1-L4要交替閃爍。采用ID來號來識別。當ID=0時,L1在閃爍,當ID=1時,L2在閃爍;當ID=2時,L3在閃爍;當ID=3時,L4在閃爍
5. 程序框圖
T0中斷服務程序框圖
主程序框圖
圖4.16.2
6. 匯編源程序
6. 匯編源程序 TCOUNT2S EQU 30H TCNT02S EQU 31H ID EQU 32H ORG 00H LJMP START ORG 0BH LJMP INT_T0 START: MOV TCOUNT2S,#00H MOV TCNT02S,#00H MOV ID,#00H MOV TMOD,#01H MOV TH0,#(65536-50000) / 256 MOV TL0,#(65536-50000) MOD 256 SETB TR0 SETB ET0 SETB EA SJMP $ INT_T0: MOV TH0,#(65536-50000) / 256 MOV TL0,#(65536-50000) MOD 256 INC TCOUNT2S MOV A,TCOUNT2S CJNE A,#40,NEXT MOV TCOUNT2S,#00H INC ID MOV A,ID CJNE A,#04H,NEXT MOV ID,#00H NEXT: INC TCNT02S MOV A,TCNT02S CJNE A,#4,DONE MOV TCNT02S,#00H MOV A,ID CJNE A,#00H,SID1 CPL P1.0 SJMP DONE SID1: CJNE A,#01H,SID2 CPL P1.1 SJMP DONE SID2: CJNE A,#02H,SID3 CPL P1.2 SJMP DONE SID3: CJNE A,#03H,SID4 CPL P1.3 SID4: SJMP DONE DONE: RETI END 7. C語言源程序 #include <AT89X51.H>
unsigned char tcount2s; unsigned char tcount02s; unsigned char ID;
void main(void) { TMOD=0x01; TH0=(65536-50000)/256; TL0=(65536-50000)%256; TR0=1; ET0=1; EA=1;
while(1); }
void t0(void) interrupt 1 using 0 { tcount2s++; if(tcount2s==40) { tcount2s=0; ID++; if(ID==4) { ID=0; } } tcount02s++; if(tcount02s==4) { tcount02s=0; switch(ID) { case 0: P1_0=~P1_0; break; case 1: P1_1=~P1_1; break; case 2: P1_2=~P1_2; break; case 3: P1_3=~P1_3; break; } } }
17. 99秒馬表設計
1. 實驗任務 (1. 開始時,顯示“00”,第1次按下SP1后就開始計時。 (2. 第2次按SP1后,計時停止。 (3. 第3次按SP1后,計時歸零。
2. 電路原理圖
圖4.17.1
3. 系統板上硬件連線
(1. 把“單片機系統”區域中的P0.0/AD0-P0.7/AD7端口用8芯排線連接到“四路靜態數碼顯示模塊”區域中的任一個a-h端口上;要求:P0.0/AD0對應著a,P0.1/AD1對應著b,……,P0.7/AD7對應著h。
(2. 把“單片機系統”區域中的P2.0/A8-P2.7/A15端口用8芯排線連接到“四路靜態數碼顯示模塊”區域中的任一個a-h端口上;要求:P2.0/A8對應著a,P2.1/A9對應著b,……,P2.7/A15對應著h。
(3. 把“單片機系統“區域中的P3.5/T1用導線連接到”獨立式鍵盤“區域中的SP1端口上;
4. 程序框圖 主程序框圖
T0中斷服務程序框圖
圖4.17.2
5. 匯編源程序 TCNTA EQU 30H TCNTB EQU 31H SEC EQU 32H KEYCNT EQU 33H SP1 BIT P3.5 ORG 00H LJMP START ORG 0BH LJMP INT_T0 START: MOV KEYCNT,#00H MOV SEC,#00H MOV A,SEC MOV B,#10 DIV AB MOV DPTR,#TABLE MOVC A,@A+DPTR MOV P0,A MOV A,B MOV DPTR,#TABLE MOVC A,@A+DPTR MOV P2,A MOV TMOD,#02H SETB ET0 SETB EA WT: JB SP1,WT LCALL DELY10MS JB SP1,WT INC KEYCNT MOV A,KEYCNT CJNE A,#01H,KN1 SETB TR0 MOV TH0,#06H MOV TL0,#06H MOV TCNTA,#00H MOV TCNTB,#00H LJMP DKN KN1: CJNE A,#02H,KN2 CLR TR0 LJMP DKN KN2: CJNE A,#03H,DKN MOV SEC,#00H MOV A,SEC MOV B,#10 DIV AB MOV DPTR,#TABLE MOVC A,@A+DPTR MOV P0,A MOV A,B MOV DPTR,#TABLE MOVC A,@A+DPTR MOV P2,A MOV KEYCNT,#00H DKN: JNB SP1,$ LJMP WT DELY10MS: MOV R6,#20 D1: MOV R7,#248 DJNZ R7,$ DJNZ R6,D1 RET INT_T0: INC TCNTA MOV A,TCNTA CJNE A,#100,NEXT MOV TCNTA,#00H INC TCNTB MOV A,TCNTB CJNE A,#4,NEXT MOV TCNTB,#00H INC SEC MOV A,SEC CJNE A,#100,DONE MOV SEC,#00H DONE: MOV A,SEC MOV B,#10 DIV AB MOV DPTR,#TABLE MOVC A,@A+DPTR MOV P0,A MOV A,B MOV DPTR,#TABLE MOVC A,@A+DPTR MOV P2,A NEXT: RETI TABLE: DB 3FH,06H,5BH,4FH,66H,6DH,7DH,07H,7FH,6FH END 6. C語言源程序 #include <AT89X51.H>
unsigned char code dispcode[]={0x3f,0x06,0x5b,0x4f, 0x66,0x6d,0x7d,0x07, 0x7f,0x6f,0x77,0x7c, 0x39,0x5e,0x79,0x71,0x00}; unsigned char second; unsigned char keycnt; unsigned int tcnt;
void main(void) { unsigned char i,j;
TMOD=0x02; ET0=1; EA=1; second=0; P0=dispcode[second/10]; P2=dispcode[second%10]; while(1) { if(P3_5==0) { for(i=20;i>0;i--) for(j=248;j>0;j--); if(P3_5==0) { keycnt++; switch(keycnt) { case 1: TH0=0x06; TL0=0x06; TR0=1; break; case 2: TR0=0; break; case 3: keycnt=0; second=0; P0=dispcode[second/10]; P2=dispcode[second%10]; break; } while(P3_5==0); } } } }
void t0(void) interrupt 1 using 0 { tcnt++; if(tcnt==400) { tcnt=0; second++; if(second==100) { second=0; } P0=dispcode[second/10]; P2=dispcode[second%10]; } }
18. “嘀、嘀、……”報警聲
1. 實驗任務
用AT89S51單片機產生“嘀、嘀、…”報警聲從P1.0端口輸出,產生頻率為1KHz,根據上面圖可知:1KHZ方波從P1.0輸出0.2秒,接著0.2秒從P1.0輸出電平信號,如此循環下去,就形成我們所需的報警聲了。
2. 電路原理圖
圖4.18.1
3. 系統板硬件連線
(1. 把“單片機系統”區域中的P1.0端口用導線連接到“音頻放大模塊”區域中的SPK IN端口上,
(2. 在“音頻放大模塊”區域中的SPK OUT端口上接上一個8歐或者是16歐的喇叭;
4. 程序設計方法
(1.生活中我們常常到各種各樣的報警聲,例如“嘀、嘀、…”就是常見的一種聲音報警聲,但對于這種報警聲,嘀0.2秒鐘,然后斷0.2秒鐘,如此循環下去,假設嘀聲的頻率為1KHz,則報警聲時序圖如下圖所示:
上述波形信號如何用單片機來產生呢?
(2. 由于要產生上面的信號,我們把上面的信號分成兩部分,一部分為1KHZ方波,占用時間為0.2秒;另一部分為電平,也是占用0.2秒;因此,我們利用單片機的定時/計數器T0作為定時,可以定時0.2秒;同時,也要用單片機產生1KHZ的方波,對于1KHZ的方波信號周期為1ms,高電平占用0.5ms,低電平占用0.5ms,因此也采用定時器T0來完成0.5ms的定時;最后,可以選定定時/計數器T0的定時時間為0.5ms,而要定時0.2秒則是0.5ms的400倍,也就是說以0.5ms定時400次就達到0.2秒的定時時間了。
5. 程序框圖
主程序框圖
中斷服務程序框圖
圖4.18.2
6. 匯編源程序 T02SA EQU 30H T02SB EQU 31H FLAG BIT 00H ORG 00H LJMP START ORG 0BH LJMP INT_T0 START: MOV T02SA,#00H MOV T02SB,#00H CLR FLAG MOV TMOD,#01H MOV TH0,#(65536-500) / 256 MOV TL0,#(65536-500) MOD 256 SETB TR0 SETB ET0 SETB EA SJMP $ INT_T0: MOV TH0,#(65536-500) / 256 MOV TL0,#(65536-500) MOD 256 INC T02SA MOV A,T02SA CJNE A,#100,NEXT INC T02SB MOV A,T02SB CJNE A,#04H,NEXT MOV T02SA,#00H MOV T02SB,#00H CPL FLAG NEXT: JB FLAG,DONE CPL P1.0 DONE: RETI END 7. C語言源程序 #include <AT89X51.H> unsigned int t02s; unsigned char t05ms; bit flag;
void main(void) { TMOD=0x01; TH0=(65536-500)/256; TL0=(65536-500)%256; TR0=1; ET0=1; EA=1; while(1); }
void t0(void) interrupt 1 using 0 { TH0=(65536-500)/256; TL0=(65536-500)%256; t02s++; if(t02s==400) { t02s=0; flag=~flag; } if(flag==0) { P1_0=~P1_0; } }
19. “叮咚”門鈴
1. 實驗任務
當按下開關SP1,AT89S51單片機產生“叮咚”聲從P1.0端口輸出到LM386,經過放大之后送入喇叭。
2. 電路原理圖
圖4.19.1
3. 系統板上硬件連線
(1. 把“單片機系統”區域中的P1.0端口用導線連接到“音頻放大模塊”區域中的SPK IN端口上;
(2. 在“音頻放大模塊”區域中的SPK OUT端口上接上一個8歐或者是16歐的喇叭;
(3. 把“單片機系統”區域中的P3.7/RD端口用導線連接到“獨立式鍵盤”區域中的SP1端口上;
4. 程序設計方法
(1. 我們用單片機實定時/計數器T0來產生700HZ和500HZ的頻率,根據定時/計數器T0,我們取定時250us,因此,700HZ的頻率要經過3次250us的定時,而500HZ的頻率要經過4次250us的定時。
(2. 在設計過程,只有當按下SP1之后,才啟動T0開始工作,當T0工作完畢,回到最初狀態。
(3. “叮”和“咚”聲音各占用0.5秒,因此定時/計數器T0要完成0.5秒的定時,對于以250us為基準定時2000次才可以。
5. 程序框圖
主程序框圖
T0中斷服務程序框圖
圖4.19.2
6. 匯編源程序 T5HZ EQU 30H T7HZ EQU 31H T05SA EQU 32H T05SB EQU 33H FLAG BIT 00H STOP BIT 01H SP1 BIT P3.7 ORG 00H LJMP START ORG 0BH LJMP INT_T0 START: MOV TMOD,#02H MOV TH0,#06H MOV TL0,#06H SETB ET0 SETB EA NSP: JB SP1,NSP LCALL DELY10MS JB SP1,NSP SETB TR0 MOV T5HZ,#00H MOV T7HZ,#00H MOV T05SA,#00H MOV T05SB,#00H CLR FLAG CLR STOP JNB STOP,$ LJMP NSP DELY10MS: MOV R6,#20 D1: MOV R7,#248 DJNZ R7,$ DJNZ R6,D1 RET INT_T0: INC T05SA MOV A,T05SA CJNE A,#100,NEXT MOV T05SA,#00H INC T05SB MOV A,T05SB CJNE A,#20,NEXT MOV T05SB,#00H JB FLAG,STP CPL FLAG LJMP NEXT STP: SETB STOP CLR TR0 LJMP DONE NEXT: JB FLAG,S5HZ INC T7HZ MOV A,T7HZ CJNE A,#03H,DONE MOV T7HZ,#00H CPL P1.0 LJMP DONE S5HZ: INC T5HZ MOV A,T5HZ CJNE A,#04H,DONE MOV T5HZ,#00H CPL P1.0 LJMP DONE DONE: RETI END
7. C語言源程序 #include <AT89X51.H> unsigned char t5hz; unsigned char t7hz; unsigned int tcnt;
bit stop; bit flag;
void main(void) { unsigned char i,j;
TMOD=0x02; TH0=0x06; TL0=0x06; ET0=1; EA=1;
while(1) { if(P3_7==0) { for(i=10;i>0;i--) for(j=248;j>0;j--); if(P3_7==0) { t5hz=0; t7hz=0; tcnt=0; flag=0; stop=0; TR0=1; while(stop==0); } } } }
void t0(void) interrupt 1 using 0 { tcnt++; if(tcnt==2000) { tcnt=0; if(flag==0) { flag=~flag; } else { stop=1; TR0=0; } } if(flag==0) { t7hz++; if(t7hz==3) { t7hz=0; P1_0=~P1_0; } } else { t5hz++; if(t5hz==4) { t5hz=0; P1_0=~P1_0; } } } |