什么是单片机寻址方式与指令系统

什么是单片机寻址方式与指令系统,第1张

 什么是单片机寻址方式与指令系统

通过前面的学习,我们已经了解了单片机内部的结构,并且也已经知道,要控制单片机,让它为我们干学,要用指令,我们已学了几条指令,但很零散,从现在开始,我们将要系统地学习8051单片机的指令部份。

一、概述

1、指令的格式

寻址方式

MCS-51指令系统的寻址方式有7种:立即寻址(#data)、寄存器寻址(Rn)、间接寻址(@Ri、@DPTR)直接寻址direct、变址寻址(A+)、相对寻址(rel)和特定寄存器寻址(A)。有些书把A当寄存器寻址,把位寻址单独作一种寻址方式,不管怎么分类其目的是为了便于记忆、掌握111条指令。
 

1.立即寻址(#data)

    *** 作数包含在指令字节中, *** 作数直接出现在指令中,并存放在程序存储器中,这种方式称为立即寻址。

立即寻址指令的 *** 作数是一个8位或16位的二进制常数,它前面以“#”号标识,例如:ADD A,#56H,即#56H与累加器A(设为31H)内容相加,结果(87H)存于累加器A中。这条指令的机器码为2456H.

 

2.寄存器寻址(Rn)

由指令指出某一个寄存器中的内容作为 *** 作数,这种寻址方式称为寄存器寻址。在这种寻址方式中,指令的 *** 作码中包含了参加 *** 作的工作寄存器R0~R7的代码(指令 *** 作码字节的低3位指明所寻址的工作寄存器)。例如:ADD  A,Rn中的Rn,当n为0、1、2时,机器码分别为28、29、2A.

3.间接寻址(@Ri/@DPTR)

    由指令指出某一个寄存器内容作为 *** 作数的地址。这种寻址方式称为寄存器间接寻址。访问外部RAM时,可使用R0,R1或DPTR作为地址指针,寄存器间接寻址用符号“@”表示。

例如:MOV A,@RO(机器码E7)是指:若RO内容为66(内部RAM地址单元66H),而66H单元中内容是27H,则指令的功能是将27H这个数送到累加器A.

 

4.直接寻址(direct)

     在指令中直接给出 *** 作数所在存储单元的地址(一个8位二进制数),称为直接寻址。直接地址用direct表示,

直接寻址方式中 *** 作数存储的空间有三种:

(1).内部数据存储器的128个字节单元(00H~7FH)

(2).位地址空间(有些书把这种寻址方式单独作一种寻址方式)

(3).特殊功能寄存器, 特殊功能寄存器只能用直接寻址方式进行访问。

 

    5.基址加变址寻址(@A+PC/@A+DPTR)

     以16位寄存器(DPTR或PC)作为基址寄存器,加上地址偏移量(累加器A中的8位无符号数)形成 *** 作数的地址。

变址寻址方式有两类:

(1).以程序计数器的值为基址例如指令:

    MOVC A,@A+PC;    ;(A)←((A)+(PC))

     指令的功能是先使PC指向本指令下一条指令地址(本指令以完成),然后PC地址与累加器内容相加,形成变址寻址的单元地址内容送A。

  (2).以数据指针DPTR为基址,以数据指针内容和累加器内容相加形成地址,例如:

MOV DPTR #4200H ;给DPTR赋值

MOV A,#10H     ;给A赋值

MOVC A ,@A+DPTR ;变址寻址方式(A)←((A)+(DPTR))

三条指令的执行结果是将4210H单元内容送A中。

 

6.相对寻址(rel)

    以程序计数器PC的当前值为基址,加上相对寻址指令的字节长度,再加上指令中给定的偏移量rel的值(rel是一个8位带符号数,用二进制补码表示),形成相对寻址的地址。

例如指令:

JNZ rel    (或rel = 23H,机器码为7023)
  当A≠0时,程序跳到这条指令后面,相差23个字节运行下一条指令。

 

7.特定寄存器寻址

    累加器A和数据针DPTR这两个使用最频繁的寄存器又称为特殊寄存器。对特定寄存器的 *** 作指令,指令不再需要指出其地址字节,指令码本身隐含了 *** 作对象A或DPTR。

例如:

INC A   (指令码04)   ;累加器加1

MOV  A,#12H   (指令码7412)   ;数12送累加器

INC DPTR  (指令码A3) ;数据指针内容加1

综上所述,寻址方式与存储器结构有密切关系。一种寻址方式只适合于对一部分存储器进行 *** 作,在使用时要加以注意。

   我们已知,要让计算机做事,就得给计算机以指令,并且我们已知,计算机很“笨”,只能懂得数字,如前面我们写进机器的75H,90H,00H等等,所以指令的第一种格式就是机器码格式,也说是数字的形式。但这种形式实在是为难我们人了,太难记了,于是有另一种格式,助记符格式,如MOV P1,#0FFH,这样就好记了。 这两种格式之间的关系呢,我们不难理解,本质上它们完全等价,只是形式不一样而已。

2、汇编

  我们写指令使用汇编格式,而计算机和单片机只懂机器码格式,所以要将我们写的汇编格式的指令转换为机器码格式,这种转换有两种办法:手工汇编和机器汇编。手工汇编实际上就是查表,因为这两种格式纯粹是格式不一样,所以是一一对应的,查一张表格就行了。不过手工查表总是嫌麻烦,所以就有了计算机软件,用计算机软件来替代手工查表,这就是机器汇编。

二、单片机的寻址

  让我们先来复习一下我们学过的一些指令:MOV P1,#0FFH,MOV R7,#0FFH这些指令都是将一些数据送到对应的位置中去,为什么要送数据呢?第一个因为送入的数能让灯全灭掉,第二个是为了要实现延时,从这里我们能看出来,在用单片机的编程语言编程时,经常要用到数据的传递,事实上数据传递是单片机编程时的一项重要工作,一共有28条指令(单片机共111条指令)。下面我们就从数据传递类指令开始吧。

  分析一下MOV P1,#0FFH这条指令,我们不难得出结论,第一个词MOV是命令动词,也就是决定做什么事情的,MOV是MOVE少写了一个E,所以就是“传递”,这就是指令,规定做什么事情,后面还有一些参数,分析一下,数据传递必须要有一个“源”也就是你要送什么数,必须要有一个“目的”,也就是你这个数要送到什么地方去,显然在上面那条单片机指令中,要送的数(源)就是0FFH,而要送达的地方(目的地)就是P1这个寄存器。在数据传递类指令中,均将目的地写在指令的后面,而将源写在最后。

  这条指令中,送给P1是这个数本身,换言之,做完这条指令后,我们能明确地知道,P1中的值是0FFH,但是并不是任何时候都能直接给出数本身的。例如,在我们前面给出的单片机延时程序例是这样写的:

MAIN: SETB P1.0     ;(1)

   LCALL DELAY ;(2)

    CLR P1.0      ;(3)

   LCALL DELAY   ;(4)

    AJMP MAIN    ;(5)

;以下子程序

DELAY: MOV R7,#250   ;(6)

D1: MOV R6,#250   ;(7)

D2: DJNZ R6,D2    ;(8)

   DJNZ R7,D1   ;(9)

   RET        ;(10)

   END        ;(11)

表1

-----------------------------------------------------

 MAIN: SETB P1.0     ;(1)

   MOV 30H,#255

    LCALL DELAY ;

    CLR P1.0      ;(3)

    MOV 30H,#200

    LCALL DELAY   ;(4)

    AJMP MAIN    ;(5)

;以下子程序

DELAY: MOV R7,30H   ;(6)

D1: MOV R6,#250   ;(7)

D2: DJNZ R6,D2    ;(8)

   DJNZ R7,D1   ;(9)

   RET        ;(10)

   END        ;(11)

表2

 这样一来,我每次调用延时程序延时的时间都是相同的(大致都是0.13S),如果我提出这样的要求:灯亮后延时时间为0.13S灯灭,灯灭后延时0.1秒灯亮,如此循环,这样的程序还能满足要求吗?不能,怎么办?我们能把延时程序改成这样(见表2):调用则见表2中的主程,也就是先把一个数送入30H,在子程序中R7中的值并不固定,而是根据30H单元中传过来的数确定。这样就能满足要求。

   从这里我们能得出结论,在数据传递中要找到被传递的数,很多时候,这个数并不能直接给出,需要变化,这就引出了一个概念:如何寻找 *** 作数,我们把寻找 *** 作数所在单元的地址称之为寻址。在这里我们直接使用数所在单元的地址找到了 *** 作数,所以称这种办法为直接寻址。除了这种办法之外,还有一种,如果我们把数放在工作寄存器中,从工作寄存器中寻找数据,则称之为寄存器寻址。例:MOV A,R0就是将R0工作寄存器中的数据送到累加器A中去。提一个问题:我们知道,工作寄存器就是内存单元的一部份,如果我们选择工作寄存器组0,则R0就是RAM的00H单元,那么这样一来,MOV A,00H,和MOV A,R0不就没什么区别了吗?为什么要加以区别呢?的确,这两条指令执行的结果是完全相同的,都是将00H单元中的内容送到A中去,但是执行的过程不一样,执行第一条指令需要2个周期,而第二条则只需要1个周期,第一条指令变成最终的目标码要两个字节(E5H 00H),而第二条则只要一个字节(E8h)就能了。

  这么斤斤计较!不就差了一个周期吗,如果是12M的晶体震荡器的话,也就1个微秒时间了,一个字节又能有多少?

   不对,如果这条指令只执行一次,也许无所谓,但一条指令如果执行上1000次,就是1毫秒,如果要执行1000000万次,就是1S的误差,这就很可观了,单片机做的是实时控制的事,所以必须如此“斤斤计较”。字节数同样如此。

再来提一个问题,现在我们已知,寻找 *** 作数能通过直接给的方式(立即寻址)和直接给出数所在单元地址的方式(直接寻址),这就够了吗?

看这个问题,要求从30H单元开始,取20个数,分别送入A累加器。

   就我们目前掌握的办法而言,要从30H单元取数,就用MOV A,30H,那么下一个数呢?是31H单元的,怎么取呢?还是只能用MOV A,31H,那么20个数,不是得20条指令才能写完吗?这里只有20个数,如果要送200个或2000个数,那岂不要写上200条或2000条命令?这未免太笨了吧。为什么会出现这样的状况?是因为我们只会把地址写在指令中,所以就没办法了,如果我们不是把地址直接写在指令中,而是把地址放在另外一个寄存器单元中,根据这个寄存器单元中的数值决定该到哪个单元中取数据,比如,当前这个寄存器中的值是30H,那么就到30H单元中去取,如果是31H就到31H单元中去取,就能解决这个问题了。怎么个解决法呢?既然是看的寄存器中的值,那么我们就能通过一定的办法让这里面的值发生变化,比如取完一个数后,将这个寄存器单元中的值加1,还是执行同一条指令,可是取数的对象却不一样了,不是吗。通过例程来说明吧。

MOV R7,#20

   MOV R0,#30H

LOOP:MOV A,@R0

   INC R0

   DJNZ R7,LOOP

    这个例程中大部份指令我们是能看懂的,第一句,是将立即数20送到R7中,执行完后R7中的值应当是20。第二句是将立即数30H送入R0工作寄存器中,所以执行完后,R0单元中的值是30H,第三句,这是看一下R0单元中是什么值,把这个值作为地址,取这个地址单元的内容送入A中,此时,执行这条指令的结果就相当于MOV A,30H。第四句,没学过,就是把R0中的值加1,因此执行完后,R0中的值就是31H,第五句,学过,将R7中的值减1,看是否等于0,不等于0,则转到标号LOOP处继续执行,因此,执行完这句后,将转去执行MOV A,@R0这句话,此时相当于执行了MOV A,31H(因为此时的R0中的值已是31H了),如此,直到R7中的值逐次相减等于0,也就是循环20次为止,就实现了我们的要求:从30H单元开始将20个数据送入A中。

这也是一种寻找数据的办法,由于数据是间接地被找到的,所以就称之为间址寻址。注意,在间址寻址中,只能用R0或R1存放等寻找的数据。

指令系统
 
数据传送指令

数据传送指令包括数据的传送、交换、堆栈数据的压入与d出,是最基本、使用率最高的一类指令。助记符有MOV、MOVX、MOVC、XCH、XCHD、SWAP、PUSH、POP共八种。
1.MOV类指令及功能(16条)
这类指令的功能是从源 *** 作数到目的 *** 作数的数据传送。
MOV  A, Rn    ;Rn→A,寄存器Rn的内容送到累加器A
MOV  A, direct   ;(direct)→A,直接地址中的内容送A
MOV  A, @Ri    ;(Ri)→A,Ri间址的内容送A
MOV  A, #data   ;data→A,立即数送A
MOV  Rn,, A    ;A→Rn,累加器A中的内容送寄存器Rn
MOV  Rn, direct   ;(direct)→Rn;直接地址中的内容送Rn
MOV  Rn, #data   ;data→Rn;立即数送Rn
MOV  direct, A   ;A→(direct),A中的内容送入直接地址中
MOV  direct, Rn   ;Rn→(direct),寄存器内容送入直接地址中
MOV  direct, direct  ;(direct) →(direct),源 *** 作数直接地址的内容送入
;目的 *** 作数的直接地址中
MOV  direct, @Ri  ;(Ri)→(direct),Ri间址内容送入直接地址中
MOV  direct, #data  ;data→(direct),立即数送入直接地址中
MOV  @Ri, A    ;A→(Ri),A中内容送到Ri间址单元中
MOV  @Ri, direct  ;(direct)→(Ri),直接地址中内容送入Ri间址单元中
MOV  @Ri, #data   ;data→(Ri),立即数送入Ri间址单元中
MOV  DPTR, #data16      ;data16→DPTR,16位常数送入数据指针DPTR中,高8
;位送入DPH,低8位送入DPH,低8位送入DPL中
从上述指令可以看出目的 *** 作数有A累加器、Rn寄存器、直接地址direct及间接地址@Ri,源 *** 作数除此之外还多一种立即数data。
例1  R0中有常数30H,而30H地址中有常数50H
执行MOV A, R0后,A=30H,R0不变。
执行MOV A, @R0后A=50H,而不是30H,这条指令的功能是把R0中内容为地址的单元的书送入A,R0中是30H也就是把30H地址中内容50H送入A。
例2  若(40H)=20H,(50H)=30H
执行MOV 40H, 50H; (50H) →(40H)
结果:(40H)=30H,50H地址中内容仍为30H。
例3  若A=40H,R0=30H,
执行MOV @R0, A              ;A→(R0)
结果:(30H)=40H,A与R0皆不变,即A=40H,R0=30H。
该指令功能是把A中内容送入R0间址单元即R0中内容为地址的单元。
例4  执行MOV DPTR, #2040H          ;2040H→DPTR
结果:DPH=20H, DPL=40H
DPTR是片外RAM地址指针,只有这一条指令是传送16位数据。
2.MOVC类指令及功能(2条)
MOVC A, @A+PC                   ;PC+1→PC, (A+PC) →A
MOVC A, @A+DPTR                  ;(A+DPTR) →A
功能:该类属于查表指令,利用这两条指令很方便地查找放在程序存储器中数据表格的内容。
例1  程序
  1000H MOV A, #10H       ;10H→A
  1002H MOVC A, @A+PC       ;PC+1→PC,PC=1003H,(A+PC)=(10H+1003H)→A
  ...
  1010H 02H
  1011H 04H
  1012H 06H
  1013H 08H
程序执行结果:A=08H
用MOVC A, @A+PC指令需注意两点:
1)指令中的PC是执行完本条指令后的PC值,即PC等于本条指令地址加1。
2)A是修正值,它等于查表指令和欲查数据相间隔字节数。A的范围是0~255,一次该指令只能查找本指令后的256B范围内的表格,故称为近程查表。
例2  程序
  1000H MOV A, #01H     ;01H→A
  1002H MOV DPTR, #6000H    ;6000H→DPTR
  1005H MOVC A,@A+DPTR   ;(A+DPTR)=(01H+6000H)=(6001H) →A
  ...
6001H 0AH
  6002H 0BH
  6003H 0CH
  6004H 0DH
程序执行结果:A=0AH,查到了地址为6001H单元中的数据。
用MOVC A, @A+DPTR指令查表特点:A, DPTR都可以改变,因此可在64KB范围内查表,故称为远程查表。这条指令更方便。
3.MOVX类指令(4条)
MOVX A, @DPTR         ;(DPTR) →A,DPTR间址单元内容送A
MOVX @DPTR, A         ;A→(DPTR), A 中内容送入DPTR间址单元
MOVX A, @Ri          ;(Ri) →A,Ri间址单元内容送A
MOVX @Ri, A          ;A→(Ri), A中内容送Ri间址单元
MOVX类指令功能:这四条指令专门用来与外部数据存储区传送数据。CPU与外部RAM传送数据时只能用间接寻址方式。
例1  把外部数据存储单元2000H中的数据送到4000H单元中,设2000H中有数据30H。
       程序             各条指令执行结果
        MOV DPTR, #2000H         ;2000H DPTR, DPTR=2000H
        MOVX A, @DPTR          ;(DPTR)  A即(2000) A,A=30H
        MOV DPTR, #4000H        ;4000H→DPTR, DPTR=4000H
        MOVX @DPTR, A          ;A→(DPTR)即A→(4000H), (4000H)=30H
例2  把内部RAM50H单元数据送到片外20H单元,设50H中单元存有数据10H。
       程序                各条指令执行结果
        MOV A,50H              ;(50H) 各条指令执行结果A, A=10H
        MOV R0,#20H          ;20H→R0, R0=20H
        MOVX @R0, A          ;A→(R0)即A→(20H)则20H=10H
注意:与外部RAM传送数据时,地址小于256B用Ri间址,大于256B时用DPTR间址。
4.交换指令
       XCH A, Rn             ;Rn A, Rn与A内容交换
       XCH A,direct            ;(direct)  A, 直接地址内容与A内容交换
       XCH A, @Ri         ;(Ri)  A,Ri间址内容与A内容交换
       XCHD A, @Ri         ;(Ri.3~Ri.0) A.3~A.0, Ri间址内容低4
位与A中低4 位内容交换
       SWAP  A          ;A.3~A.0  A.7~A.4, A中高4位与低4位
交换
例  若R0=30H, A=F0H, (30H)=46H
执行    XCH A, R0               ;结果:A=30H,R0=F0H, R0与A 内容交换
 执行    XCH A, @R0               ;结果:A=46H, (30H)=F0H, R0中不变,
;实际上是(R0) A即(30H) A
 若执行 XCHD A, @R0               ;结果:A=F6H,(30)H=40H
                    ;A与(30H)中低4位交换,高4位不变
  执行 SWAP A                 ;结果:A=0FH, 高低4位互换
5.堆栈 *** 作指令(2条)
 PUSH、POP属堆栈 *** 作指令,其功能是把直接地址中的内容压入堆栈保存,或从堆栈中取出(d出)数据到直接地址中。
         PUSH direct     ;SP+1→SP, (direct) →(SP)
                 ;直接地址内容压入堆栈顶
         POP  direct     ;(SP)→(direct), SP-1→SP
                 ;堆栈栈顶内容d出到直接地址
 注意:堆栈是用户自己设定的内部RAM中的一块专用存储区,使用堆栈时一定先设堆栈指针。堆栈遵循后进先出的原则安排数据。压入数据时SP先加1,再压入;d出时,先d出数据,SP再减1。
例  设堆栈指针为30H,为保护现场把A和B中的内容压入堆栈保护,然后根据需要再把两者d出。设A中为30H,B中为01H。
       程序        执行结果
        MOV   SP, #30H  ;30H→SP, SP=30H设堆栈指针为30H
        PUSH  ACC        ;SP+1→SP=31H, A→(SP)即A→(31H),(31H)=30H
        PUSH  B    ;SP+1→SP=32H, B→(SP)即B→(32H),(32H)=01H
        POP   B    ;SP→B即(32H)→B, B=01H, SP-1→SP=31H
        POP  ACC    ;SP→A即(31H)→A, A=30H, SP-1→SP=30H
从此例可以看出压入、d出过程SP的变化规律

算术运算指令

算术运算指令的主要功能是实现算术加、减、乘、除等运算。
1.ADD类指令是不带进位的加法运算指令(4条)。
ADD A,Rn          ;A+Rn→A, A与Rn寄存器内容相加,结果送到A中
ADD A,direct         ;(direct)+A→A, A与直接地址内容相加,和送A
ADD A, @Ri      ;(Ri)+A→A, A与Ri间址内容相加,和送A
ADD A, #data         ;data+A→A, A与立即数相加,和送A
注意:ADD类指令相加结果均在A中,相加后源 *** 作数不变。若A中最高位有进位,Cy置1;若半加位有进位,AC置1。A的结果还影响奇偶标志位P。
例  A=30H, R0=10H
执行  ADD A,R0  结果:A=40H, R0=10H,标志位 P=1, Cy=0, OV=0, AC=0
2.ADDC类指令(带进位加法4条)
ADDC A, Rn      ;A+Rn+Cy→A,  A与R n内容、进位状态相加,和送
到A中
ADDC A, direct     ;(direct)+Cy+A→A, A与直接地址中内容、进位状态
相加,和送A
ADDC A, @Ri      ;(Ri)+Cy+A→A, A与Ri间址单元中内容、进位状态
相加,和送A
       ADDC A, #data         ;data+Cy+A→A, A与 立即数、进位状态相加,和送A
与ADD类指令的区别是,ADDC指令相加时连同进位标志Cy内容一起相加,主要用于多字节加法中的高位字节的相加,而最低位字节相加用ADD指令。进位位Cy加到字节的最低位。
例  编写计算1234H+0FE7H的程序,将结果存入内部RAM的41H和40H单元,40H存低8位,41H存高8位。
      程序
       MOV A, #34H   ;被加数低8位数34H送A
       ADD A, #0E7H   ;加数低8位数E7H与之相加,A=1BH,Cy=1
       MOV 40H, A   ;A→40H即34H+E7H结果存入40H中(40H=1BH)
       MOV A, #12H   ;被加数高8位数12H送A
       ADDC A, #0FH   ;加数高8位0FH和Cy与A相加,A=22H
       MOV 41H, A   ;高8位与进位位之和存入41H中(41H)=22H
           ;总和为221BH,总结果在41H,40H单元中
3.SUBB类指令(4条)
 SUBB类指令是带借位减法指令,其功能是将A中被减数减去源 *** 作数指出的内容,再减去借位标志Cy(原进位标志)状态,差值在A中。
SUBB A, Rn    ;A-Rn-Cy→A ,A减寄存器Rn内容及进位标志
     SUBB A, direct   ;A-(direct)-Cy→A,A减直接地址内容和进位标志
     SUBB A, Ri    ;A-(Ri)-Cy→A, A减Ri间址单元内容和进位位标志
     SUBB A, #data   ;A-data-Cy→A, A减立即数和进位标志
说明:
1) 多字节减法时,低位相减有借位则把Cy置1,否则Cy为0。
2) MCS-51系列指令中没有不带借位的减法指令,所以在单字节或低位字节减法时用SUBB类指令前要先将Cy清0。
3)减去一个数实际上是加上这个数的相反数(负数),减法运算常常用补码相加方式。
4.MUL(乘)和DIV(除)指令
 乘法指令只有一条:
MUL  AB          ;A×B→B和A,结果16位,高8位存入B,低8位在A中
 若乘积大于FFH则将溢出标志OV置1。
 除法指令也只有一条:
DIV  AB              ; A÷B商→A,余数→B
 注意:当除数为0时结果不确定,则溢出将OV置1。
5.INC(加1)和DEC(减1)类指令
 加1类指令共5条,其功能是将 *** 作数内容加1。
INC A     ;A+1→A, A加1
INC   Rn         ;Rn+1→Rn, Rn中内容加1
INC   direct       ;(direct)+1→(direct), 直接地址中内容加1
INC @Ri        ;(Ri)+1→(Ri), Ri间址中的内容加1
INC   DPTR    ;DPTR+1→DPTR, 数据指针加1
例  判断INC R0和INC @R0两条指令结果,比较两者的区别。设R0=30H,(30H)=00H。
 执行  INC   R0            ;R0+1=30H+1→R0, 结果R0=31H
 执行  INC   @R0           ;(R0)+1=(30H)+1→(R0),结果(30H)=01H,R0中内
容不变,仍为30H
 减1类指令共4条,其功能是将 *** 作数指定单元内容减1。
       DEC  A     ;A-1→A, A中内容减1
       DEC  Rn         ;Rn-1→Rn, Rn中内容减1
       DEC  direct    ;(direct)-1→(direct), 直接地址中内容减1
       DEC  @Ri         ;(Ri)-1→(Ri), Ri间址中的内容减1
  *** 作过程与加1指令类似,这里不再举例。
6.十进制加法调整指令(1条)
       DA   A
 功能:在加法指令后,把A中二进制码自动调整成BCD码。
例   MOV  A, #05H       ;05H→A
       ADD  A, #08H       ;05H+08H→A=0DH
       DA   A        ;结果调整A=13H,即是13的BCD码
 注意:DA A指令只能跟在ADD或ADDC加法指令后,不适用于减法。

逻辑运算指令

1.ANL类指令(6条)
ANL类是逻辑与指令,其功能是将源 *** 作数作数内容和目的 *** 作数内容按位相“与”,结果存入目的 *** 作数指定单元中,源 *** 作数不变。
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)
例  设A=F6H,(30H)=0FH
执行  ANL A, 30H          ;A∩ (30H) →A
*** 作如下:
 11110110  (F6H)
∩  00001111  (0FH)   注意:按位相“与”
    00000110  (06H)
结果:A=06H, 30H地址内容不变,即(30H)=0FH
若执行ANL 30H, A           ;(30H)∩ A→(30H)
*** 作同上,结果放在30H地址中,A中内容不变,即(30H)=06H, A=F6H。
2.ORL类指令(6条)
ORL类指令是逻辑或指令,其功能是将源 *** 作数作数内容和目的 *** 作数内容按位逻辑“或”,结果存入目的 *** 作数指定单元中,源 *** 作数不变。
ORL A, Rn     ;A∪Rn→A
ORL A,direct       ;A∪(direct) →A
       ORL A, @Ri    ;A∪(Ri) →A
       ORL A, #data       ;A∪data→A
       ORL direct, A       ;(direct)∪A→(direct)
       ORL direct, #data      ;(direct)∪data→(direct)
 “或”运算和“与”运算过程类似,这里不再举例。
3.XRL类指令(6条)
 XRL类是异或指令,其功能是将两个 *** 作数指定内容按位“异或”,结果存于目的 *** 作数指定单元中。“异或”原则是相同为“0”,相异为“1”。
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)
例  (50H)=05H
 执行  XRL 50H, #06H             ;(50H)⊕06H→(50H)
  *** 作如下:
     00000101 (05H)
⊕  00000110 (06H)
        00000011 (03H)
结果:(50H)=03H
4.循环移位指令(4条)
 循环移位指令的功能是将累加器A中内容循环位移或者和进位位一起移位。
例  A=01H, Cy=1
若执行一次  RRC  A后,结果为:A=10000000B  Cy=1
若执行一次  RLC  A后,结果为:A=00000011B  Cy=0
5.取反、清0指令
     CPL  A                  ;累加器内容按位取反。如果1就变0,如果0就变1
     CLR  A                  ;累加器A清0

控制转移类指令

计算机运行过程中,有时因为 *** 作的需要,程序不能按顺序逐条执行指令,需要改变程序运行方向,即将程序跳转到某个指定的地址再顺序执行下去。
控制转移类指令的功能就是根据要求修改程序计数器PC的内容,以改变程序运行方向,实现转移。
控制转移类指令可分为:无条件转移、条件转移、绝对转移、相对转移和调用、返回指令。下面我们将分类介绍。
1.无条件转移指令(4条)
LJMP   add16           ;add16→PC,无条件跳转到add16地址,可在64KB范围内
转移,称为长转移指令
AJMP   add11          ;add11→PC,无条件转向add11地址,在2KB范围内转移
SJMP   rel           ;PC+2+rel→PC,相对转移,rel是偏移量,8 位有符号
数,范围-128~127,即可向后跳转128,向前可跳转127
JMP    @A+DPTR         ;A+DPTR→PC ,属散转指令,无条件转向A与DPTR内容相
加后形成的新地址
例1  执行指令
LJMP   9100H
不管这条指令存放在哪里,执行时将使程序转移到9100H,和AJMP,SJMP指令是有差别的。
例2  程序
2000H   MOV   R0 , #10H  ;10H→PC
2002H   SJMP  03H   ;PC+2+rel=2002H+2+03H=2007H→PC
  ┇        ┇
2006H     ┇
2007H     ┇
  从说明中可见,执行SJMP  03H 指令后,马上跳转到2007H地址执行程序。
2.条件转移指令(8条)
条件转移指令是根据某种特定条件转移的指令。条件满足时转移,条件不满足时则顺序
执行下面的指令。
JZ   rel           ;A=0转向PC+2+rel→PC,A≠0顺序执行
JNZ  rel           ;A≠转向PC+2+rel→PC ,A=0顺序执行
CJNE A, direct, rel     ;A≠ (direct)转向PC+3+rel→PC且当A>(direct),Cy=0
;当A<(direct),Cy=1
;否则A=(direct),PC+3→PC即顺序执行
CJNE A, #data, rel      ;A data P转向PC+3+rel→PC且当A >data,Cy=0
;当A ;A=data,PC+3→PC顺序执行
CJNZ  Rn, #data, rel  ;Rn≠data转向PC+3+rel→PC
;且当Rn>data,Cy=0,当Rn;Rn=data,PC+3→PC顺序执行
CJNE  @Ri,#data, rel  ;(Ri) ≠data ,PC+3+rel→PC
;且当(Ri)>data ,Cy=0,当(Ri);(Ri)=data, PC+3→PC顺序执行
DJNZ  Rn, rel       ;Rn-1→Rn ,Rn ≠0转向PC+2+rel→PC
;Rn=0,PC+2→PC顺序执行
DJNZ direct, rel      ;(direct)-1→(direct),(direct) ≠0转向 PC+2+rel
→PC
;(direct)=0 ,PC+2→PC顺序执行
注意:
1)CJNE类指令借用进位标志Cy作为比较结果的标志位。从指令中可知,目的 *** 作数内容小于原 *** 作数内容Cy置1,反之Cy清0,该类指令多用于分支程序。
2) DJNZ指令执行时Rn或direct先减1,然后再判断Rn或direct内容是否等于0。不为0则转,为0顺序执行。DJNZ用在循环程序中,控制循环次数很方便。
3) JZ和JNZ的 *** 作数只有一个,是对A的内容的进行判断的指令。
例1 以下程序的循环次数是多少,最后(R0)=?
MOV  R0 , #0
LL:     ┇
DJNZ  R0 , LL
分析:由于DJNZ是减1再判断大小的,因为R0=0,所以第一次执行DJNZ  R0 , LL后R0=FFH=255,则程序要执行的次数为256次,R0最后的值为0。
解:程序要循环的次数为256次,最后R0=0
3.调用、返回、控 *** 作指令
在程序设计中,常常要把具有一定功能的公用程序编制成子程序。当主程序转至子
程序时用调用指令,而在子程序的最后安排一条返回指令,使执行完子程序后再返回到主程序。
(1) LCALL    addr16    ;调用入口地址为addr16的子程序
这是一条长调指令,可调用64KB范围内的子程序,因此,可放在程序的任何位置。
指令的执行过程分两步:第一步把断点(当前执行指令的下一条指令地址)压入堆栈。第二步将调用的子程序的入口地址装入PC。即addr16(16位地址)→PC,转向执行子程序。
(2) ACALL    addr11      ;子程序入口地址为addr11的子程序
这是一条短调指令,只能实现2KB范围内的子程序的调用。其指令执行过程与LCALL
指令一样。但是需要注意的是:ACALL中addr11只占用PC的PC.0~PC.10位。
(3) RET         ;放在子程序最后,使程序准确返回到主程序断点处
执行过程为:(SP)→PC.8~PC.15断点地址高字节送入PC 
SP-1→SP,(SP) →PC.0~PC.7断点低字节送入PC,
这时PC中为主程序断点地址,程序准确返回到调用指令的下一条。
例  设SP=62H,(62H)=07H,(61H)=30H,执行指令RET
结果:SP=60H,(PC)=0730H,CPU从0730H开始执行程序。
(4) RETI     ;中断返回指令
该指令用于中断服务程序,使中断程序结束后准确返回到主程序断点处,执行过程同RET,它还能清除优先级状态。
(5) NOP         ;空 *** 作
执行该指令时,CPU只进行取指令、译码,而不进行任何 *** 作,故称为控 *** 作。常用于产生一个机器周期延时。

位 *** 作指令

MCS-51单片机的特色之一是具有很强的位处理功能。位 *** 作指令又称为布尔指令,其功能是对内部RAM中可进行位 *** 作的区域进行位 *** 作。
    在进行位 *** 作时,位累加器C即进位标志Cy,位地址是片内RAM字节地址20H~2FH单元中连续的128个位(位地址00H~7FH)和部分功能寄存器。凡SFR中字符等地址能被8整除的特殊功能寄存器都具有可寻址的位地址,其中ACC(位地址E0H~E7H),B(位地址F0H~F7H)和片内RAM中128个位都可作软件标志或存储位变量。
1. 位数据传送类指令(2条)
MOV   C , bit      ;(bit) →C,寻址位的状态送入C
MOV   bit , C      ;C→(bit),C的状态送入位地址中
2. 位修正指令(6条)
CLR  C        ;0→C, 清0累加器
CLR  bit    ;0→(bit);清0寻址位
CPL  C        ;/C→C,取反
CPL  bit       ;(/bit) →(bit),寻址位取反
SETB   C       ;1→C,C置1
SETB   bit       ;1→ (bit),寻址位置1
3. 位逻辑运算指令(4条)
ANL  C , bit   ;C∩(bit) →C,寻址位和C“与”,结果放在C
ANL  C , /bit      ;C∩(/bit) →C,寻址位的非和C“与”,结果放在C
ORL  C , bit   ;C∪(bit) →C,寻址位和C“或”,结果放在C
ORL  C , /bit      ;C∪(bit) →C,寻址位和C的非“或”,结果放在C
4. 位条件转移指令(5条)
JC   rel    ;C=1转向PC+2+rel→PC
                                 C=0顺序执行PC+2→PC
JNC  rel       ;C=0转向PC+2+rel→PC
                                 C=1顺序执行PC+2→PC
JB   bit , rel         ;(bit) =1转向PC+3+rel→PC
                                (bit) =0顺序执行PC+3→PC
JNB  bit , rel      ;(bit) =0转向PC+3+rel→PC
                                (bit) =1顺序执行PC+3→PC
JBC  bit , rel      ;(bit) =1转向PC+3+rel→PC;同时0→(bit)
                                     (bit) =0顺序执行PC+3→PC
注意:JBC与JB指令区别,前者转移后并把寻址位清0,后者只转移不清0寻址位。
例1 设P1为输入口,P3.0作输出线,执行下列指令:
MOV   C , P1.0       ;(P1.0) →C
ANL   C , P1.1       ;(C)∩(P1.1) →C
ANL   C , /P1.32   ;(C)∩(/P1.2) →C
MOV   P3.0 , C        ;C→P3.0 
结果是:P3.0=(P1.0) ∩(P1.1) ∩(/P1.2)
例2  用位 *** 作指令编程计算逻辑方程
         P1.5=ACC.0 ∩ (B.0∪P1.2) ∪P1.3
解:     MOV  C , B.0       ;B.0→C
ORL  C , P1.2       ;C∪P1.2→C  即B.0+P1.2→C
ANL  C , ACC.0  ;C∩ACC.0→C  即ACC.0∩(B.0∪P1.2)→C
ORL  C , P1.3       ;C∪P1.3→C 即 ACC.0∩(B.0∪P1.2)∪P1.3→C
MOV  P1.5 , C       ;C→P1.5

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/dianzi/2457498.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-08-04
下一篇 2022-08-04

发表评论

登录后才能评论

评论列表(0条)

保存