新聞中心

51單片機(jī)指令詳解

作者: 時(shí)間:2016-11-19 來(lái)源:網(wǎng)絡(luò) 收藏
數(shù)據(jù)傳遞類(lèi)指令

    以累加器為目的操作數(shù)的指令

本文引用地址:http://m.butianyuan.cn/article/201611/318420.htm

      MOV A,Rn

      MOV A,direct

      MOV A,@Ri

      MOV A,#data

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

下面我們通過(guò)一些例子加以說(shuō)明:

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

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

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

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

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

      MOV Rn,A

      MOV Rn,direct

      MOV Rn,#data

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

    以直接地址為目的操作數(shù)的指令

      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

    以間接地址為目的操作數(shù)的指令

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

      MOV @Ri,direct MOV @R1,20H

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

    十六位數(shù)的傳遞指令

      MOV DPTR,#data16

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

    累加器A與片外RAM之間的數(shù)據(jù)傳遞類(lèi)指令

      MOVX A,@Ri

      MOVX @Ri,A

      MOVX #9; A,@DPTR

      MOVX @DPTR,A

說(shuō)明:

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

      2)要讀或?qū)懲獠康腞AM,當(dāng)然也必須要知道RAM的地址,在后兩條指令中,地址是被直接放在DPTR中的。而前兩條指令,由于Ri(即R0或R1)只是一個(gè)8位的寄存器,所以只提供低8位地址。因?yàn)橛袝r(shí)擴(kuò)展的外部RAM的數(shù)量比較少,少于或等于256個(gè),就只需要提供8位地址就夠了。

      3)使用時(shí)應(yīng)當(dāng)首先將要讀或?qū)懙牡刂匪腿隓PTR或Ri中,然后再用讀寫(xiě)命令。

      例:將外部RAM中100H單元中的內(nèi)容送入外部RAM中200H單元中。

        MOV DPTR,#0100H

        MOVX A,@DPTR

        MOV DPTR,#0200H

        MOVX @DPTR,A

    程序存儲(chǔ)器向累加器A傳送指令

        MOVC A,@A+DPTR

        本指令是將ROM中的數(shù)送入A中。本指令也被稱(chēng)為查表指令,常用此指令來(lái)查一個(gè)已做好在ROM中的表格(類(lèi)似C語(yǔ)言中的指針)

    說(shuō)明:

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

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

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

            MOV DPTR,#TABLE

            MOV A,R0

            MOVC A,@A+DPTR

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

        設(shè)R0中的值為2,送入A中,而DPTR中的值則為T(mén)ABLE,則最終確定的ROM單元的地址就是TABLE+2,也就是到這個(gè)單元中去取數(shù),取到的是4,顯然它正是2的平方。其它數(shù)據(jù)也可以類(lèi)推。

        標(biāo)號(hào)的真實(shí)含義:從這個(gè)地方也可以看到另一個(gè)問(wèn)題,我們使用了標(biāo)號(hào)來(lái)替代具體的單元地址。事實(shí)上,標(biāo)號(hào)的真實(shí)含義就是地址數(shù)值。在這里它代表了,0,1,4,9,16,25這幾個(gè)數(shù)據(jù)在ROM中存放的起點(diǎn)位置。而在以前我們學(xué)過(guò)的如LCALL DELAY指令中,DELAY 則代表了以DELAY為標(biāo)號(hào)的那段程序在ROM中存放的起始地址。事實(shí)上,CPU正是通過(guò)這個(gè)地址才找到這段程序的。

          可以通過(guò)以下的例子再來(lái)看一看標(biāo)號(hào)的含義:

            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。這個(gè)可以看懂了吧?

            那為什么不這樣寫(xiě)程序,要用標(biāo)號(hào)呢?不是增加疑惑嗎?

            答:如果這樣寫(xiě)程序的話(huà),在寫(xiě)程序時(shí),我們就必須確定這張表格在ROM中的具體的位置,如果寫(xiě)完程序后,又想在這段程序前插入一段程序,那么這張表格的位置就又要變了,要改ORG 100H這句話(huà)了,我們是經(jīng)常需要修改程序的,那多麻煩,所以就用標(biāo)號(hào)來(lái)替代,只要一編譯程序,位置就自動(dòng)發(fā)生變化,我們把這個(gè)麻煩事交給計(jì)算機(jī)指PC機(jī)去做了。

    堆棧操作

      PUSH direct

      POP #9; direct

      第一條指令稱(chēng)之為推入,就是將direct中的內(nèi)容送入堆棧中,第二條指令稱(chēng)之為彈出,就是將堆棧中的內(nèi)容送回到direct中。推入指令的執(zhí)行過(guò)程是,首先將SP中的值加1,然后把SP中的值當(dāng)作地址,將direct中的值送進(jìn)以SP中的值為地址的RAM單元中。例:

        MOV SP,#5FH

        MOV A,#100

        MOV B,#20

        PUSH ACC

        PUSH B

        則執(zhí)行第一條PUSH ACC指令是這樣的:將SP中的值加1,即變?yōu)?0H,然后將A中的值送到60H單元中,因此執(zhí)行完本條指令后, 內(nèi)存60H單元的值就是100,同樣,執(zhí)行PUSH B時(shí),是將SP+1,即變?yōu)?1H,然后將B中的值送入到61H單元中,即執(zhí)行完本條指令后,61H單元中的值變?yōu)?0。

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

       接上例:

        POP B

        POP ACC

        則執(zhí)行過(guò)程是:將SP中的值(現(xiàn)在是61H)作為地址,取61H單元中的數(shù)值(現(xiàn)在是20),送到B中,所以執(zhí)行完本條指令后B中的值是20,然后將SP減1,因此本條指令執(zhí)行完后,SP的值變?yōu)?0H,然后執(zhí)行POP ACC,將SP中的值(60H)作為地址,從該地址中取數(shù)(現(xiàn)在是100),并送到ACC中,所以執(zhí)行完本條指令后,ACC中的值是100。

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

      還有一個(gè)問(wèn)題,如果我不用堆棧,比如說(shuō)在PUSH ACC指令處用MOV 60H,A,在PUSH B處用指令MOV 61H,B,然后用MOV A,60H,MOV B,61H來(lái)替代兩條POP指令,不是也一樣嗎?是的,從結(jié)果上看是一樣的,但是從過(guò)程看是不一樣的,PUSH和POP指令都是單字節(jié),單周期指令,而MOV指令則是雙字節(jié),雙周期指令。更何況,堆棧的作用不止于此,所以一般的計(jì)算機(jī)上都設(shè)有堆棧,而我們?cè)诰帉?xiě)子程序,需要保存數(shù)據(jù)時(shí),通常也不采用后面的方法,而是用堆棧的方法來(lái)實(shí)現(xiàn)。

        例:寫(xiě)出以下程序的運(yùn)行結(jié)果

          MOV 30H,#12

          MOV 31H,#23

          PUSH 30H

          PUSH 31H

          POP 30H

          POP 31H

          結(jié)果是30H中的值變?yōu)?3,而31H中的值則變?yōu)?2。也就兩者進(jìn)行了數(shù)據(jù)交換。從這個(gè)例子可以看出:使用堆棧時(shí),入棧的書(shū)寫(xiě)順序和出棧的書(shū)寫(xiě)順序必須相反,才能保證數(shù)據(jù)被送回原位,否則就要出錯(cuò)了。

    算術(shù)運(yùn)算類(lèi)指令

    1.不帶進(jìn)位位的加法指令

      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中的值與其后面的值相加,最終結(jié)果否是回到A中。

     例:

       MOV A,#30H

      ADD A,#10H

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

    2.帶進(jìn)位位的加法指令

      ADDC A,Rn

      ADDC A,direct

      ADDC A,@Ri

      ADDC A,#data

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

      說(shuō)明:由于51單片機(jī)是一種8位機(jī),所以只能做8位的數(shù)學(xué)運(yùn)算,但8位運(yùn)算的范圍只有0-255,這在實(shí)際工作中是不夠的,因此就要進(jìn)行擴(kuò)展,一般是將2個(gè)8位的數(shù)學(xué)運(yùn)算合起來(lái),成為一個(gè)16位的運(yùn)算,這樣,可以表達(dá)的數(shù)的范圍就可以達(dá)到0-65535。如何合并呢?其實(shí)很簡(jiǎn)單,讓我們看一個(gè)10進(jìn)制數(shù)的例子:

        66+78。

      這兩個(gè)數(shù)相加,我們根本不在意這的過(guò)程,但事實(shí)上我們是這樣做的:先做6+8(低位),然后再做6+7,這是高位。做了兩次加法,只是我們做的時(shí)候并沒(méi)有刻意分成兩次加法來(lái)做罷了,或者說(shuō)我們并沒(méi)有意識(shí)到我們做了兩次加法。之所以要分成兩次來(lái)做,是因?yàn)檫@兩個(gè)數(shù)超過(guò)了一位數(shù)所能表達(dá)的范置(0-9)。

      在做低位時(shí)產(chǎn)生了進(jìn)位,我們做的時(shí)候是在適當(dāng)?shù)奈恢命c(diǎn)一下,然后在做高位加法是將這一點(diǎn)加進(jìn)去。那么計(jì)算機(jī)中做16位加法時(shí)同樣如此,先做低8位的,如果兩數(shù)相加產(chǎn)生了進(jìn)位,也要“點(diǎn)一下”做個(gè)標(biāo)記,這個(gè)標(biāo)記就是進(jìn)位位C,在PSW中。在進(jìn)行高位加法是將這個(gè)C加進(jìn)去。例:1067H+10A0H,先做67H+A0H=107H,而107H顯然超過(guò)了0FFH,因此最終保存在A中的是7,而1則到了PSW中的CY位了,換言之,CY就相當(dāng)于是100H。然后再做10H+10H+CY,結(jié)果是21H,所以最終的結(jié)果是2107H。

    3.帶借位的減法指令

      SUBB A,Rn

      SUBB A,direct

      SUBB A,@Ri

      SUBB A,#data

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

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

;

    4.乘法指令

      MUL AB

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

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

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

    5.除法指令

      DIV AB

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

    6.加1指令

      INC A

      INC Rn

      INC direct

      INC @Ri

      INC DPTR

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

      INC A (A)=13H

      INC R2 (R0)=34H

      INC 21H (21H)=33H

      INC @R0 (34H)=23H

      INC DPTR 9; ( DPTR)=1235H

      結(jié)果如上所示。

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

    7.減1指令

      DEC A

      DEC RN

      DEC direct

      DEC @Ri

      與加1指令類(lèi)似,就不多說(shuō)了。

    邏輯運(yùn)算類(lèi)指令:

    1.對(duì)累加器A的邏輯操作:

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

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

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

      RLC A ;將A中的值加上進(jìn)位位進(jìn)行邏輯左移

      RR A ;將A中的值進(jìn)行邏輯右移

      RRC A ;將A中的值加上進(jìn)位位進(jìn)行邏輯右移

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

      例:(A)=73H,則執(zhí)行CPL A,這樣進(jìn)行:

      73H化為二進(jìn)制為00011,

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

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

      例:A中的值為68H,執(zhí)行RL A。68H化為二進(jìn)制為01101,按上圖進(jìn)行移動(dòng)。01101化為11010,即D0H。

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

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

      1 01101后,結(jié)果是0 11011,也就是C進(jìn)位位的值變成了0,而(A)則變成了D1H。

      RR A和RRC A就不多談了,請(qǐng)大家參考上面兩個(gè)例子自行練習(xí)吧。

      SWAP A,是將A中的值的高、低4位進(jìn)行交換。

      例:(A)=39H,則執(zhí)行SWAP A之后,A中的值就是93H。怎么正好是這么前后交換呢?因?yàn)檫@是一個(gè)16進(jìn)制數(shù),每1個(gè)16進(jìn)位數(shù)字代表4個(gè)二進(jìn)位。注意,如果是這樣的:(A)=39,后面沒(méi)H,執(zhí)行SWAP A之后,可不是(A)=93。要將它化成二進(jìn)制再算:39化為二進(jìn)制是10,也就是1,0高4位是1,低4位是0,交換后是01,也就是71H,即113。

    2.邏輯與指令

      ANL A,Rn ;A與Rn中的值按位與,結(jié)果送入A中

      ANL A,direct ;A與direct中的值按位與,結(jié)果送入A中

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

      ANL A,#data ;A與立即數(shù)data按位與,結(jié)果送入A中

      ANL direct,A ;direct中值與A中的值按位與,結(jié)果送入direct中

      ANL direct,#data ;direct中的值與立即數(shù)data按位與,結(jié)果送入direct中。

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

      例:71H和56H相與則將兩數(shù)寫(xiě)成二進(jìn)制形式:

      (71H) 01

     ?。?6H) 00100110

      結(jié)果 00100 即20H,從上面的式子可以看出,兩個(gè)參與運(yùn)算的值只要其中有一個(gè)位上是0,則這位的結(jié)果就是0,兩個(gè)同是1,結(jié)果才是1。

      理解了邏輯與的運(yùn)算規(guī)則,結(jié)果自然就出來(lái)了。看每條指令后面的注釋

      下面再舉一些例子來(lái)看。

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

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

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

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

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

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

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

        10011

       或 01101

     結(jié)果 11001

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

        10011

      異或 01101

      結(jié)果 11001

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

    

    3..邏輯或指令:

      ORL A,Rn ;A和Rn中的值按位或,結(jié)果送入A中

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

      ORL A,#data ;A和立direct中的值按位或,結(jié)果送入A中

      ORL A,@Ri ;A和即數(shù)data按位或,結(jié)果送入A中

      ORL direct,A ;direct中值和A中的值按位或,結(jié)果送入direct中

      ORL direct,#data ;direct中的值和立即數(shù)data按位或,結(jié)果送入direct中。

    4.邏輯異或指令:

      XRL A,Rn ;A和Rn中的值按位異或,結(jié)果送入A中

      XRL A,direct ;A和direct中的值按位異或,結(jié)果送入A中

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

      XRL A,#data ;A和立即數(shù)data按位異或,結(jié)果送入A中

      XRL direct,A ;direct中值和A中的值按位異或,結(jié)果送入direct中

      XRL direct,#data ;direct中的值和立即數(shù)data按位異或,結(jié)果送入direct中。

    控制轉(zhuǎn)移類(lèi)指令

  一、無(wú)條件轉(zhuǎn)移類(lèi)指令

    1.短轉(zhuǎn)移類(lèi)指令

      AJMP addr11

    2.長(zhǎng)轉(zhuǎn)移類(lèi)指令

      LJMP addr16

    3.相對(duì)轉(zhuǎn)移指令

      SJMP rel

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

    二、間接轉(zhuǎn)移指令

      JMP @A+DPTR

      這條指令的用途也是跳轉(zhuǎn),轉(zhuǎn)到什么地方去呢?這可不能由標(biāo)號(hào)簡(jiǎn)單地決定了。讓我們從一個(gè)實(shí)際的例子入手吧。

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

      MOV A,R0 ;從R0中取數(shù)(詳見(jiàn)下面說(shuō)明)

      MOV B,#2

      MUL A,B ;A中的值乘2(詳見(jiàn)下面的說(shuō)明)

      JMP A,@A+DPTR ;跳轉(zhuǎn)

      TAB: AJMP S1 ;跳轉(zhuǎn)表格

      AJMP S2

      AJMP S3

      應(yīng)用背景介紹:在單片機(jī)開(kāi)發(fā)中,經(jīng)常要用到鍵盤(pán),見(jiàn)上面的9個(gè)按鍵的鍵盤(pán)。我們的要求是:當(dāng)按下功能鍵A………..G時(shí)去完成不同的功能。這用程序設(shè)計(jì)的語(yǔ)言來(lái)表達(dá)的話(huà),就是:按下不同的鍵去執(zhí)行不同的程序段,以完成不同的功能。怎么樣來(lái)實(shí)現(xiàn)呢?

      前面的程序讀入的是按鍵的值,如按下A鍵后獲得的鍵值是0,按下B鍵后獲得的值是1等等,然后根據(jù)不同的值進(jìn)行跳轉(zhuǎn),如鍵值為0就轉(zhuǎn)到S1執(zhí)行,為1就轉(zhuǎn)到S2執(zhí)行。。。。如何來(lái)實(shí)現(xiàn)這一功能呢?

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

      下面我們來(lái)看這段程序的執(zhí)行過(guò)程:第一句MOV DPTR,#TAB執(zhí)行完了之后,DPTR中的值就是TAB,第二句是MOV A,R0,我們假設(shè)R0是由按鍵處理程序獲得的鍵值,比如按下A鍵,R0中的值是0,按下B鍵,R0中的值是1,以此類(lèi)推,現(xiàn)在我們假設(shè)按下的是B鍵,則執(zhí)行完第二條指令后,A中的值就是1。并且按我們的分析,按下B后應(yīng)當(dāng)執(zhí)行S2這段程序,讓我們來(lái)看一看是否是這樣呢?第三條、第四條指令是將A中的值乘2,即執(zhí)行完第4條指令后A中的值是2。下面就執(zhí)行JMP @A+DPTR了,現(xiàn)在DPTR中的值是TAB,而A+DPTR后就是TAB+2,因此,執(zhí)行此句程序后,將會(huì)跳到TAB+2這個(gè)地址繼續(xù)執(zhí)行。看一看在TAB+2這個(gè)地址里面放的是什么?就是AJMP S2這條指令。因此,馬上又執(zhí)行AJMP S2指令,程序?qū)⑻絊2處往下執(zhí)行,這與我們的要求相符合。

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

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

          LJMP S1,LJMP S2……這段程序還能正確地執(zhí)行嗎?如果不能,應(yīng)該怎么改?

    三、條件轉(zhuǎn)移指令:

條件轉(zhuǎn)移指令是指在滿(mǎn)足一定條件時(shí)進(jìn)行相對(duì)轉(zhuǎn)移。

    1..判A內(nèi)容是否為0轉(zhuǎn)移指令

      JZ rel

      JNZ rel

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

      MOV A,R0

      JZ L1

      MOV R1,#00H

      AJMP L2

      L1: MOV R1,#0FFH

      L2: SJMP L2

      END

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

      第一條指令的功能清楚了,第二條當(dāng)然就好理解了,如果A中的值不等于0,就轉(zhuǎn)移。把上面的那個(gè)例子中的JZ改成JNZ試試吧,看看程序執(zhí)行的結(jié)果是什么?

    2.比較轉(zhuǎn)移指令

      CJNE A,#data,rel

      CJNE A,direct,rel

      CJNE Rn,#data,rel

      CJNE @Ri,#data,rel

      第一條指令的功能是將A中的值和立即數(shù)data比較,如果兩者相等,就順序執(zhí)行(執(zhí)行本指令的下一條指令),如果不相等,就轉(zhuǎn)移,同樣地,我們可以將rel理解成標(biāo)號(hào),即:CJNE A,#data,標(biāo)號(hào)。這樣利用這條指令,我們就可以判斷兩數(shù)是否相等,這在很多場(chǎng)合是非常有用的。但有時(shí)還想得知兩數(shù)比較之后哪個(gè)大,哪個(gè)小,本條指令也具有這樣的功能,如果兩數(shù)不相等,則CPU還會(huì)反映出哪個(gè)數(shù)大,哪個(gè)數(shù)小,這是用CY(進(jìn)位位)來(lái)實(shí)現(xiàn)的。如果前面的數(shù)(A中的)大,則CY=0,否則CY=1,因此在程序轉(zhuǎn)移后再次利用CY就可判斷出A中的數(shù)比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

        上面的程序中有一條指令我們還沒(méi)學(xué)過(guò),即JC,這條指令的原型是JC rel,作用和上面的JZ類(lèi)似,但是它是判CY是0,還是1進(jìn)行轉(zhuǎn)移,如果CY=1,則轉(zhuǎn)移到JC后面的標(biāo)號(hào)處執(zhí)行,如果CY=0則順序執(zhí)行(執(zhí)行它的下面一條指令)。

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

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

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

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

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

    3.循環(huán)轉(zhuǎn)移指令

      DJNZ Rn,rel

      DJNZ direct,rel

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

      DJNZ 10H,LOOP

  調(diào)用與返回指令

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

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

   位及位操作指令

      通過(guò)前面那些流水燈的例子,我們已經(jīng)習(xí)慣了“位”一位就是一盞燈的亮和滅,而我們學(xué)的指令卻全都是用“字節(jié)”來(lái)介紹的:字節(jié)的移動(dòng)、加法、減法、邏輯運(yùn)算、移位等等。用字節(jié)來(lái)處理一些數(shù)學(xué)問(wèn)題,比如說(shuō):控制冰箱的溫度、電視的音量等等很直觀(guān),可以直接用數(shù)值來(lái)表在。可是如果用它來(lái)控制一些開(kāi)關(guān)的打開(kāi)和合上,燈的亮和滅,就有些不直接了,記得我們上次課上的流水燈的例子嗎?我們知道送往P1口的數(shù)值后并不能馬上知道哪個(gè)燈亮和來(lái)滅,而是要化成二進(jìn)制才知道。工業(yè)中有很多場(chǎng)合需要處理這類(lèi)開(kāi)關(guān)輸出,繼電器吸合,用字節(jié)來(lái)處理就顯示有些麻煩,所以在8031單片機(jī)中特意引入一個(gè)位處理機(jī)制。

    一、.位尋址區(qū)

      在8031中,有一部份RAM和一部份SFR是具有位尋址功能的,也就是說(shuō)這些RAM的每一個(gè)位都有自已的地址,可以直接用這個(gè)地址來(lái)對(duì)此進(jìn)行操作。

字節(jié)地址

位地址

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

        內(nèi)部RAM的20H-2FH這16個(gè)字節(jié),就是8031的位尋址區(qū)??磮D1??梢?jiàn)這里面的每一個(gè)RAM中的每個(gè)位我們都可能直接用位地址來(lái)找到它們,而不必用字節(jié)地址,然后再用邏輯指令的方式。

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

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

    三、位操作指令

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

        1..位傳送指令

          MOV C,BIT

          MOV BIT,C

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

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

          MOV P1.0,CY ;將P1.0的狀態(tài)送給CY。

      2..位修正指令

          位清0指令

          CLR C ;使CY=0

          CLR bit ;使指令的位地址等于0。例:CLR P1.0 ;即使P1.0變?yōu)?

          位置1指令

            SETB C ;使CY=1

            SETB bit ;使指定的位地址等于1。例:SETB P1.0 ;使P.0變?yōu)?

          位取反指令

            CPL C ;使CY等于原來(lái)的相反的值,由1變?yōu)?,由0變?yōu)?。

            CPL bit ;使指定的位的值等于原來(lái)相反的值,由0變?yōu)?,由1變?yōu)?。

            例:CPL P1.0

            以我們做過(guò)的實(shí)驗(yàn)為例,如果原來(lái)燈是亮的,則執(zhí)行本指令后燈滅,反之原來(lái)燈是滅的,執(zhí)行本指令后燈亮。

    四、位邏輯運(yùn)算指令

    1..位與指令

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

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

      例:ANL C,/P1.0

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

      可用下列程序驗(yàn)證:

        ORG 0H

        AJMP START

        ORG 30H

        START: MOV SP,#5FH

        MOV P1,#0FFH

        SETB C

        ANL C,/P1.0

        MOV P1.1,C ;將做完的結(jié)果送P1.1,結(jié)果應(yīng)當(dāng)是P1.1上的燈亮,而P1.0上的燈還是不亮。

    2..位或指令

      ORL C,bit

      ORL C,/bit

      這個(gè)的功能大家自行分析吧,然后對(duì)照上面的例程,編一個(gè)驗(yàn)證程序,看看你相得對(duì)嗎?

    五、位條件轉(zhuǎn)移指令

    1..判CY轉(zhuǎn)移指令

      JC rel

      JNC rel

      第一條指令的功能是如果CY等于1就轉(zhuǎn)移,如果不等于1就順序執(zhí)行。那么轉(zhuǎn)移到什么地方去呢?我們可以這樣理解:JC 標(biāo)號(hào),如果等于1就轉(zhuǎn)到標(biāo)號(hào)處執(zhí)行。這條指令我們?cè)谏瞎?jié)課中已講到,不再重復(fù)。

      第二條指令則和第一條指令相反,即如果CY=0就轉(zhuǎn)移,不等于0就順序執(zhí)行,當(dāng)然,我們也同樣理解: JNC 標(biāo)號(hào)

    2..判位變量轉(zhuǎn)移指令

      JB bit,rel

      JNB bit,rel

      第一條指令是如果指定的bit位中的值是1,則轉(zhuǎn)移,否則順序執(zhí)行。同樣,我們可以這樣理解這條指令:JB bit,標(biāo)號(hào)

      第二條指令請(qǐng)大家先自行分析

      下面我們舉個(gè)例子說(shuō)明:

        ORG 0H

        LJMP START

        ORG 30H

        START:MOV SP,#5FH

        MOV P1,#0FFH

        MOV P3,#0FFH

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

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

        LJM P L1

        L2: MOV P1,#00H

        LJMP L1

        L3: MOV P1,#0FFH

        LJMP L1

        END

        把上面的例子寫(xiě)入片子,看看有什么現(xiàn)象………

        按下接在P3.2上的按鍵,P1口的燈全亮了,松開(kāi)或再按,燈并不熄滅,然后按下接在P3.3上的按鍵,燈就全滅了。這像什么?這不就是工業(yè)現(xiàn)場(chǎng)經(jīng)常用到的“啟動(dòng)”、“停止”的功能嗎?

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

        改程序還可以用JB來(lái)寫(xiě) 略



關(guān)鍵詞: 51單片機(jī)指令詳

評(píng)論


技術(shù)專(zhuān)區(qū)

關(guān)閉