<acronym id="xonnx"></acronym>
      <td id="xonnx"></td>
    1. <pre id="xonnx"></pre>

      1. 專注電子技術學習與研究
        當前位置:單片機教程網 >> MCU設計實例 >> 瀏覽文章

        MCS-51單片機匯編指令詳解

        作者:佚名   來源:本站原創   點擊數:  更新時間:2014年03月16日   【字體:
        以累加器為目的操作數的指令
         

               MOV A,Rn

               MOV A,direct

               MOV A,@Ri

               MOV A,#data

           第一條指令中,Rn代表的是R0-R7。第二條指令中,direct就是指的直接地址,而第三條指令中,就是我們剛才講過的。第四條指令是將立即數data送到A中。

         下面我們通過一些例子加以說明:

               MOV A,R1 ;將工作寄存器R1中的值送入A,R1中的值保持不變。

               MOV A,30H ;將內存30H單元中的值送入A,30H單元中的值保持不變。

               MOV A,@R1 ;先看R1中是什么值,把這個值作為地址,并將這個地址單元中的值送入A中。如執行命令前R1中的值為20H,則是將20H單元中的值送                          入A中。

                MOV A,#34H ;將立即數34H送入A中,執行完本條指令后,A中的值是34H。

         

            以寄存器Rn為目的操作的指令

               MOV Rn,A

               MOV Rn,direct

               MOV Rn,#data

               這組指令功能是把源地址單元中的內容送入工作寄存器,源操作數不變。

         

            以直接地址為目的操作數的指令

               MOV direct,A 例: MOV 20H,A

               MOV direct,Rn MOV 20H,R1

               MOV direct1,direct2 MOV 20H,30H

               MOV direct,@Ri MOV 20H,@R1

               MOV direct,#data MOV 20H,#34H

         

            以間接地址為目的操作數的指令

               MOV @Ri,A 例:MOV @R0,A

               MOV @Ri,direct MOV @R1,20H

               MOV @Ri,#data MOV @R0,#34H

         

            十六位數的傳遞指令

               MOV DPTR,#data16

               8051是一種8位機,這是唯一的一條16位立即數傳遞指令,其功能是將一個16位的立即數送入DPTR中去。其中高8位送入 DPH(083H),低8位送入DPL(082H)。例:MOV DPTR,#1234H,則執行完了之后DPH中的值為12H,DPL中的值為34H。反之,如果我們分別向DPH,DPL送數,則結果也一樣。如有下面兩條指令:MOV DPH,#35H,MOV DPL,#12H。則就相當于執行了MOV DPTR,#3512H。

         

            累加器A與片外RAM之間的數據傳遞類指令

               MOVX A,@Ri

               MOVX @Ri,A

               MOVX #9; A,@DPTR

               MOVX @DPTR,A

         說明:

               1)在51中,與外部存儲器RAM打交道的只可以是A累加器。所有需要送入外部RAM的數據必需要通過A送去,而所有要讀入的外部RAM中的數據也必需通過A讀入。在此我們可以看出內外部RAM的區別了,內部RAM間可以直接進行數據的傳遞,而外部則不行,比如,要將外部RAM中某一單元(設為 0100H單元的數據)送入另一個單元(設為0200H單元),也必須先將0100H單元中的內容讀入A,然后再送到0200H單元中去。

               2)要讀或寫外部的RAM,當然也必須要知道RAM的地址,在后兩條指令中,地址是被直接放在DPTR中的。而前兩條指令,由于Ri(即R0或 R1)只是一個8位的寄存器,所以只提供低8位地址。因為有時擴展的外部RAM的數量比較少,少于或等于256個,就只需要提供8位地址就夠了。

               3)使用時應當首先將要讀或寫的地址送入DPTR或Ri中,然后再用讀寫命令。

               例:將外部RAM中100H單元中的內容送入外部RAM中200H單元中。

                 MOV DPTR,#0100H

                 MOVX A,@DPTR

                 MOV DPTR,#0200H

                 MOVX @DPTR,A

         

            程序存儲器向累加器A傳送指令

                  MOVC A,@A+DPTR

                  本指令是將ROM中的數送入A中。本指令也被稱為查表指令,常用此指令來查一個已做好在ROM中的表格(類似C語言中的指針)

             說明:

                 此條指令引出一個新的尋址方法:變址尋址。本指令是要在ROM的一個地址單元中找出數據,顯然必須知道這個單元的地址,這個單元的地址是這樣確定的:在執行本指令立腳點DPTR中有一個數,A中有一個數,執行指令時,將A和DPTR中的數加起為,就成為要查找的單元的地址。

                 1)查找到的結果被放在A中,因此,本條指令執行前后,A中的值不一定相同。

                     例:有一個數在R0中,要求用查表的方法確定它的平方值(此數的取值范圍是0-5)

                     MOV DPTR,#TABLE

                     MOV A,R0

                     MOVC A,@A+DPTR

                     TABLE: DB 0,1,4,9,16,25

         

                設R0中的值為2,送入A中,而DPTR中的值則為TABLE,則最終確定的ROM單元的地址就是TABLE+2,也就是到這個單元中去取數,取到的是4,顯然它正是2的平方。其它數據也可以類推。

                 標號的真實含義:從這個地方也可以看到另一個問題,我們使用了標號來替代具體的單元地址。事實上,標號的真實含義就是地址數值。在這里它代表了,0,1,4,9,16,25這幾個數據在ROM中存放的起點位置。而在以前我們學過的如LCALL DELAY指令中,DELAY 則代表了以DELAY為標號的那段程序在ROM中存放的起始地址。事實上,CPU正是通過這個地址才找到這段程序的。

                   可以通過以下的例子再來看一看標號的含義:

                     MOV DPTR,#100H

                     MOV A,R0

                     MOVC A,@A+DPTR 

                     ORG 0100H.

                     DB 0,1,4,9,16,25

                     如果R0中的值為2,則最終地址為100H+2為102H,到102H單元中找到的是4。這個可以看懂了吧?

                     那為什么不這樣寫程序,要用標號呢?不是增加疑惑嗎?

                     答:如果這樣寫程序的話,在寫程序時,我們就必須確定這張表格在ROM中的具體的位置,如果寫完程序后,又想在這段程序前插入一段程序,那么這張表格的位置就又要變了,要改ORG 100H這句話了,我們是經常需要修改程序的,那多麻煩,所以就用標號來替代,只要一編譯程序,位置就自動發生變化,我們把這個麻煩事交給計算機&#0;&#0;指PC機去做了。

         

            堆棧操作

               PUSH direct

               POP #9; direct

               第一條指令稱之為推入,就是將direct中的內容送入堆棧中,第二條指令稱之為彈出,就是將堆棧中的內容送回到direct中。推入指令的執行過程是,首先將SP中的值加1,然后把SP中的值當作地址,將direct中的值送進以SP中的值為地址的RAM單元中。例:

                 MOV SP,#5FH

                 MOV A,#100

                 MOV B,#20

                 PUSH ACC

                 PUSH B

                 則執行第一條PUSH ACC指令是這樣的:將SP中的值加1,即變為60H,然后將A中的值送到60H單元中,因此執行完本條指令后, 內存60H單元的值就是100,同樣,執行PUSH B時,是將SP+1,即變為61H,然后將B中的值送入到61H單元中,即執行完本條指令后,61H單元中的值變為20。

                 POP指令的執行是這樣的,首先將SP中的值作為地址,并將此地址中的數送到POP指令后面的那個direct中,然后SP減1。

                接上例:

                 POP B

                 POP ACC

                 則執行過程是:將SP中的值(現在是61H)作為地址,取61H單元中的數值(現在是20),送到B中,所以執行完本條指令后B中的值是 20,然后將SP減1,因此本條指令執行完后,SP的值變為60H,然后執行POP ACC,將SP中的值(60H)作為地址,從該地址中取數(現在是100),并送到ACC中,所以執行完本條指令后,ACC中的值是100。

               這有什么意義呢?ACC中的值本來就是100,B中的值本來就是20,是的,在本例中,的確沒有意義,但在實際工作中,則在PUSH B后往往要執行其他指令,而且這些指令會把A中的值,B中的值改掉,所以在程序的結束,如果我們要把A和B中的值恢復原值,那么這些指令就有意義了。

               還有一個問題,如果我不用堆棧,比如說在PUSH ACC指令處用MOV 60H,A,在PUSH B處用指令MOV 61H,B,然后用MOV A,60H,MOV B,61H來替代兩條POP指令,不是也一樣嗎?是的,從結果上看是一樣的,但是從過程看是不一樣的,PUSH和POP指令都是單字節,單周期指令,而 MOV指令則是雙字節,雙周期指令。更何況,堆棧的作用不止于此,所以一般的計算機上都設有堆棧,而我們在編寫子程序,需要保存數據時,通常也不采用后面的方法,而是用堆棧的方法來實現。

                 例:寫出以下程序的運行結果

                   MOV 30H,#12

                   MOV 31H,#23

                   PUSH 30H

                   PUSH 31H

                   POP 30H

                   POP 31H

                   結果是30H中的值變為23,而31H中的值則變為12。也就兩者進行了數據交換。從這個例子可以看出:使用堆棧時,入棧的書寫順序和出棧的書寫順序必須相反,才能保證數據被送回原位,否則就要出錯了。

         

            算術運算類指令

             1.不帶進位位的加法指令

               ADD A,#DATA ;例:ADD A,#10H

               ADD A,direct ;例:ADD A,10H

               ADD A,Rn ;例:ADD A,R7

               ADD A,@Ri ;例:ADD A,@R0

               用途:將A中的值與其后面的值相加,最終結果否是回到A中。

              例:

               MOV A,#30H

               ADD A,#10H

               則執行完本條指令后,A中的值為40H。

         

            2.帶進位位的加法指令

               ADDC A,Rn

               ADDC A,direct

               ADDC A,@Ri

               ADDC A,#data

               用途:將A中的值和其后面的值相加,并且加上進位位C中的值。

               說明:由于51單片機是一種8位機,所以只能做8位的數學運算,但8位運算的范圍只有0-255,這在實際工作中是不夠的,因此就要進行擴展,一般是將2個8位的數學運算合起來,成為一個16位的運算,這樣,可以表達的數的范圍就可以達到0-65535。如何合并呢?其實很簡單,讓我們看一個 10進制數的例子:

                 66+78。

               這兩個數相加,我們根本不在意這的過程,但事實上我們是這樣做的:先做6+8(低位),然后再做6+7,這是高位。做了兩次加法,只是我們做的時候并沒有刻意分成兩次加法來做罷了,或者說我們并沒有意識到我們做了兩次加法。之所以要分成兩次來做,是因為這兩個數超過了一位數所能表達的范置(0-9)。

               在做低位時產生了進位,我們做的時候是在適當的位置點一下,然后在做高位加法是將這一點加進去。那么計算機中做16位加法時同樣如此,先做低 8位的,如果兩數相加產生了進位,也要“點一下”做個標記,這個標記就是進位位C,在PSW中。在進行高位加法是將這個C加進去。例:1067H+10A0H,先做67H+A0H=107H,而107H顯然超過了0FFH,因此最終保存在A中的是7,而1則到了PSW中的CY位了,換言之,CY就相當于是100H。然后再做10H+10H+CY,結果是21H,所以最終的結果是2107H。

         

         

            3.帶借位的減法指令

              SUBB A,Rn

               SUBB A,direct

               SUBB A,@Ri

               SUBB A,#data

               設(每個H,(R2)=55H,CY=1,執行指令SUBB A,R2之后,A中的值為73H。

               說明:沒有不帶借位的減法指令,如果需要做不帶位的減法指令(在做第一次相減時),只要將CY清零即可。

         

            4.乘法指令

               MUL AB

               此指令的功能是將A和B中的兩個8位無符號數相乘,兩數相乘結果一般比較大,因此最終結果用1個16位數來表達,其中高8位放在B中,低8位放在A中。在乘積大于FFFFFH(65535)時,0V置1(溢出),否則OV為0,而CY總是0。

               例:(A)=4EH,(B)=5DH,執行指令

               MUL AB后,乘積是1C56H,所以在B中放的是1CH,而A中放的則是56H。

         

            5.除法指令

               DIV AB

               此指令的功能是將A中的8位無符號數除以B中的8位無符號數(A/B)。除法一般會出現小數,但計算機中可沒法直接表達小數,它用的是我們小學生還沒接觸到小數時用的商和余數的概念,如13 /5,其商是2,余數是3。除了以后,商放在A中,余數放在B中。CY和OV都是0。如果在做除法前B中的值是00H,也就是除數為0,那么0V=1。

         

            6.加1指令

               INC A

               INC Rn

               INC direct

               INC @Ri

               INC DPTR

               用途很簡單,就是將后面目標中的值加1。例:(A)=12H,(R0)=33H,(21H)=32H,(34H)=22H,DPTR=1234H。執行下面的指令:

               INC A (A)=13H

               INC R2 (R0)=34H

               INC 21H (21H)=33H

               INC @R0 (34H)=23H

               INC DPTR 9; ( DPTR)=1235H

               結果如上所示。

               說明:從結果上看INC A和ADD A,#1差不多,但INC A是單字節,單周期指令,而ADD #1則是雙字節,雙周期指令,而且INC A不會影響PSW位,如(A)=0FFH,INC A后(A)=00H,而CY依然保持不變。如果是ADD A ,#1,則(A)=00H,而CY一定是1。因此加1指令并不適合做加法,事實上它主要是用來做計數、地址增加等用途。另外,加法類指令都是以A為核心的&#0;&#0;其中一個數必須放在A中,而運算結果也必須放在A中,而加1類指令的對象則廣泛得多,可以是寄存器、內存地址、間址尋址的地址等等。

         

            7.減1指令

               DEC A

               DEC RN

               DEC direct

               DEC @Ri

               與加1指令類似,就不多說了。

         

            邏輯運算類指令:

            1. 對累加器A的邏輯操作:

               CLR A ;將A中的值清0,單周期單字節指令,與MOV A,#00H效果相同。

               CPL A ;將A中的值按位取反

               RL A ;將A中的值邏輯左移

               RLC A ;將A中的值加上進位位進行邏輯左移

               RR A ;將A中的值進行邏輯右移

               RRC A ;將A中的值加上進位位進行邏輯右移

               SWAP A ;將A中的值高、低4位交換。

         

              例:(A)=73H,則執行CPL A,這樣進行:

               73H化為二進制為01110011,

               逐位取反即為 10001100,也就是8CH。

               RL A是將(A)中的值的第7位送到第0位,第0位送1位,依次類推。

         

              例:A中的值為68H,執行RL A。68H化為二進制為01101000,按上圖進行移動。01101000化為11010000,即D0H。

               RLC A,是將(A)中的值帶上進位位(C)進行移位。

         

              例:A中的值為68H,C中的值為1,則執行RLC A

               1 01101000后,結果是0 11010001,也就是C進位位的值變成了0,而(A)則變成了D1H。

               RR A和RRC A就不多談了,請大家參考上面兩個例子自行練習吧。

               SWAP A,是將A中的值的高、低4位進行交換。

         

              例:(A)=39H,則執行SWAP A之后,A中的值就是93H。怎么正好是這么前后交換呢?因為這是一個16進制數,每1個16進位數字代表4個二進位。注意,如果是這樣的:(A)=39,后面沒H,執行SWAP A之后,可不是(A)=93。要將它化成二進制再算:39化為二進制是10111,也就是0001,0111高4位是0001,低4位是0111,交換后是01110001,也就是71H,即113。

         

            2.邏輯與指令

               ANL              A,Rn        ;A與Rn中的值按位'與',結果送入A中

               ANL              A,direct ;A與direct中的值按位'與',結果送入A中

               ANL              A,@Ri ;A與間址尋址單元@Ri中的值按位'與',結果送入A中

               ANL              A,#data ;A與立即數data按位'與',結果送入A中

               ANL              direct,A ;direct中值與A中的值按位'與',結果送入direct中

               ANL              direct,#data ;direct中的值與立即數data按位'與',結果送入direct中。

         

              這幾條指令的關鍵是知道什么是邏輯與。這里的邏輯與是指按位與

               例:71H和56H相與則將兩數寫成二進制形式:

              。71H) 01110001

              。56H) 00100110

               結果 00100000 即20H,從上面的式子可以看出,兩個參與運算的值只要其中有一個位上是0,則這位的結果就是0,兩個同是1,結果才是1。

               理解了邏輯與的運算規則,結果自然就出來了?疵織l指令后面的注釋

              下面再舉一些例子來看。

                 MOV              A,#45H ;(A)=45H

                 MOV              R1,#25H ;(R1)=25H

                 MOV              25H,#79H ;(25H)=79H

                 ANL              A,@R1 ;45H與79H按位與,結果送入A中為 41H (A)=41H

                 ANL              25H,#15H ;25H中的值(79H)與15H相與結果為(25H)=11H)

                 ANL              25H,A ;25H中的值(11H)與A中的值(41H)相與,結果為(25H)=11H

               在知道了邏輯與指令的功能后,邏輯或和邏輯異或的功能就很簡單了。邏輯或是按位“或”,即有“1”為1,全“0”為0。例:

                 10011000

                或 01100001

              結果 11111001

                 而異或則是按位“異或”,相同為“0”,相異為“1”。例:

                 10011000

               異或 01100001

               結果 11111001

               而所有的或指令,就是將與指令中的ANL 換成ORL,而異或指令則是將ANL       換成XRL。

             

            3..邏輯或指令:

               ORL              A,Rn        ;A和Rn中的值按位'或',結果送入A中

               ORL              A,direct ;A和與間址尋址單元@Ri中的值按位'或',結果送入A中

               ORL              A,#data ;A和立direct中的值按位'或',結果送入A中

               ORL              A,@Ri ;A和即數data按位'或',結果送入A中

               ORL              direct,A ;direct中值和A中的值按位'或',結果送入direct中

               ORL              direct,#data ;direct中的值和立即數data按位'或',結果送入direct中。

         

            4.邏輯異或指令:

               XRL              A,Rn        ;A和Rn中的值按位'異或',結果送入A中

               XRL              A,direct ;A和direct中的值按位'異或',結果送入A中

               XRL              A,@Ri ;A和間址尋址單元@Ri中的值按位'異或',結果送入A中

               XRL              A,#data ;A和立即數data按位'異或',結果送入A中

               XRL              direct,A ;direct中值和A中的值按位'異或',結果送入direct中

               XRL              direct,#data ;direct中的值和立即數data按位'異或',結果送入direct中。

         

             控制轉移類指令

           一、無條件轉移類指令

             1.短轉移類指令

               AJMP       addr11

         

            2.長轉移類指令

               LJMP       addr16

         

            3.相對轉移指令

               SJMP       rel

         

              上面的三條指令,如果要仔細分析的話,區別較大,但初學時,可不理會這么多,統統理解成:JMP標號,也就是跳轉到一個標號處。事實上,LJMP標號,在前面的例程中我們已接觸過,并且也知道如何來使用了。而AJMP和SJMP也是一樣。那么他們的區別何在呢?在于跳轉的范圍不一樣。好比跳遠,LJMP一下就能跳64K這么遠(當然近了更沒關系了)。而AJMP最多只能跳2K距離,而SJMP則最多只能跳256這么遠。原則上,所有用 SJMP或AJMP的地方都可以用LJMP來替代。因此在初學時,需要跳轉時可以全用LJMP,除了一個場合。什么場合呢?先了解一下AJMP,AJMP 是一條雙字節指令,也就說這條指令本身占用存儲器(ROM)的兩個單元。而LJMP則是三字節指令,即這條指令占用存儲器(ROM)的三個單元。下面是第四條跳轉指令。

         

            二、間接轉移指令

               JMP         @A+DPTR

               這條指令的用途也是跳轉,轉到什么地方去呢?這可不能由標號簡單地決定了。讓我們從一個實際的例子入手吧。

               MOV    DPTR,#TAB       ;將TAB所代表的地址送入DPTR

               MOV    A,R0                  ;從R0中取數(詳見下面說明)

               MOV    B,#2                        

               MUL    A,B           ;A中的值乘2(詳見下面的說明)

               JMP    A,@A+DPTR      ;跳轉

               TAB:      AJMP     S1          ;跳轉表格

               AJMP     S2

               AJMP     S3

         

              應用背景介紹:在單片機開發中,經常要用到鍵盤,見上面的9個按鍵的鍵盤。我們的要求是:當按下功能鍵A………..G時去完成不同的功能。這用程序設計的語言來表達的話,就是:按下不同的鍵去執行不同的程序段,以完成不同的功能。怎么樣來實現呢?

              前面的程序讀入的是按鍵的值,如按下'A'鍵后獲得的鍵值是0,按下'B'鍵后獲得的值是'1'等等,然后根據不同的值進行跳轉,如鍵值為0就轉到S1執行,為1就轉到S2執行。。。。如何來實現這一功能呢?

              先從程序的下面看起,是若干個AJMP語句,這若干個AJMP語句最后在存儲器中是這樣存放的,也就是每個AJMP語句都占用了兩個存儲器的空間,并且是連續存放的。而AJMP S1存放的地址是TAB,到底TAB等于多少,我們不需要知道,把它留給匯編程序來算好了。

              下面我們來看這段程序的執行過程:第一句MOV DPTR,#TAB執行完了之后,DPTR中的值就是TAB,第二句是MOV A,R0,我們假設R0是由按鍵處理程序獲得的鍵值,比如按下A鍵,R0中的值是0,按下B鍵,R0中的值是1,以此類推,現在我們假設按下的是B鍵,則執行完第二條指令后,A中的值就是1。并且按我們的分析,按下B后應當執行S2這段程序,讓我們來看一看是否是這樣呢?第三條、第四條指令是將A中的值乘 2,即執行完第4條指令后A中的值是2。下面就執行JMP @A+DPTR了,現在DPTR中的值是TAB,而A+DPTR后就是TAB+2,因此,執行此句程序后,將會跳到TAB+2這個地址繼續執行?匆豢丛 TAB+2這個地址里面放的是什么?就是AJMP    S2這條指令。因此,馬上又執行AJMP              S2指令,程序將跳到S2處往下執行,這與我們的要求相符合。

              請大家自行分析按下鍵“A”、“C”、“D”……之后的情況。

              這樣我們用JMP     @A+DPTR就實現了按下一鍵跳到相應的程序段去執行的這樣一個要求。再問大家一個問題,為什么取得鍵值后要乘2?如果例程下面的所有指令換成LJMP,即:

                  LJMP      S1,LJMP        S2……這段程序還能正確地執行嗎?如果不能,應該怎么改?

         

            三、條件轉移指令:

         條件轉移指令是指在滿足一定條件時進行相對轉移。 

            1..判A內容是否為0轉移指令

               JZ rel

               JNZ rel

               第一指令的功能是:如果(A)=0,則轉移,否則順序執行(執行本指令的下一條指令)。轉移到什么地方去呢?如果按照傳統的方法,就要算偏移量,很麻煩,好在現在我們可以借助于機器匯編了。因此這第指令我們可以這樣理解:JZ 標號。即轉移到標號處。下面舉一例說明:

               MOV A,R0

               JZ L1

               MOV R1,#00H

               AJMP L2

               L1: MOV R1,#0FFH

               L2: SJMP L2

               END

               在執行上面這段程序前如果R0中的值是0的話,就轉移到L1執行,因此最終的執行結果是R1中的值為0FFH。而如果R0中的值不等于0,則順序執行,也就是執行 MOV R1,#00H指令。最終的執行結果是R1中的值等于0。

               第一條指令的功能清楚了,第二條當然就好理解了,如果A中的值不等于0,就轉移。把上面的那個例子中的JZ改成JNZ試試吧,看看程序執行的結果是什么?

         

            2.比較轉移指令

               CJNE A,#data,rel

               CJNE A,direct,rel

               CJNE Rn,#data,rel

               CJNE @Ri,#data,rel

               第一條指令的功能是將A中的值和立即數data比較,如果兩者相等,就順序執行(執行本指令的下一條指令),如果不相等,就轉移,同樣地,我們可以將rel理解成標號,即:CJNE A,#data,標號。這樣利用這條指令,我們就可以判斷兩數是否相等,這在很多場合是非常有用的。但有時還想得知兩數比較之后哪個大,哪個小,本條指令也具有這樣的功能,如果兩數不相等,則CPU還會反映出哪個數大,哪個數小,這是用CY(進位位)來實現的。如果前面的數(A中的)大,則CY=0,否則 CY=1,因此在程序轉移后再次利用CY就可判斷出A中的數比data大還是小了。

               例:

                 MOV A,R0

                 CJNE A,#10H,L1

                 MOV R1,#0FFH

                 AJMP L3

                 L1: JC L2

                 MOV R1,#0AAH

                 AJMP L3

                 L2: MOV R1,#0FFH

                 L3: SJMP L3

                 上面的程序中有一條指令我們還沒學過,即JC,這條指令的原型是JC rel,作用和上面的JZ類似,但是它是判CY是0,還是1進行轉移,如果CY=1,則轉移到JC后面的標號處執行,如果CY=0則順序執行(執行它的下面一條指令)。

                 分析一下上面的程序,如果(A)=10H,則順序執行,即R1=0。如果(A)不等于10H,則轉到L1處繼續執行,在L1處,再次進行判斷,如果(A)>10H,則CY=1,將順序執行,即執行MOV R1,#0AAH指令,而如果(A)<10H,則將轉移到L2處指行,即執行MOV R1,#0FFH指令。因此最終結果是:本程序執行前,如果(R0)=10H,則(R1)=00H,如果(R0)>10H,則(R1)=0AAH,如果(R0)<10H,則(R1)=0FFH。

                 弄懂了這條指令,其它的幾條就類似了,第二條是把A當中的值和直接地址中的值比較,第三條則是將直接地址中的值和立即數比較,第四條是將間址尋址得到的數和立即數比較,這里就不詳談了,下面給出幾個相應的例子。

                 CJNE A,10H ;把A中的值和10H中的值比較(注意和上題的區別)

                 CJNE 10H,#35H ;把10H中的值和35H中的值比較

                 CJNE @R0,#35H ;把R0中的值作為地址,從此地址中取數并和35H比較

         

            3.循環轉移指令

               DJNZ Rn,rel

               DJNZ direct,rel

               第一條指令在前面的例子中有詳細的分析,這里就不多談了。第二條指令,只是將Rn改成直接地址,其它一樣,也不多說了,給一個例子。

               DJNZ 10H,LOOP

         

                  調用與返回指令

              。1)主程序與子程序 在前面的燈的實驗中,我們已用到過了子程序,只是我們并沒有明確地介紹。子程序是干什么用的,為什么要用子程序技術呢?舉個例子,我們數據老師布置了10 道算術題,經過觀察,每一道題中都包含一個(3*5+2)*3的運算,我們可以有兩種選擇,第一種,每做一道題,都把這個算式算一遍,第二種選擇,我們可以先把這個結果算出來,也就是51,放在一邊,然后要用到這個算式時就將51代進去。這兩種方法哪種更好呢?不必多言。設計程序時也是這樣,有時一個功能會在程序的不同地方反復使用,我們就可以把這個功能做成一段程序,每次需要用到這個功能時就“調用”一下。

         

             。2)調用及回過程:主程序調用了子程序,子程序執行完之后必須再回到主程序繼續執行,不能“一去不回頭”,那么回到什么地方呢?是回到調用子程序的下面一條指令繼續執行(當然啦,要是還回到這條指令,不又要再調用子程序了嗎?那可就沒完沒了了……)。 

         

            位及位操作指令

              通過前面那些流水燈的例子,我們已經習慣了“位”一位就是一盞燈的亮和滅,而我們學的指令卻全都是用“字節”來介紹的:字節的移動、加法、減法、邏輯運算、移位等等。用字節來處理一些數學問題,比如說:控制冰箱的溫度、電視的音量等等很直觀,可以直接用數值來表在?墒侨绻盟鼇砜刂埔恍╅_關的打開和合上,燈的亮和滅,就有些不直接了,記得我們上次課上的流水燈的例子嗎?我們知道送往P1口的數值后并不能馬上知道哪個燈亮和來滅,而是要化成二進制才知道。工業中有很多場合需要處理這類開關輸出,繼電器吸合,用字節來處理就顯示有些麻煩,所以在8031單片機中特意引入一個位處理機制。

            一、.位尋址區

              在8031中,有一部份RAM和一部份SFR是具有位尋址功能的,也就是說這些RAM的每一個位都有自已的地址,可以直接用這個地址來對此進行操作。

        字節地址

        位地址

        2FH

        7FH

         

         

         

         

         

         

        78H

        2EH

        77H

         

         

         

         

         

         

        70

        2DH

        6FH

         

         

         

         

         

         

        68H

        2CH

        67H

         

         

         

         

         

         

        60H

        2BH

        5FH

         

         

         

         

         

         

        58H

        2AH

        57H

         

         

         

         

         

         

        50H

        29H

        4FH

         

         

         

         

         

         

        48H

        28H

        47H

         

         

         

         

         

         

        40H

        27H

        3FH

         

         

         

         

         

         

        38H

        26H

        37H

         

         

         

         

         

         

        30H

        25H

        2FH

         

         

         

         

         

         

        28H

        24H

        27H

         

         

         

         

         

         

        20H

        23H

        1FH

         

         

         

         

         

         

        18H

        22H

        17H

         

         

         

         

         

         

        10H

        21H

        0FH

         

         

         

         

         

         

        08H

        20H

        07H

        06H

        05H

        04H

        03H

        02H

        01H

        00H

        圖1

                內部RAM的20H-2FH這16個字節,就是8031的位尋址區?磮D1?梢娺@里面的每一個RAM中的每個位我們都可能直接用位地址來找到它們,而不必用字節地址,然后再用邏輯指令的方式。

         

             二、可以位尋址的特殊功能寄存器

              8031中有一些SFR是可以進行位尋址的,這些SFR的特點是其字節地址均可被8整除,如A累加器,B寄存器、PSW、IP(中斷優先級控制寄存器)、IE(中斷允許控制寄存器)、SCON(串行口控制寄存器)、TCON(定時器/計數器控制寄存器)、P0-P3(I/O端口鎖存器)。以上的一些SFR我們還不熟,等我們講解相關內容時再作詳細解釋。

            三、位操作指令

              MCS-51單片機的硬件結構中,有一個位處理器(又稱布爾處理器),它有一套位變量處理的指令集。在進行位處理時,CY(就是我們前面講的進位位)稱“位累加器”。有自已的位RAM,也就是我們剛講的內部RAM的20H-2FH這16個字節單元即128個位單元,還有自已的位I/O空間(即 P0.0…..P0.7,P1.0…….P1.7,P2.0……..P2.7,P3.0……..P3.7)。當然在物理實體上它們與原來的以字節尋址用的 RAM,及端口是完全相同的,或者說這些RAM及端口都可以有兩種用法。

                1..位傳送指令

                  MOV C,BIT

                  MOV BIT,C

                  這組指令的功能是實現位累加器(CY)和其它位地址之間的數據傳遞。

                例:MOV P1.0,CY ;將CY中的狀態送到P1.0引腳上去(如果是做算術運算,我們就可以通過觀察知道現在CY是多少啦)。

                  MOV P1.0,CY ;將P1.0的狀態送給CY。

         

              2..位修正指令

                  位清0指令

                  CLR C ;使CY=0

                  CLR bit ;使指令的位地址等于0。例:CLR P1.0 ;即使P1.0變為0

                  位置1指令

                    SETB C ;使CY=1

                    SETB bit ;使指定的位地址等于1。例:SETB P1.0 ;使P.0變為1

                  位取反指令

                    CPL C ;使CY等于原來的相反的值,由1變為0,由0變為1。

                    CPL bit ;使指定的位的值等于原來相反的值,由0變為1,由1變為0。

                    例:CPL P1.0

                    以我們做過的實驗為例,如果原來燈是亮的,則執行本指令后燈滅,反之原來燈是滅的,執行本指令后燈亮。

            四、位邏輯運算指令

            1..位與指令

              ANL C,bit ;CY與指定的位地址的值相與,結果送回CY

              ANL C,/bit ;先將指定的位地址中的值取出后取反,再和CY相與,結果送回CY,但注意,指定的位地址中的值本身并不發生變化。

              例:ANL C,/P1.0

              設執行本指令前,CY=1,P1.0等于1(燈滅),則執行完本指令后CY=0,而P1.0也是等于1。

              可用下列程序驗證:

                ORG 0000H

                AJMP START

                ORG 30H

                START: MOV SP,#5FH

                MOV P1,#0FFH

                SETB C

                ANL C,/P1.0

                MOV P1.1,C ;將做完的結果送P1.1,結果應當是P1.1上的燈亮,而P1.0上的燈還是不亮。

            2..位或指令

              ORL C,bit

              ORL C,/bit

              這個的功能大家自行分析吧,然后對照上面的例程,編一個驗證程序,看看你相得對嗎?

            五、位條件轉移指令

            1..判CY轉移指令

              JC rel

              JNC rel

              第一條指令的功能是如果CY等于1就轉移,如果不等于1就順序執行。那么轉移到什么地方去呢?我們可以這樣理解:JC 標號,如果等于1就轉到標號處執行。這條指令我們在上節課中已講到,不再重復。

              第二條指令則和第一條指令相反,即如果CY=0就轉移,不等于0就順序執行,當然,我們也同樣理解: JNC 標號

         

            2..判位變量轉移指令

              JB bit,rel

              JNB bit,rel

              第一條指令是如果指定的bit位中的值是1,則轉移,否則順序執行。同樣,我們可以這樣理解這條指令:JB bit,標號

              第二條指令請大家先自行分析

              下面我們舉個例子說明:

                ORG 0000H

                LJMP START

                ORG 30H

                START:MOV SP,#5FH

                MOV P1,#0FFH

                MOV P3,#0FFH

                L1: JNB P3.2,L2 ;P3.2上接有一只按鍵,它按下時,P3.2=0

                JNB P3.3,L3 ;P3.3上接有一只按鍵,它按下時,P3.3=0

                LJM P L1

                L2: MOV P1,#00H

                LJMP L1

                L3: MOV P1,#0FFH

                LJMP L1

                END

                把上面的例子寫入片子,看看有什么現象………

                按下接在P3.2上的按鍵,P1口的燈全亮了,松開或再按,燈并不熄滅,然后按下接在P3.3上的按鍵,燈就全滅了。這像什么?這不就是工業現場經常用到的“啟動”、“停止”的功能嗎?

                怎么做到的呢?一開始,將0FFH送入P3口,這樣,P3的所有引線都處于高電平,然后執行L1,如果P3.2是高電平(鍵沒有按下),則順序執行JNB P3.3,L3語句,同樣,如果P3.3是高電平(鍵沒有按下),則順序執行LJMP L1語句。這樣就不停地檢測P3.2、P3.3,如果有一次P3.2上的按鍵按下去了,則轉移到L2,執行MOV P1,#00H,使燈全亮,然后又轉去L1,再次循環,直到檢測到P3.3為0,則轉L3,執行MOV P1,#0FFH,例燈全滅,再轉去L1,如此循環不已

        關閉窗口

        相關文章

        欧美性色欧美精品视频,99热这里只有精品mp4,日韩高清亚洲日韩精品一区二区,2020国自产拍精品高潮