《單片機原理及應用》課件1第3章_第1頁
《單片機原理及應用》課件1第3章_第2頁
《單片機原理及應用》課件1第3章_第3頁
《單片機原理及應用》課件1第3章_第4頁
《單片機原理及應用》課件1第3章_第5頁
已閱讀5頁,還剩83頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領

文檔簡介

第3章輸入口及其應用3.18051的輸入/輸出口3.2控制轉(zhuǎn)移類指令3.3輸入電路設計3.4設計課目與演練——按鍵控制LED小結(jié)

習題

本章重點講述輸入/輸出(I/O)口的內(nèi)部結(jié)構(gòu),并把輸入/輸出口與特殊功能寄存器、控制信號等之間建立關聯(lián),結(jié)合跳轉(zhuǎn)指令和端口輸入電路設計,給出了實例。第3章、第4章和第5章內(nèi)容的內(nèi)在聯(lián)系比較密切,都在講輸入/輸出口及其應用,但側(cè)重點有所不同。本章重點是講I/O口的內(nèi)部結(jié)構(gòu)和輸入電路的設計與保護,第4章重點講外部電路和驅(qū)動,第5章把輸入/輸出合起來講應用。其中外設的擴展方法和地址確定是對2.4節(jié)存儲器擴展方法的進一步講解和應用。3.18051的輸入/輸出口

MCS—51單片機共有4個8位的并行I/O口,分別記做P0、P1、P2、P3,共32個端子。這4個端口為MCS—51單片機與外部器件或外部設備進行信息(數(shù)據(jù)、地址、控制信號)交換提供了多功能的輸入/輸出通道,也為MCS—51單片機擴展外部功能,構(gòu)成應用系統(tǒng)提供了必要的條件;在內(nèi)部RAM中有特殊功能寄存器與其對應,并且具有位尋址功能。3.1.1輸入/輸出口的內(nèi)部結(jié)構(gòu)與操作

MCS—51單片機的4個并行I/O口中每一位的結(jié)構(gòu)如圖3-1所示。由于4個端口的功能有所不同,因此,它們在電路結(jié)構(gòu)上也有區(qū)別,但其工作原理基本相似。從圖3-1可以看出,端口的每一位都有一個鎖存器、一個輸出驅(qū)動器(場效應管)和一個輸入數(shù)據(jù)緩沖器。其中鎖存器為D型觸發(fā)器,在CPU的控制下,可對P0~P3口的鎖存器進行讀—修改—寫操作和對端子進行讀寫操作。

1.?P0口

1)?P0口作為通用I/O口使用當MCS—51單片機的CPU對片內(nèi)存儲器和I/O口進行讀寫時,由硬件置控制線為0,使開關MUX處于圖3-1(a)所示位置,輸出級V2與鎖存器端相連。同時使上拉場效應管V1處于截止狀態(tài),此時輸出級是開漏電路,P0口作一般的I/O口使用。

P0口用作輸出。在CPU執(zhí)行輸出指令時,寫脈沖加到鎖存器的CLK上,與內(nèi)部總線相連的D端數(shù)據(jù)取反后出現(xiàn)在端上,再經(jīng)V2反相,出現(xiàn)在P0口上的數(shù)據(jù)正好是內(nèi)部總線的數(shù)據(jù)。圖3-1輸入/輸出口的內(nèi)部結(jié)構(gòu)

P0口用作輸入。在CPU執(zhí)行端口輸入指令時,讀端子信號打開下部的緩沖器,P0口上的數(shù)據(jù)經(jīng)緩沖器讀到內(nèi)部數(shù)據(jù)總線上。

2)?P0口作為地址/數(shù)據(jù)總線使用當MCS—51單片機進行外部存儲器擴展,CPU對片外存儲器進行讀寫時,由硬件置控制線為1,開關MUX撥向上方,此時P0口作地址/數(shù)據(jù)總線使用。

P0口用作輸出地址/數(shù)據(jù)總線使用。在MCS—51單片機與外部擴展存儲器或外圍器件組成的系統(tǒng)中,P0口輸出低8位地址或數(shù)據(jù)。此時MUX將CPU內(nèi)部地址/數(shù)據(jù)總線經(jīng)反相后與V2相連,這樣,由圖可以看出,V1與V2構(gòu)成推拉式輸出電路,從而增大了負載能力。

?由P0口輸入數(shù)據(jù)。當讀端子信號有效時,打開輸入緩沖器,使輸入端口的數(shù)據(jù)進入內(nèi)部總線。綜上所述,當P0作通用I/O口輸出時,輸出級屬開漏電路,因此必須外接上拉電阻,才有高電平輸出。P0口外接上拉電阻的電路如圖3-2所示,電阻值一般在5.1~10kΩ范圍內(nèi)選擇。如果8位都需要上拉電阻,則可以使用排阻,如圖3-3所示。注意:圖中標注的節(jié)點為P0.0、P0.1、…、P0.7,是強調(diào)把P0口作為I/O口使用。P0口作為地址/數(shù)據(jù)使用時,常標注為D0、D1、D2、…、D7,此時P0口不需要上拉電阻。因此,P0口在作普通I/O口使用時,其不是一個真正的雙向I/O口,而是準雙向;但是在作地址/數(shù)據(jù)總線時,它是一個真正的雙向口,并且可以驅(qū)動8個LSTTL負載。圖3-2外接上拉電阻的電路圖3-3都使用上拉電阻

2.?P1口

P1口一般用作通用I/O口,可用于位處理,各位都可以單獨輸入或輸出。

P1口同樣是準雙向的I/O口,當需要某位先輸出然后再輸入的時候,應該在輸入操作前加一條輸出1的指令,然后再輸入信息才正確。對于復位后,由于各位鎖存器均置為1,端輸出為0,下拉場效應管截止,因此,各位用作輸出或者輸入都是正確的。

輸出1時,端為0,場效應管截止,此時,P1.x靠上拉電阻輸出1,這個時候驅(qū)動能力比較差。所以,當輸出1而需要帶動較大負載時,常常需要外加驅(qū)動電路(詳細見第4章)。

輸出0時,端為1,場效應管打開,此時,P1.x強制輸出0,這個時候驅(qū)動能力較強。因此,當輸出為0時,一般不需要外加驅(qū)動。正是基于這點考慮,驅(qū)動LED時常用的接法如圖3-4所示。

對于AT89S52,P1口的某些引腳還可以有第二功能。P1.0引腳用于定時/計數(shù)器2的外部事件計數(shù)輸入端口,P1.1引腳用于定時/計數(shù)器2的外部控制端口。P1.5~P1.7還用于片內(nèi)Flash的編程。圖3-4驅(qū)動LED的方法

3.?P2口

P2口的位結(jié)構(gòu)與P0口類似,輸出驅(qū)動部分與P1口類似,但多了一個轉(zhuǎn)換控制部分。當CPU對片內(nèi)存儲器和I/O口進行讀寫時,內(nèi)部硬件使MUX接通Q端,此時,P2口作一般的I/O口使用,作用及用法與P1口相同。當CPU對片外存儲器或I/O口進行讀寫時,MUX選擇地址總線,此時,P2口輸出的是高8位地址,這樣就可以擴展片外存儲器(ROM或者RAM)。由于CPU訪問片外存儲器的操作往往是連續(xù)進行的,P2口要不斷地送出高8位地址,因此P2口此時不能用作通用I/O口。

4.?P3口

P3口與P1口相比,多了非門和輸入數(shù)據(jù)緩沖器,這使P3口除了具有P1口的準雙向I/O功能外,?還可以使用該端口具有的第二功能。當?shù)诙δ茌敵龆藶?時,輸出Q端信號;當D鎖存器輸出為1時,輸出第二功能信號。

P3口作通用I/O口使用。P3口作通用I/O使用時,其工作原理與P1口類似,第二功能輸出端保持高電平,D鎖存器的Q端狀態(tài)經(jīng)與非門和V2輸出。

P3口作為輸入使用時,應先用軟件向端口鎖存器寫1,使Q端為1,經(jīng)與非門輸出為0,V2截止。此時,CPU給出讀端子信號,將端子上的信號經(jīng)緩沖器1和輸入三態(tài)緩沖器送到內(nèi)部總線。

P3口作第二功能使用。當P3口的某位被用作第二功能時,內(nèi)部硬件自動設置該位端口鎖存器的Q端為1,使與非門可以輸出第二功能輸出端狀態(tài)。第二功能輸出端主要指對TXD、、的輸出。由于P3口用作第二功能時D鎖存器Q端已置1,第二功能輸出端不作輸出時也保持為1,使得輸出V2截止。由于此時端口已不作為通用I/O口,讀端子信號無效,輸入三態(tài)緩沖器不導通,這樣P3口端子的第二功能輸入信號(RXD、、、T0、T1)經(jīng)緩沖器1送入第二功能輸入端。P3口各位對應的第二功能如表3-1所示。表3-1P3口的第二功能3.1.2輸入/輸出口的應用與擴展

1.輸入/輸出口的應用特點

各輸入/輸出口的適用功能。P0口一般用作數(shù)據(jù)/低8位地址復用口,P1口一般作I/O擴展口用,P2口作高8位地址和I/O擴展的地址譯碼用,P3口作中斷輸入、串行通信口用。在實際應用系統(tǒng)中,僅靠單片機自帶的資源很難達到系統(tǒng)的要求,需要外部功能的擴展,尤其是需要外部程序存儲器或數(shù)據(jù)存儲器的擴展。因此,在單片機的系統(tǒng)設計中,經(jīng)常要擴展I/O口。

各輸入/輸出口的使用方法和驅(qū)動能力。在單片機應用中,P0口作為I/O口使用時,需要外加上拉電阻,而P1、P2、P3口內(nèi)部設有上拉電阻,不用外加。這4個I/O口均為準雙向I/O口,其驅(qū)動能力不同:P0口的驅(qū)動能力最強,可以驅(qū)動8個LSTTL負載;其余3個端口只能驅(qū)動4個LSTTL負載。

各輸入/輸出口的兩種讀方式。由圖3-1可見,每個I/O均有兩種讀入方法,即讀鎖存器和讀引腳,并有相應的指令。讀鎖存器指令也稱為讀—修改—寫指令,如表3-2所示。當目的操作數(shù)為某一I/O口或者I/O口的某一位時,這些指令均為讀—修改—寫指令。讀引腳指令一般是以I/O口為源操作數(shù)的指令。執(zhí)行讀引腳指令時,打開三態(tài)門,輸入端口引腳狀態(tài)。例如,P1口在輸入狀態(tài)時的讀引腳指令為:MOVA,P1。表3-2讀—修改—寫指令

2.擴展實例這里使用常用的鎖存器、三態(tài)門等芯片進行并行I/O擴展,電路如圖3-5所示。該電路中,74LS273作為端口的擴展輸出,74LS244作為端口的擴展輸入。如果系統(tǒng)中還有其它擴展I/O口,則可以使用線選法或譯碼法分配其地址空間。下面分析電路的原理。

輸出控制信號由引腳P2.0和取或運算而得。當兩者都為低電平的時候,或門輸出為0,將P0口的數(shù)據(jù)鎖存到74LS273中。74LS273的輸出控制發(fā)光二極管,當某位引腳輸出高電平時,對應的發(fā)光二極管點亮。

輸入控制信號由引腳P2.0和取或運算而得。當兩者都為低電平時,或門輸出為0,此時選通74LS244,將外部的數(shù)據(jù)信息輸入到總線。圖3-5中的某按鍵按下時,讀到的相應位為0,否則為1。

輸入和輸出都是在P2.0引腳為0的時候有效的,分別用和區(qū)別控制輸入和輸出,因此不會產(chǎn)生輸入和輸出的沖突。在程序中訪問擴展I/O口時,用MOVX指令實現(xiàn)。例如,現(xiàn)在要把按鍵狀態(tài)讀入到A中,然后輸出到LED上顯示,完成該功能的程序段為:

MOV

DPTR,#0FEFFH ;擴展I/O的設備地址

MOVX

A,@DPTR ;由信號識別現(xiàn)在是選通74LS244,讀按鍵

MOVX

@DPTR,A;由信號識別現(xiàn)在是寫LS273, ;控制LED發(fā)光注意:上面的指令是逐步運行的,這樣由上至下逐條執(zhí)行指令的結(jié)構(gòu)就是所謂的順序結(jié)構(gòu)。圖3-5I/O口擴展實例3.2控制轉(zhuǎn)移類指令程序通常是按由上至下的指令順序運行的,程序的順序執(zhí)行是由程序計數(shù)器PC自動加1實現(xiàn)的。為了適應復雜的測控系統(tǒng)的需要,經(jīng)常需要改變程序的執(zhí)行順序,實現(xiàn)分支轉(zhuǎn)向,這種情況稱為“程序轉(zhuǎn)移”。控制轉(zhuǎn)移類指令一般是通過改變PC值來實現(xiàn)的,因此該類指令的作用區(qū)域就是PC能夠訪問的程序存儲器空間??刂妻D(zhuǎn)移類指令共有22條,包括無條件轉(zhuǎn)移、條件轉(zhuǎn)移、子程序調(diào)用及返回指令等,具體如表3-3所示??刂妻D(zhuǎn)移類指令一般不影響標志位。表3-3控制轉(zhuǎn)移類指令續(xù)表續(xù)表3.2.1無條件轉(zhuǎn)移圖3-6所示是4條無條件跳轉(zhuǎn)指令的執(zhí)行要點和跳轉(zhuǎn)范圍。下面舉例進一步說明。

1.?LJMP、AJMP、SJMP這三條指令都是跳轉(zhuǎn)指令,執(zhí)行過程分別如圖3-6(a)、(c)、(b)所示。可以看出,LJMP在整個64KB的程序存儲器空間范圍內(nèi)直接跳轉(zhuǎn),與當前指令位置無關。AJMP是在當前指令的下一條指令所在的2KB范圍內(nèi)跳轉(zhuǎn),執(zhí)行時把當前指令的PC值加2,然后把PC的低11位換成AJMP指令當中的11位地址。SJMP則是把當前指令的PC值加2后,再把PC值與指令中的符號數(shù)rel相加,形成一個以當前PC+2為基點的-128~127范圍的跳轉(zhuǎn)空間。在實際編寫程序時,程序員不需要人為去計算上面提到的偏移距離或跳轉(zhuǎn)的范圍,而是在跳轉(zhuǎn)指令中使用標號(參考1.5.2節(jié)),編譯程序會自動進行計算,實現(xiàn)程序員所希望的跳轉(zhuǎn)。圖3-6幾條無條件跳轉(zhuǎn)指令的執(zhí)行過程

2.

JMP@A+DPTR這是間接轉(zhuǎn)移指令,也稱散轉(zhuǎn)指令。轉(zhuǎn)移地址由數(shù)據(jù)指針DPTR與累加器A中的8位無符號數(shù)相加而形成。其執(zhí)行結(jié)構(gòu)如圖3-6(d)所示。下面是幾個跳轉(zhuǎn)指令的綜合應用,程序分析如圖3-7所示。

ORG0000H

LJMPJUMP1 JUMP2: MOVA,#02H JMP@A+DPTR JUMP1: MOVDPTR,#TABLE SJMPJUMP2

TABLE: AJMPPORT0

AJMPPORT1 AJMPPORT2

AJMPPORT3 SJMP$ PORT0: MOVP0,#00H PORT1: MOVP1,#01H PORT2: MOVP2,#02H PORT3: MOVP3,#03H END圖3-7幾個跳轉(zhuǎn)指令的綜合演示通過這個程序的學習,需要了解到:

程序不僅僅可以由上至下順序執(zhí)行,還可以打破順序跳著執(zhí)行。后面還要學習有條件的跳轉(zhuǎn)和調(diào)用。

在實際編程中,放在SJMP、AJMP指令后面的不是需要計算的rel和addr11,而是用標號表示的目的地址,如:SJMPJUMP2。具體指令中的地址則由編譯程序自動完成。

SJMP$是一種常用的程序原地執(zhí)行的寫法。后面學了循環(huán)后,就知道這是一個死循環(huán),在學習階段經(jīng)常使用。特別在上機實驗時,當執(zhí)行到這條指令后,程序不會退出,所以可以繼續(xù)觀察寄存器、MEMORY中的值。

上面的分析方法還是使用了μV3的匯編指令混合顯示方法。慢慢地適應這種學習方法,對于學習單片機編程可以收到事半功倍的效果。進一步:

圖3-7對于跳轉(zhuǎn)指令的跳轉(zhuǎn)地址有詳細的運算,圖3-6對于跳轉(zhuǎn)指令的跳轉(zhuǎn)過程有詳細的圖示,對比二者,進一步理解跳轉(zhuǎn)指令的執(zhí)行過程和原理。

思考驗證:仔細閱讀關于SJMPrel指令中rel的解釋。?指令SJMP$的作用是執(zhí)行原地跳轉(zhuǎn)(循環(huán)),由圖3-7中的解釋可以知道,這里的$實際獲得的值為0FEH,即-2。如果在程序中實際書寫的指令為:SJMP0FEH,則程序會怎樣執(zhí)行?先分析然后到機器上去驗證吧!3.2.2條件轉(zhuǎn)移條件轉(zhuǎn)移的原理是當程序設定的條件滿足時,進行程序的轉(zhuǎn)移,否則程序順序執(zhí)行。這一點在C程序中采用“if”語句進行描述。條件轉(zhuǎn)移結(jié)構(gòu)采用如圖3-8所示的流程圖描述。51所有的條件轉(zhuǎn)移指令都是采用相對尋址方式得到轉(zhuǎn)移目的地址,以rel作為8位偏移量。在編寫程序時,正像前面轉(zhuǎn)移指令所介紹的一樣,常用目的地址的標號來代替rel,由匯編或者其他的編譯器自動換算成8位相對地址。后面的解釋不再使用相對地址,而是直接采用程序編寫時使用的標號地址。圖3-8條件轉(zhuǎn)移流程圖根據(jù)判斷條件把條件轉(zhuǎn)移指令劃分為4類(如表3-3所示):

累加器判零轉(zhuǎn)移指令;

數(shù)值比較判等轉(zhuǎn)移指令;

減1判零轉(zhuǎn)移指令;

判位轉(zhuǎn)移指令。下面在程序中對相關的指令進行解釋。

(1)程序如下(仍使用前面圖3-5所示的電路):

ORG 0000H LJMP MAIN ORG 0040H

MAIN: MOV SP,#30H MOV DPTR,#0FEFFH ;設置控制字

MOVX A,@DPTR ;讀按鍵狀態(tài)

JZ LED_OFF ;判斷A是否為0 MOV A,#01H ;如果不為0,

MOVX @DPTR,A ;則點亮D0 SJMP GOON ;跳轉(zhuǎn)

LED_OFF:

MOV A,#00H ;否則熄滅D0 MOVX @DPTR,A

GOON:

SJMP$

END對該程序的分析如圖3-9所示。進一步:

這個程序完成的功能是:如果8個按鍵全部閉合,則發(fā)光二極管D0熄滅,否則D0點亮。

注意看上面的分析,“如果…,則…,否則…”,還有圖3-8所示的流程圖,這就是程序的基本結(jié)構(gòu)之一:選擇結(jié)構(gòu)。

分析圖中,陰影部分作為以后常用的程序結(jié)構(gòu)框架,以后再舉例時,這一部分一般不再給出。讀者只要把程序段填充到這個框架中,就可以運行了。當然,這里面不包括中斷部分,以后還要給這個框架補充內(nèi)容。

就這個程序完成的功能而言,里面有不少的“廢話”。這個以后再解釋。

這個程序只對鍵盤判斷一次,并且對LED0的狀態(tài)也只是操作一次,如何動態(tài)監(jiān)測并且及時更新輸出呢?請繼續(xù)學習。圖3-9程序分析

(2)程序如下:

DELAY: MOV R0,#00H ;延時控制

DELAY1: MOV R1,#00H ;

DJNZ R1,$ ;

DJNZ R0,DELAY1這個程序段前面已經(jīng)出現(xiàn)過,現(xiàn)在解釋如下:①

DJNZR1,$:該語句先把R1的值減1,然后判斷是否為0,若不為0,則跳轉(zhuǎn),因為是跳轉(zhuǎn)到$,所以還是跳轉(zhuǎn)到本指令繼續(xù)執(zhí)行,再把R1的值減1,然后判斷是否為0,若不為0,則跳轉(zhuǎn),如此反復執(zhí)行下去;當判斷R1的值為0時,程序不再跳轉(zhuǎn),而是向下繼續(xù)執(zhí)行。執(zhí)行結(jié)構(gòu)如圖3-10所示。圖3-10DJNZR1,$的執(zhí)行結(jié)構(gòu)

如果R1的初始值為1,則執(zhí)行一次R1?=?R1-1(注:匯編語言當中沒有這種表達方式,但以后的C程序會有這種表達方式)后,R1的值為0,所以這個結(jié)構(gòu)只執(zhí)行一次;如果R1的初始值為2,那么執(zhí)行一次后R1的值變成1,再執(zhí)行一次后變成0,所以執(zhí)行2次;依此類推,如果R1的初始值為n(因為采用8位寄存器計數(shù),所以n不能大于255。如果控制的循環(huán)次數(shù)大于255怎么辦,請繼續(xù)學習),那么這個結(jié)構(gòu)的執(zhí)行次數(shù)就是n次。我們可以說,這個結(jié)構(gòu)循環(huán)執(zhí)行了n次。R1用于控制循環(huán)次數(shù),稱為循環(huán)控制變量。終于提出循環(huán)這個概念了。

循環(huán)結(jié)構(gòu)是程序的三大結(jié)構(gòu)之一,它包括循環(huán)體和循環(huán)出口控制結(jié)構(gòu)。其執(zhí)行流程如圖3-11所示。如果沒有退出循環(huán)的出口,我們稱這個循環(huán)為死循環(huán)。除非單片機重新啟動,否則程序?qū)⒂肋h循環(huán)。有時候我們要利用死循環(huán),但是有時候它卻會給我們帶來麻煩。要合理使用循環(huán),要謹慎使用死循環(huán)。圖3-11循環(huán)結(jié)構(gòu)

如果R1的初始值為00H,那么循環(huán)次數(shù)是多少呢?第一次變成FFH,到第256次的時候變成0,因此應當是256次。給循環(huán)變量賦值為0,得到的卻是最大循環(huán)控制次數(shù),請讀者注意類似的表達方式。②?DJNZR0,DELAY1:這個指令格式和①是一樣的,過程可以描述為:把R0的值減1,判斷R0是否為0,如果不為0,則跳轉(zhuǎn)去DELAY1處執(zhí)行;否則繼續(xù)向下順序執(zhí)行。該程序段的執(zhí)行結(jié)構(gòu)如圖3-12所示。進一步解釋:

DJNZR0,DELEY1構(gòu)成循環(huán)結(jié)構(gòu)。循環(huán)控制變量是R0,循環(huán)體是MOVR1,#00H和DJNZR1,$這兩條指令。而DJNZR1,$本身又是一個循環(huán),包含在DJNZ構(gòu)成的另一個循環(huán)中。這種循環(huán)體中還包含有循環(huán)的結(jié)構(gòu)稱為循環(huán)的嵌套。根據(jù)程序的需要,循環(huán)可以多重嵌套。被包含的循環(huán)稱為內(nèi)循環(huán),外圍的循環(huán)則稱為外循環(huán)。圖3-12循環(huán)的嵌套

如圖3-13所示,分析這個程序段占用的機器周期和對應的時間。單片機使用的晶振為12MHz,則一個機器周期的時間為所以1μs×[2+256×(2+2×256+2)]=192098μs這就是為什么把這段程序稱之為延時程序。如果需要精確延時,則還需要仔細計算里面的每一條指令,作出合理安排,配合得到精確延時。但是,精確的延時或者定時不會使用這樣的程序段,而是采用定時/計數(shù)器的方式,第7章會學到。圖3-13循環(huán)所占時間計算3.2.3子程序調(diào)用及返回在一個程序中經(jīng)常遇到反復多次執(zhí)行某功能程序段的情況,如果重復編寫這個程序段,會使程序冗長而且雜亂。常把這個經(jīng)常使用的具有一定功能的程序段單獨編寫,稱為子程序。在需要使用這個功能塊的程序處,設置一個子程序調(diào)用指令,就可以轉(zhuǎn)去執(zhí)行這個子程序。當遇到子程序中的返回指令時,就可以回到剛才調(diào)用子程序的斷點處繼續(xù)執(zhí)行。這樣不但減少了編程工作量,而且縮短了程序的長度,增加了程序的可讀性。子程序是一種重要的程序結(jié)構(gòu)。調(diào)用子程序的程序稱為“主程序”,主程序和子程序的調(diào)用關系如圖3-14所示。如果在子程序中又調(diào)用了其他子程序,則稱為子程序的嵌套,如圖3-15所示。調(diào)用和返回構(gòu)成子程序調(diào)用的完整的過程。調(diào)用出現(xiàn)在主程序中,而返回則出現(xiàn)在子程序的執(zhí)行終點處(但不一定是該子程序段的最后一條指令)。圖3-14子程序調(diào)用圖3-15子程序的嵌套

1.調(diào)用與返回

51單片機提供兩條子程序調(diào)用指令:LCALLaddr16和ACALLaddr11。addr16與addr11的使用方法和規(guī)則與LJMPaddr16、AJMPaddr11中的完全相同,這里不再贅述。程序調(diào)用時,單片機自動將當前PC入棧(注意,當前PC為當前指令的下一指令字節(jié)所在的地址,程序調(diào)用子程序返回后從該地址繼續(xù)向下執(zhí)行,稱為斷點地址,即子程序的返回地址),然后將標號所標示的調(diào)用地址送入PC,使程序轉(zhuǎn)到子程序中執(zhí)行,即所謂發(fā)生調(diào)用。標號即為子程序的入口地址。

51單片機提供的返回指令有子程序返回指令RET和中斷返回指令RETI。RET指令的功能是從堆棧中彈出子程序的斷點地址給PC,程序返回主程序斷點處繼續(xù)向下執(zhí)行。調(diào)用子程序時入棧的是斷點處的地址,現(xiàn)在執(zhí)行RET彈出斷點地址給PC后,程序轉(zhuǎn)移到調(diào)用時的斷點處繼續(xù)向下執(zhí)行,就是所謂的子程序調(diào)用的返回。RETI用于中斷返回,它除了把程序從中斷服務子程序返回到主程序的斷點處(即程序返回任務),還要清除中斷響應時被置位的優(yōu)先觸發(fā)器,開放較低級的中斷,恢復中斷邏輯等硬件設置。因此,RET、RETI這兩條指令不能交換使用。把3.2.2節(jié)中講的延時程序段設計成延時子程序:

DELAY:

MOV R0,#00H ;延時控制

DELAY1:MOV R1,#00H ;

DJNZ R1,$ ;

DJNZ R0,DELAY1 ;

RET把該延時子程序放到一個程序段中進一步解釋:

LOOP: MOV DPTR,#0FEFFH

MOV A,#01H

MOVX @DPTR,A

LCALL DELAY

MOV A,#02H

MOVX @DPTR,A

LCALL DELAY

SJMP LOOP

DELAY: MOV R0,#00H

DELAY1: MOV R1,#00H

DJNZ R1,$

DJNZ R0,DELAY1

RET子程序調(diào)用的分析如圖3-16所示。圖3-16子程序調(diào)用分析圖示進一步分析:

該程序段兩次調(diào)用了DELAY子程序,作為延時子程序。注意有陰影的那兩條指令。

SJMPLOOP構(gòu)成了無條件控制的循環(huán),而且循環(huán)沒有出口,這就是死循環(huán)。這是利用這個循環(huán)構(gòu)成了讓LED0、LED1不停地亮滅的效果。注意:3.2.2節(jié)中已經(jīng)分析了這個延時程序段的執(zhí)行時間為192098μs,大概為0.2s,所以,兩個燈交替亮滅的頻率大概為1/(0.2?+?0.2)?=?2.5Hz。這個速度人眼是可以分辨出來的。當然,如果想改變亮滅的速度,應該怎么辦呢?請繼續(xù)向后學習。

程序可以在多個地方調(diào)用同一個子程序。該程序段調(diào)用子程序的框架如圖3-17所示。圖3-17在不同位置調(diào)用子程序圖示

2.現(xiàn)場保護在主程序調(diào)用子程序之前,累加器或工作寄存器中可能存放著主程序運算的中間結(jié)果,這些中間結(jié)果在主程序中仍然有用,子程序如果也用到這些寄存器,就需要在執(zhí)行子程序自身的功能前,將累加器、工作寄存器或其他可能被影響的單元內(nèi)容保護起來,即現(xiàn)場保護。這種保護是必須的,否則子程序返回后,會影響主程序的正常執(zhí)行。當子程序執(zhí)行完畢,要返回之前,可將保存的那些數(shù)據(jù)恢復到原來的寄存器或累加器中,這個過程稱為現(xiàn)場恢復?,F(xiàn)場保護通常是由堆棧來完成的,在子程序開始時使用入棧指令,將需要保護的寄存器內(nèi)容入棧。在子程序返回前,再將堆棧中保存的內(nèi)容對應彈出(出棧),即現(xiàn)場恢復。堆棧的操作具有后進先出的特點,因此入棧和出棧操作的順序相反。例如,DELEY子程序中使用到R0、R1寄存器,如果主程序中使用R0、R1,則為了不影響主程序?qū)υ摷拇嫫鞯氖褂茫谧映绦蛑芯鸵峁┍Wo。具體操作如下:

DELAY: PUSH 00H ;R0入棧

PUSH 01H ;R1入棧

MOV R0,#00H

DELAY1:MOV R1,#00H

DJNZ R1,$

DJNZ R0,DELAY1

POP 01H ;彈出時順序相反

POP 00H; RET進一步:

保護的目的是子程序的執(zhí)行不影響主程序,所以,如果子程序沒有影響主程序的因素,就不需要提供保護。

這里提供的這個保護方案,仔細研究有沒有問題?R0、R1對應的地址是受RS1、RS0位的影響的。當RS1RS0為00的時候,R0的地址就是00H,R1的地址就是01H,否則就不是。所以,這個保護本身是有問題的。那么,該怎么解決呢?

還有一種整體的解決方案。如果約定,主程序使用第0組工作寄存器,子程序使用第1組工作寄存器,那么只要控制RS1RS0的值就可以了。進入子程序的時候設置:SETBRS0;退出子程序前設置:CLRRS0。

還有其他的辦法,請讀者自己分析。

3.參數(shù)傳遞主程序調(diào)用子程序時,可以給子程序傳遞一些參數(shù),增加子程序的通用性。主程序傳給子程序的這些參數(shù)稱為入口參數(shù)。在調(diào)用子程序前,主程序應先把子程序所需要的入口參數(shù)放到某些約定的存儲單元中,進入子程序后,再從約定的單元取出入口參數(shù)進行處理。子程序完成任務后,應把處理結(jié)果傳遞給主程序,便于程序進一步處理。子程序傳給主程序的這些參數(shù)稱為出口參數(shù)。處理完任務后,子程序返回前,應把出口參數(shù)送到約定單元。返回主程序后,再從這些約定單元取得出口參數(shù)作進一步的處理。注:有些子程序不需要入口參數(shù)或出口參數(shù)。在MCS—51單片機中,進行參數(shù)傳遞的方法有多種:

用累加器或者工作寄存器進行傳遞;

用地址指針進行傳遞;

用堆棧傳遞參數(shù)。前面給出的DELAY延時程序的延時時間是固定的,是因為相關參數(shù)都是在DELAY子程序中固定,用立即數(shù)的形式給出。下面做一下簡單修改:

DELAY: ;MOV R0,#00H

DELAY1:

MOV R1,#00H

DJNZ R1,$ DJNZ R0,DELAY1 RET注意,在子程序中的MOVR0,#00H這條指令前面加了“;”,該指令被屏蔽了。這時調(diào)用DELAY子程序時,應先在主程序中給出R0的初始值。給出的初始值不同,延時時間也就不同。下面是調(diào)用示范程序,因為該示例程序比較簡單,讀者請自行分析。

LOOP: MOV DPTR,#0FEFFH

MOV A,#01H

MOVX @DPTR,A

MOV R0,#80H

LCALL DELAY MOV A,#02H

MOVX @DPTR,A

MOV R0,#30H

LCALL DELAY

SJMP LOOP

DELAY: ;MOV R0,#00H;注意,這條指令已被屏蔽

DELAY1: MOV R1,#00H

DJNZ R1,$ DJNZ R0,DELAY1 RET該示例程序中,R0成了DELAY這個子程序的入口參數(shù)。其他的傳遞形式以后會學到。3.2.4空操作NOP

NOP指令執(zhí)行一個空周期,它在程序中主要用于調(diào)整時間或者匹配時鐘。在寫程序存儲器時,沒有編程到的區(qū)域都是默認的00H,即為NOP。3.3輸入電路設計輸入電路是單片機與外部建立聯(lián)系的重要通道。輸入的穩(wěn)定可靠性,是單片機可以正確獲取外部信息的保證。對于計算機,目前市場上有很多兼容的成品輸入設備,如鍵盤、鼠標、掃描儀等。對于單片機,由于控制要求的復雜性和單片機本身型號的多樣性,目前基本沒有統(tǒng)一的可以在各型號間兼容使用的輸入設備。因此,對單片機工程師而言,每一個產(chǎn)品都要有輸入設備的設計,而且相互之間的輸入又可能不盡相同。但是,這些產(chǎn)品的輸入設備的工作原理還是基本相同的,初學者要掌握必要的基礎知識。這里先介紹開關信號的輸入,主要是實現(xiàn)人機接口的鍵盤輸入部分。關于模擬量的輸入在第9章介紹。鍵盤的輸入設計方案在三個章節(jié)中分階段闡述,為了讓讀者有個整體印象,簡介如下:

獨立式按鍵設計:側(cè)重于理論的講述和分析,給出較為基礎的鍵盤設計方案。本章介紹。

矩陣式鍵盤設計:系統(tǒng)介紹矩陣鍵盤的設計方法,給出鍵盤設計與實用中存在的深層次問題的探討與分析——重(chong)鍵和連擊。第5章介紹。

鍵盤設計方案的完善:介紹實用鍵盤的設計方法,應用中斷方式進行鍵盤設計。第6章介紹。

1.鍵盤輸入的特點鍵盤實質(zhì)上是一組按鍵開關的組合。通常,按鍵所用開關為機械彈性開關,均利用了機械觸點的合、斷作用。一個電壓信號通過機械觸點的斷開、閉合過程,其波形如圖3-18所示。由于機械觸點的彈性作用,一個按鍵開關在閉合時不會馬上穩(wěn)定的接通,在斷開時也不會一下斷開,而是有一連串的抖動。抖動時間的長短由按鍵的機械特性決定,一般為5~10ms。這個參數(shù)在后面的設計中會用到。按鍵的穩(wěn)定閉合時間長短是由鍵盤操作人員的按鍵動作決定的,一般為0.1~5s的時間。在設計中要參考利用這個時間參數(shù)。圖3-18按鍵抖動信號分析

2.按鍵的確認與消抖措施按鍵的閉合與否,反映在電壓上就是高電平或者低電平的變化,如果高電平代表斷開,那么低電平則表示閉合。所以,通過電平的高低狀態(tài)的檢測,便可確認按鍵是否按下。為了確保CPU對一次按鍵動作確認一次按鍵,必須消除抖動的影響。下面介紹軟件、硬件消抖的辦法。

1)基本RS觸發(fā)器構(gòu)成的消抖電路如圖3-19(a)所示,當開關由觸點1推向2時,在2點上會產(chǎn)生抖動,因為開關已經(jīng)離開1,所以這個時候觸點在2點上的抖動僅僅導致端在0和1之間的短暫跳變。但是端已經(jīng)為1,由基本RS觸發(fā)器的性質(zhì)知道,當端為0時,Q端輸出1;當端為1時,Q端保持原來的狀態(tài)不變。所以,Q端保持穩(wěn)定的輸出,沒有跳變。另一個過程同理。在圖3-19(b)中給出了相應的波形。圖3-19基本RS觸發(fā)器構(gòu)成的硬件消抖電路

2)濾波消抖電路濾波消抖原理圖如圖3-20所示??梢钥闯觯陂_關開、關的開始階段,存在一個不穩(wěn)定的電壓,消抖的關鍵是讓這個抖動的時間小于門電壓達到轉(zhuǎn)換電平所需要的時間。VH是非門轉(zhuǎn)換所需要的門開啟電壓,VL是門關閉電壓。在閉合時,抖動階段要在電壓達到VH之前結(jié)束;在斷開時,抖動階段要在電壓降到VL之前結(jié)束。這個時間可以通過改變R1、R2、C的值來調(diào)整充放電時間常數(shù),一般要保證C由穩(wěn)態(tài)電壓充電到開啟電壓或者放電到門關閉電壓的延遲時間大于等于10ms。這個延時時間可以根據(jù)電路進行計算,也可以通過實驗的方式獲得。圖中的參數(shù)僅供參考。圖3-20濾波消抖

3)軟件消抖當按鍵較多時,使用硬件消抖的方案便失去可行性,這時軟件消抖就是優(yōu)先選擇的方案。而且,軟件消抖也可以做得比較出色,其方法簡單,成本較低,因而得到了廣泛應用。軟件資料的基本原理是:當程序檢測到有按鍵按下時,執(zhí)行一個10ms的延時,然后再檢測一次,對比是否還是剛才的按鍵狀態(tài)。如果是,則確認按鍵并處理,否則可以認為是干擾,放棄處理,或作異常處理,從而消除抖動的影響。

3.獨立式按鍵接口設計所謂獨立式按鍵接口,是與目前常用的矩陣式鍵盤(第5章介紹)相比較而言的,具體指I/O口的獨立性,每一根口線作為一個獨立的按鍵輸入檢測。當按下或釋放按鍵時,輸入到I/O口的電平發(fā)生高低變化,程序依此來判斷是否有按鍵按下,并且可以識別具體的按鍵。獨立式按鍵電路配置靈活,軟件結(jié)構(gòu)簡單,如圖3-21所示。但其每個按鍵需占用一根輸入口線,在按鍵數(shù)量較多時,輸入口浪費大,電路結(jié)構(gòu)顯得很繁雜,故此種鍵盤使用于按鍵較少或操作速度要求較高的場合。下面介紹幾種獨立式按鍵的接口。

(1)圖3-21(a)為典型的獨立式按鍵工作電路。當某個按鍵按下時,相對應的輸入口線被拉低,讀入的這個端口對應的位為0,依此判斷是哪個按鍵被按下。至于圖中的上拉電阻,則是為了通用性。實際連接電路時,需要查詢所選用單片機的接口內(nèi)部是否有上拉電阻,如果有,則把外接的上拉電阻去掉,以免加重系統(tǒng)負擔。以后的電路都遵循這個規(guī)律。圖3-21獨立式按鍵接口設計獨立式按鍵的軟件結(jié)構(gòu)比較簡單,一般采用查詢方式。程序如下:

START: MOVP1,#0FFH ;為P1口讀入做準備

MOVA,P1 ;實質(zhì)上是暫存到R0,為了增加通用性

MOV00H,A ;使用00H LCALLDELAY10 ;調(diào)用延時10ms子程序

MOVA,P1 ;再次讀入按鍵狀態(tài)

CJNEA,00H,START ;如果還相同,則按鍵有效,并進行處理,否則返回到START

CJNEA,#0FEH,KEY_1 ;是否是第1個按鍵(P1.0)?不是就繼續(xù)判斷下一個

LJMPFUNC0 ;是就轉(zhuǎn)去執(zhí)行功能

KEY_1: CJNEA,#0FDH,KEY_2 ;是否是第2個按鍵(P1.1)?不是就繼續(xù)判斷下一個

LJMPFUNC1 ;是就轉(zhuǎn)去執(zhí)行功能

KEY_2: CJNEA,#0FBH,KEY_3 ;是否是第3個按鍵(P1.2)?不是就繼續(xù)判斷下一個

LJMPFUNC2 ;是就轉(zhuǎn)去執(zhí)行功能

KEY_3: CJNEA,#0F7H,KEY_4 ;是否是第4個按鍵(P1.3)?不是就繼續(xù)判斷下一個

LJMPFUNC3 ;是就轉(zhuǎn)去執(zhí)行功能

KEY_4: JBACC.4,KEY_5 ;是否是第5個按鍵(P1.4)?不是就繼續(xù)判斷下一個

LJMPFUNC4 ;注意,這里更換了判斷方式,其實質(zhì)沒變

KEY_5: JBACC.5,KEY_6 ;是否是第6個按鍵(P1.5)?不是就繼續(xù)判斷下一個

LJMPFUNC5 ;更換判斷方式的目的是給讀者提供更多的選擇

KEY_6: JBACC.6,KEY_7 ;是否是第7個按鍵(P1.6)?不是就繼續(xù)判斷下一個

LJMPFUNC6

KEY_7: LJMPFUNC7 ;如果能夠執(zhí)行到這里,就是第8個按鍵了

FUNC0: ;功能自己補充

LJMPSTART

FUNC1: ;功能自己補充

LJMPSTART

FUNC2: ;功能自己補充

LJMPSTART

FUNC3: ;功能自己補充

LJMPSTART…………

FUNC4: ;功能自己補充

LJMPSTART

FUNC5: ;功能自己補充

LJMPSTART

FUNC6: ;功能自己補充

LJMPSTART

FUNC7: ;功能自己補充

LJMPSTART

DELAY10: ;延時部分請讀者自己增加進一步解釋:

這個鍵盤程序是以程序段的形式出現(xiàn)的,其功能就是循環(huán)判斷是否有按鍵按下,如果有,則對應執(zhí)行該按鍵的功能。……………

按鍵功能部分省略,讀者可以根據(jù)自己的需要進行補充,替換掉省略號部分即可,比如:

FUNC0:MOV A,#01H

MOV DPTR,#0FEFFH

MOVX @DPTR,A

LJMP START如果和前面電路3-5對應,則可以控制LED。

判斷是否有按鍵的思路是:先讀入按鍵,延時10ms后再次讀入按鍵,如果兩次讀入的按鍵狀態(tài)相等,則說明是一個穩(wěn)定的按鍵,可以處理,否則放棄。這個判斷部分使用的指令是:

CJNE A, 00H, START實質(zhì)上執(zhí)行的是:

CJNE A,R0, START但是在μV3中不支持這個格式,所以采用了上面的形式,請讀者注意。讀者可以根據(jù)自己程序設置的情況來合理分配這個臨時比對單元。比如:

Key_TempEQU 40H

CJNE A, Key_Temp, START

判斷哪一個按鍵的思路是:把讀入的按鍵狀態(tài)從P1.0到P1.7逐位判定,哪一位為0,則對應該位上有按鍵按下。這里提供了兩種判斷思路:

CJNE A,#0FEH,KEY_1

LJMP FUNC0…這種判斷是基于這樣一種設定:同時只有一個按鍵按下,當一個按鍵按下時,相應的口線輸入為0,而其他的都為1。如果同時有兩個或兩個以上的按鍵按下,可以看出,上面的判斷將無效。在這種方式下,按鍵相互之間有影響。所

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責。
  • 6. 下載文件中如有侵權(quán)或不適當內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論