3.3 数据传送类指令

数据传送类指令是最常用、最基本的一类指令。数据传送类指令的一般功能是把源操作数传送到目的操作数,指令执行后,源操作数不变,目的操作数被源操作数所代替。这类指令主要用于数据的传送、保存及交换数据等场合。

在89C51单片机的指令系统中,各类数据传送指令共有29条,分述如下。

3.3.1 内部RAM数据传送指令

内部RAM的数据传送类指令共16条,包括累加器、寄存器、特殊功能寄存器、RAM单元之间的相互数据传送。

1.以累加器A为目的操作数的数据传送指令

        MOV  A,# data            ;A ←data
        MOV  A,direct            ;A ← (direct)
        MOV  A,Rn                ;A ← (Rn)
        MOV  A,@Ri               ;A ← ((Ri))

这组指令的功能是将源操作数所指定的内容送入累加器A中。源操作数可以采用立即寻址、直接寻址、寄存器寻址和寄存器间接寻址4种寻址方式。

上述指令在上节均有例题和图示,不再重复。

2.以寄存器Rn为目的操作数的数据传送指令

        MOV  Rn,A                ;Rn ← (A)
        MOV  Rn,# data           ;Rn ←data
        MOV  Rn,direct           ;Rn ← (direct)

这组指令的功能是将源操作数所指定的内容送到当前工作寄存器组R0~R7中的某个寄存器中。源操作数可以采用寄存器寻址、立即寻址和直接寻址。

注意,没有“MOV Rn,Rn”指令,也没有“MOV Rn,@Ri”指令。

例3-1 已知(A)=50H,(R1)=10H,(R2)=20H,(R3)=30H,(30H)=4FH,执行指令:

        MOV  R1,A                ;R1←(A)
        MOV  R2,30H              ;R2← (30H)
        MOV  R3,# 85H            ;R3←85H

执行后,(R1)= 50H,(R2)= 4FH,(R3)= 85H

3.以直接地址为目的操作数的数据传送指令

        MOV  direct,A            ;direct ← (A)
        MOV  direct,# data       ;direct ←data
        MOV  direct1,direct2     ;direct1← (direct2)
        MOV  direct,Rn           ;direct ← (Rn)
        MOV  direct,@Ri          ;direct ← ( (Ri))

这组指令的功能是将源操作数所指定的内容送入由直接地址direct所指定的片内存储单元。源操作数可以采用寄存器寻址、立即寻址、直接寻址和寄存器间接寻址。

例3-2 已知(R0)=60H,(60H)=72H,现执行如下指令:

        MOV  40H,@R0             ;(40H)← (60H)

该指令执行过程如图3-5所示。

图3-5 MOV 40H,@R0执行示意图

执行结果为(40H)= 72H

注意,“MOV direct1,direct2”指令在译成机器码时,源地址在前,目的地址在后。

4.以间接地址@Ri为目的操作数的数据传送指令

        MOV  @Ri,A               ;(Ri)← (A)
        MOV  @Ri,# data          ;(Ri)←data
        MOV  @Ri,direct          ;(Ri)← (direct)

这组指令的功能是把源操作数所指定的内容送入以R0或R1为地址指针的片内RAM单元中。源操作数可以采用寄存器寻址、立即寻址和直接寻址3种方式。

注意,没有“MOV@Ri,Rn”指令。

例3-3 已知(R1)=30H,(A)=20H,执行指令:

        MOV  @R1,A               ;(30H)← (A)

执行指令结果为(30H)= 20H

5.以DPTR为目的操作数的数据传送指令

        MOV  DPTR,# data16        ;DPTR ←data16

这是89C51单片机指令系统唯一的一条16位立即数传送指令,其功能是将外部存储器(RAM或ROM)某单元地址作为立即数送到DPTR中,立即数的高8位送DPH,低8位送DPL。

注意,该指令在译成机器码时,16位立即数其高8位在前,低8位在后。

在使用上述指令时,需注意以下几点。

(1)要区分各种寻址方式的含义,正确传送数据。

例3-4 若(R0)=30H,(30H)=50H时,注意以下指令的执行结果:

        MOV  A,R0                  ;(A)= 30H
        MOV  A,@R0                 ;(A)=  (30H)= 50H
        MOV  A,30H                 ;(A)=  (30H)= 50H
        MOV  A,# 30H               ;(A)= 30H

(2)所有传送指令都不影响标志位,这里所说的标志位是指CY、AC和OV。涉及累加器A的将影响奇偶标志位P。

(3)估算指令的字节数,凡是指令中既不包含字节地址,又不包含8位立即数的指令均为一字节指令;若指令中包含一个8位字节地址或8位立即数,指令字节数为2,若指令中包含两个这样的操作数,则指令字节数为3。如:

        MOV  A,  @R0               ;1字节
        MOV  A,  direct            ;2字节
        MOV  direct,# data         ;3字节
        MOV  DPTR,# data16         ;3字节

3.3.2 访问外部RAM的数据传送指令

CPU与外部RAM或I/O口进行数据传送,必须采用寄存器间接寻址的方法,并通过累加器A来传送。这类指令共有4条:

        MOVX  A,@DPTR            ;A← ((DPTR))
        MOVX  @DPTR,A            ;(DPTR)← (A)
        MOVX  A,@Ri              ;A← ((Ri))
        MOVX  @Ri,A              ;(Ri)← (A)

前两条指令是以DPTR作为间址寄存器,其功能是将DPTR所指定的外部RAM单元与累加器A之间传送数据。由于DPTR是16位地址指针,因此这两条指令的寻址范围可达片外RAM 64 KB全部空间。

后两条指令是以R0或R1作为间址寄存器,其功能是将R0或R1所指定的外部RAM单元与累加器A之间传送数据。由于R0或R1是8位地址指针,因此这两条指令的寻址范围仅限于外部RAM 256个字节单元。

例3-5 试编程,将片外RAM的2000H单元内容送入片外RAM的0200H单元中。

片外 RAM与片外 RAM之间不能直接传送,需通过累加器 A,另外,当片外RAM地址值大于FFH时,需用DPTR作为间址寄存器。编程如下:

        MOV  DPTR,# 2000H         ;源数据地址送DPTR
        MOVX  A,@DPTR             ;从外部RAM中取数送A
        MOV  DPTR,# 0200H         ;目的地址送DPTR
        MOVX  @DPTR,A             ;A中内容送外部RAM

3.3.3 程序存储器向累加器A传送数据指令

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

这两条指令的功能是从程序存储器中读取源操作数送入累加器A中。源操作数均为变址寻址方式。这两条指令都是一字节指令。

这两条指令特别适合于读取表格在ROM中建立的数据,故称做查表指令。虽然这两条指令的功能完全相同,但在具体使用中却有一点差异。

前一条指令是采用DPTR作为基址寄存器。在使用前,可以很方便地把一个16位地址(表格首地址)送入DPTR,实现在整个64 KB ROM空间向累加器A的数据传送。即数据表格可以存放在64 KB程序存储器的任意位置,因此,第一条指令称为远程查表指令。远程查表指令使用起来比较方便。

后一条指令是以PC作为基址寄存器。在程序中,执行该查表指令时PC值是确定的,为下一条指令的地址,而不是表格首地址,这样基址和实际要读取的数据表格首地址就不一致,使得A+PC与实际要访问的单元地址不一致,为此,在使用该查表指令之前,必须用一条加法指令进行地址调整,地址调整只能通过对累加器A的内容进行调整,使得A+PC和所读ROM单元地址保持一致。

例3-6 若在外部ROM中2000H单元开始存放(0~9)的平方值0,1,4,9,…, 81,要求根据累加器A中的值(0~9),来查找所对应的平方值,并存入60H单元中。

(1)用DPTR作为基址寄存器:

              MOV  DPTR,# 2000H      ;表格首地址送DPTR
              MOVC  A,@A+ DPTR       ;根据表格首地址及A确定地址,取数送A
              MOV  60H,A             ;存结果

这种情况,(A)+(DPTR)之和就是所查平方值所存的地址。

(2)用PC作为基址寄存器,在MOVC指令之前应先用一条加法指令进行地址调整,编程如下:

      (2字节)  ADD  A,# data         ;(A)+ data 作为地址调整
      (1字节)  MOVC  A,@A+ PC        ;(A)+ data+ (PC)确定查表地址,取数送A
      (2字节)  MOV  60H,A            ;存结果
      (1字节)  RET 
      2000H:DB 0,1,4,9,16,25,36,…,81

执行该查表指令时,PC已指向下一条指令地址,很显然,PC的内容不是要查找的表格首地址2000H,两者之间存在地址差,因此需进行地址调整,使其能指向表格首地址,由于PC的内容不能随意改变,所以只能借助于A来进行调整。故在MOVC指令之前,先执行对A的加法操作,其中# data的值要根据MOVC指令后的地址和数据表格首地址之间的地址差确定,也就是由MOVC下边的指令与数据表格首地址之间,其他指令所占的字节数之和来确定。本例中,data=03H。

还应注意,累加器A中的内容为8位无符号数,该查表指令只能查找指令所在地址以后256 B范围内的数据,即表格只能放在该指令所在地址之后的256个字节范围内,故称之为近程查表指令。

3.3.4 数据交换指令

数据交换指令共有5条,可完成累加器和内部RAM单元之间的字节或半字节交换。

1.整字节交换指令

整字节交换指令有3条,完成累加器A与内部RAM单元内容的整字节交换如下:

        XCH  A,Rn                ; (A)←→ (Rn)
        XCH  A,direct            ;(A)←→ (direct)
        XCH  A,@Ri               ;(A)←→ ((Ri))

2.半字节交换指令

        XCHD  A,@Ri              ; (A) 3~0←→ ((Ri))3~0

该指令功能是将A的低4位和Ri间接寻址单元的低4位交换,而各自的高4位内容都保持不变。

3.累加器高低半字节交换指令

        SWAP  A                   ;(A)7 4←→ (A)3 0

由于十六进制数或BCD码都是以4位二进制数表示,因此SWAP指令主要用于实现十六进制数或BCD码的数位交换。

例3-7 试编程,将外部RAM 1000H单元中的数据与内部RAM 6AH单元中的数据相互交换。

数据交换指令只能完成累加器A和内部RAM单元之间的数据交换,要完成外部RAM与内部RAM之间的数据交换,需先把外部RAM中的数据取到A中,交换后再送回到外部RAM中。编程如下:

        MOV   DPTR,    # 1000H          ;外部RAM地址送DPTR
        MOVX  A,       @DPTR            ;从外部RAM中取数送A
        XCH   A,       6AH              ;A与6AH地址中的内容进行交换
        MOVX  @DPTR,   A                ;交换结果送外部RAM

3.3.5 堆栈操作指令

堆栈操作指令可以实现对数据或断点地址的保护,它只有两条指令:

        PUSH  direct              ;SP ← (SP)+ 1,(SP)← (direct)
        POP  direct               ;direct ← ((SP)),SP ← (SP)- 1

前一条指令是进栈指令,其功能是先将栈指针SP的内容加 1,使它指向栈顶空单元,然后将直接地址direct单元的内容送入栈顶空单元。

后一条指令是出栈指令,其功能是将SP所指的单元的内容送入直接地址所指出的单元,然后将栈指针SP的内容减1,使之指向新的栈顶单元。

注意,进栈、出栈指令只能以直接寻址方式来取得操作数,不能用累加器或工作寄存器Rn作为操作数。例如把累加器A的内容送入堆栈,应使用指令:

        PUSH  ACC

这里ACC表示累加器A的直接地址EOH。

利用堆栈操作指令也可以完成数据的传送。