3.4.1 硬件電路
硬件電路采用實(shí)驗(yàn)開發(fā)板上的電路,如圖3.6所示。用S1~S4組成的鍵盤分別控制P1口發(fā)光二極管發(fā)光。

圖3.6 AT89S51單片機(jī)P1口外接8只LED發(fā)光二極管
3.4.2 程序設(shè)計(jì)
ORG 0000H
LJMP MAIN
ORG 0030H
MAIN: ORL P3,#3CH
MOV A,P3
ANL A,#3CH
MOV R0,A
CJNE A,#3CH,MAIN1
SJMP MAIN
MAIN1: MOV R1,#10
PDO: LCALL DELAY
DJNZ R1,PDO
MOV A,P3
CJNE A,R0,DODO
K_S1: JB P3.2,K_S2
LJMP KEY_1
K_S2: JB P3.3,K_S3
LJMP KEY_2
K_S3: JB P3.4,K_S4
LJMP KEY_3
K_S4: JB P3.5,DODO
LJMP KEY_4
DODO: SJMP MAIN
KEY_1: MOV P1,#0FDH
SJMP MAIN
KEY_2: MOV P1,#0FBH
SJMP MAIN
KEY_3: MOV P1,#0FEH
SJMP MAIN
KEY_4: MOV R1,#10
SPK2: MOV R2,#50H
SPK1: CPL P3.2
LCALL DELAY ;調(diào)用延時(shí)程序
DJNZ R2,SPK1
DJNZ R1,SPK2
SJMP MAIN
DELAY: MOV R3,#10
DEL: MOV R4,#50
DJNZ R4,$
DJNZ R3,DEL
END
3.4.3 源程序的編輯、編譯、下載
打開“偉福”模擬仿真軟件進(jìn)行程序的編輯、編譯。
打開“ISP下載軟件”將目標(biāo)文件下載到ISP-4實(shí)驗(yàn)開發(fā)板上的AT89S51單片機(jī)芯片,觀察程序運(yùn)行結(jié)果。
3.4.4 相關(guān)知識(shí)
1. 如何用按鍵控制燈?
按鍵是單片機(jī)常用的輸人控制設(shè)備,用于信息和命令的輸人,當(dāng)按鍵與燈的對(duì)應(yīng)關(guān)系建立后,單片機(jī)程序不斷輪流檢測(cè)S1~S4按鍵是否有鍵按下,當(dāng)有某鍵按下時(shí),單片機(jī)點(diǎn)亮相應(yīng)的燈。也就是說,每個(gè)按鍵都對(duì)應(yīng)了一個(gè)程序段,按下不同按鍵,程序就執(zhí)行相應(yīng)程序段,怎樣才能實(shí)現(xiàn)這種轉(zhuǎn)移呢?原來單片機(jī)中專門有一類控制轉(zhuǎn)移類指令。
2. MCS-51單片機(jī)有哪些控制轉(zhuǎn)移指令?
控制轉(zhuǎn)移指令用于控制程序的流向,所控制的范圍即為程序存儲(chǔ)器區(qū)間,MCS-51系列單片機(jī)的控制轉(zhuǎn)移指令相對(duì)豐富,有可對(duì)64kB程序空間地址單元進(jìn)行訪問的長(zhǎng)調(diào)用、長(zhǎng)轉(zhuǎn)移指令,也有可對(duì)2kB字節(jié)進(jìn)行訪問的絕對(duì)調(diào)用和絕對(duì)轉(zhuǎn)移指令,還有在一頁范圍內(nèi)短相對(duì)轉(zhuǎn)移及其它無條件轉(zhuǎn)移指令,這些指令的執(zhí)行一般都不會(huì)對(duì)標(biāo)志位有影響。
(1) 無條件轉(zhuǎn)移指令(4條)
這組指令執(zhí)行完后,程序就會(huì)無條件轉(zhuǎn)移到指令所指向的地址上去。長(zhǎng)轉(zhuǎn)移指令訪問的程序存儲(chǔ)器空間為16地址64kB,絕對(duì)轉(zhuǎn)移指令訪問的程序存儲(chǔ)器空間為11位地址2kB空間。
LJMP addr16 ;addr16→(PC),給程序計(jì)數(shù)器賦予新值的16位地址。
AJMP addr11 ;(PC)+2→(PC),addr11→(PC10-0)程序計(jì)數(shù)器賦予新值(11位地址),(PC15-11)不改變。
SJMP rel ;(PC)+ 2 + rel→(PC)當(dāng)前程序計(jì)數(shù)器先加上2再加上偏移量給程序計(jì)數(shù)器賦予新值。
JMP @A+DPTR ;(A)+ (DPTR)→(PC),累加器所指向地址單元的值加上數(shù)據(jù)指針的值給程序計(jì)數(shù)器賦予新值。
如:任務(wù)中的 LJMP MAIN 指令,就屬無條件轉(zhuǎn)移指令。
(2) 條件轉(zhuǎn)移指令(8條)
程序可利用這組豐富的指令根據(jù)當(dāng)前的條件進(jìn)行判斷,看是否滿足某種特定的條件,從而控制程序的轉(zhuǎn)向。
JZ rel ; A=0,(PC)+ 2 + rel→(PC),累加器中的內(nèi)容為0,則轉(zhuǎn)移到偏移量所指向的地址,否則程序往下執(zhí)行。
JNZ rel ; A≠0,(PC)+ 2 + rel→(PC),累加器中的內(nèi)容不為0,則轉(zhuǎn)移到偏移量所指向的地址,否則程序往下執(zhí)行。
CJNE A, data, rel ; A≠(data),(PC)+ 3 + rel→(PC),累加器中的內(nèi)容不等于直接地址單元的內(nèi)容,則轉(zhuǎn)移到偏移量所指向的地址,否則程序往下執(zhí)行。
CJNE A, #data, rel ; A≠#data,(PC)+ 3 + rel→(PC),累加器中的內(nèi)容不等于立即數(shù),則轉(zhuǎn)移到偏移量所指向的地址,否則程序往下執(zhí)行。
CJNE Rn, #data, rel ; A≠#data,(PC)+ 3 + rel→(PC),工作寄存器Rn中的內(nèi)容不等于立即數(shù),則轉(zhuǎn)移到偏移量所指向的地址,否則程序往下執(zhí)行。
CJNE @Ri, #data, rel ; A≠#data,(PC)+ 3 + rel→(PC),工作寄存器Ri指向地址單元中的內(nèi)容不等于立即數(shù),則轉(zhuǎn)移到偏移量所指向的地址,否則程序往下執(zhí)行。
DJNZ Rn, rel ; (Rn)-1→(Rn),(Rn)≠0,(PC)+ 2 + rel→(PC)工作寄存器Rn減1不等于0,則轉(zhuǎn)移到偏移量所指向的地址,否則程序往下執(zhí)行。
DJNZ data, rel ; (Rn)-1→(Rn),(Rn)≠0,(PC)+ 2 + rel→(PC)直接地址單元中的內(nèi)容減1不等于0,則轉(zhuǎn)移到偏移量所指向的地址,否則程序往下執(zhí)行。
在上面任務(wù)中就有此類指令,大家找一找,并且分析他們的功能。
(3) 子程序調(diào)用指令(1條)
子程序是為了便于程序編寫,減少那些需反復(fù)執(zhí)行的程序占用多余的地址空間而引入的程序分支,從而有了主程序和子程序的概念,需要反復(fù)執(zhí)行的一些程序,我們?cè)诰幊虝r(shí)一般都把它們編寫成子程序,當(dāng)需要用它們時(shí),就用一個(gè)調(diào)用命令使程序按調(diào)用的地址去執(zhí)行,這就需要子程序的調(diào)用指令和返回指令。
LCALL addr16 ; 長(zhǎng)調(diào)用指令,可在64kB空間調(diào)用子程序。此時(shí)(PC)+ 3→(PC),(SP)+ 1→(SP),(PC7-0)→(SP),(SP)+ 1→(SP),(PC15-8)→(SP),addr16→(PC),即分別從堆棧中彈出調(diào)用子程序時(shí)壓入的返回地址。
ACALL addr11 ; 絕對(duì)調(diào)用指令,可在2kB空間調(diào)用子程序,此時(shí)(PC)+ 2→(PC),(SP)+ 1→(SP),(PC7-0)→(SP),(SP)+ 1→(SP),(PC15-8)→(SP),addr11→(PC10-0)。
RET ; 子程序返回指令。此時(shí)(SP)→(PC15-8),(SP)- 1→(SP),(SP)→(PC7-0),(SP)- 1→(SP)。
RETI ; 中斷返回指令,除具有RET功能外,還具有恢復(fù)中斷邏輯的功能,需注意的是,RETI指令不能用RET代替。
如:任務(wù)中的 LCALL DELAY 指令,請(qǐng)你分析這條指令的執(zhí)行過程。
(4) 空操作指令(1條)
這條指令將累加器中的內(nèi)容清0。
NOP ; 這條指令除了使PC加1,消耗一個(gè)機(jī)器周期外,沒有執(zhí)行任何操作??捎糜诙虝r(shí)間的延時(shí)。
3. 控制轉(zhuǎn)移指令應(yīng)用舉例
【例3.10】 將外部數(shù)據(jù)RAM的一個(gè)數(shù)據(jù)塊傳送到內(nèi)部數(shù)據(jù)RAM,兩者的首址分別為DATA1和DATA2,遇到傳送的數(shù)據(jù)為零時(shí)停止。
解:外部RAM的數(shù)據(jù)傳送一定要以累加器A作為過渡,利用判零條件轉(zhuǎn)移正好可以判別是否要繼續(xù)傳送或者終止。完成數(shù)據(jù)傳送的參考程序如下:
MOV R0,#DATA1 ;外部數(shù)據(jù)塊首址送R0
MOV R1,#DATA2 ;內(nèi)部數(shù)據(jù)塊首址送R1
LOOP:MOV A,@ R0 ;取外部RAM數(shù)據(jù)入A
HERE: JZ HERE ;數(shù)據(jù)為零則終止傳送
MOV @ R1, A ;數(shù)據(jù)傳送至內(nèi)部RAM單元
INC R0 ;修改地址指針,指向下一數(shù)據(jù)地址
INC R1
SJMP LOOP ;循環(huán)取數(shù)
注意:以上程序中,寫在指令SJMP LOOP 中的LOOP處的8位相對(duì)轉(zhuǎn)移偏移量rel,而地址標(biāo)號(hào)LOOP 表示MOVX指令的16位單元地址。
【例3.11】 將內(nèi)部數(shù)據(jù)RAM中從DATA單元開始的10個(gè)無符號(hào)數(shù)相加,相加結(jié)果送SUM單元保存。
解:設(shè)相加結(jié)果不超過8位二進(jìn)制數(shù),則相應(yīng)的程序如下:
MOV R0,#0AH ;給R0置計(jì)數(shù)器初值
MOV R1,#DATA ;數(shù)據(jù)塊首址送R1
CLR A ;A清零
LOOP:ADD A,@ R1 ;加1個(gè)數(shù)
INC R1 ;修改地址,指向下一個(gè)數(shù)
DJNZ R0,LOOP ;R0減1,不為零循環(huán)
MOV SUM,A ;存10個(gè)數(shù)相加和
