3.3 指令系统

AT89S51/52单片机指令系统按功能可分为5大类:数据传送类指令、算术运算类指令、逻辑运算类指令、控制转移类指令和位操作类指令。

3.3.1 数据传送类指令

数据传送类指令是单片机中最常用、最基本的指令,用于将数值从源操作数传送到目的操作数。指令执行后,源操作数内容不改变,目的操作数内容修改为源操作数。但交换指令则不同,它是把源操作数和目的操作数内容进行互换。堆栈指令则是对堆栈进行操作。

数据传送类指令用到的助记符有MOV、MOVX、MOVC、XCH、XCHD、SWAP、PUSH和POP。这类指令一般不影响标志位,只有堆栈操作可以直接修改程序状态字PSW。另外,对于目的操作数为累加器A的指令将影响奇偶标志位P。

1.内部RAM数据传送指令(16条)

单片机芯片内部RAM是数据传送最为频繁的部分,有关的传送指令也最多,包括工作寄存器、累加器、内部RAM单元以及特殊功能寄存器之间的相互数据传送。传送指令中的右操作数为源操作数,指示数据的来源;而左操作数为目的操作数,表示数据的存储地址。指令完成将源操作数内容传送到目的操作数,操作数从右向左传送数据。

通用格式为MOV <目的操作数>,<源操作数>。

(1)以累加器A为目的操作数的指令(4条)

978-7-111-61780-8-Chapter03-7.jpg

这类指令的功能是将源操作数所指定的内容传送到累加器A。源操作数有立即数、工作寄存器、直接地址和寄存器间接寻址4种方式。

(2)以寄存器Rn为目的操作数的指令(3条)

978-7-111-61780-8-Chapter03-8.jpg

这3条指令的功能是把源操作数所指定的内容传送到当前工作寄存器组R0~R7的某个寄存器中。源操作数有寄存器A、直接地址和立即数3种方式。注意,没有“MOV Rn,Rn”和“MOV Rn,@Ri”指令。可见,工作寄存器之间不能直接传送数据。

(3)以直接地址为目的操作数的指令(5条)

978-7-111-61780-8-Chapter03-9.jpg

这类指令的功能是将源操作数所指定的内容送入由直接地址direct所指出的片内存储单元中。源操作数有立即数、直接地址、工作寄存器、累加器A和寄存器间址方式。

(4)以间接地址为目的操作数的指令(3条)

978-7-111-61780-8-Chapter03-10.jpg

978-7-111-61780-8-Chapter03-11.jpg

这类指令的功能是将源操作数所指定的内容送入以R0或R1为寄存器间址的片内存储单元中。源操作数有立即数、直接地址和累加器A这3种方式。对于AT89S52单片机片内的高128B RAM,可以采用这些指令进行数据的写操作。

(5)十六位数据传送指令(1条)

MOV DPTR,#datal6 ;DPTR←data16

这条指令的功能是将一个16位的立即数送入DPTR中。其中立即数的高8位送DPH,立即数的低8位送DPL。这条指令是三字节指令,即操作码占一个字节,16位立即数占两个字节。

【例3-1】已知(A)=40H,(R0)=00H,(R1)=00H,(30H)=0ABH,(40H)=7FH,执行以下指令后(A)=?

978-7-111-61780-8-Chapter03-12.jpg

指令执行后:(A)=0ABH。

【例3-2】已知(40H)=50H,(41H)=51H,(50H)=0ABH,(51H)=0CDH,执行以下指令后(50H)=?(51H)=?

978-7-111-61780-8-Chapter03-13.jpg

可以看出,指令执行后,50H与51H中内容进行互换,(50H)=0CDH,(51H)=0ABH。

2.外部RAM数据传送指令(4条)

对于AT89S51/52单片机指令系统,内部RAM单元之间的数据传送可以使用直接寻址、寄存器寻址以及寄存器间接寻址方式。CPU对外部RAM单元的访问只能使用寄存器间接寻址的方式,但可以分别使用DPTR和Ri作为间址寄存器。外部数据传送指令主要是通过累加器A实现CPU与片外数据存储器之间的数据传送。

AT89S51/52单片机是通过与外部数据存储器的数据传送指令来实现对外部数据存储器RAM的读写操作的。为了与访问内部RAM数据传送指令相区分,在指令助记符中增加了“X”以代表进行片外的操作。需要注意的是,在访问外部存储器RAM时,只能通过累加器A进行。在使用外部RAM数据传送指令时,应当先将要读或写的地址送入间址寄存器DPTR或Ri中,然后再采用传送指令。

使用Ri进行间接寻址:

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

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

使用Ri(i=0或1)进行寻址时,由于R0和R1是8位地址指针,因此指令的寻址范围只限于外部RAM的低256个单元。

使用DPTR进行间接寻址:

978-7-111-61780-8-Chapter03-14.jpg

由于DPTR是16位地址指针,因此指令的寻址范围可达整个片外数据存储器64KB空间。

例如,将外部数据存储器0030H单元中的内容写入外部数据存储器3000H单元中,可用以下指令实现:

MOV R0, #30H

MOVX A, @R0

MOV DPTR, #3000H

MOVX @DPTR, A

前两行指令将外部RAM中0030H单元内容取出来,后面两行实现写入操作。可见,在使用外部RAM数据传送指令时,先将要读或写的地址送入间址寄存器DPTR或R0中,才能使用外部RAM传送指令。

由于在AT89S51/52单片机指令系统中,片外扩展的I/O端口地址与片外RAM是统一进行编址的,没有专门对外设的输入/输出指令。因此,如果在片外数据存储器的地址空间上扩展I/O端口,则上面的4条指令就可以作为输入/输出指令。

3.程序存储器数据传送指令(2条)

由于程序存储器在逻辑上是统一编址的,因此在这里既包括内部程序存储器,也包括外部程序存储器。由于对程序存储器只能读而不能写,因此其数据传送都是单向的,即从程序存储器读出数据,并且只能向累加器A传送。这类指令共两条:

978-7-111-61780-8-Chapter03-15.jpg

这两条指令都是单字节指令,并且都为变址寻址方式,其寻址范围为64KB。指令首先执行16位无符号数的加法操作,获得基址与变址之和,其和作为程序存储器的地址,再将该地址中的内容送入A中,实现程序存储器到累加器的常数传送,每次传送一个字节。

这两条指令通常用于查表操作,因此可以看成是查表专用指令。虽然这两条指令的功能完全相同,但在具体使用中却有一点差异。前一条指令的基址寄存器DPTR能提供16位基址,而且还能在使用前给DPTR赋值,因此查表范围可达整个程序存储器的64KB空间,使用起来比较方便;后一条指令是以PC作为基址寄存器,虽然也能提供16位基址,但其基址值PC是固定的,不能通过数据传送指令来改变,而且随该指令在程序中的位置变化而变化,因此在使用时需对变址寄存器A进行修正。由于A的内容为8位无符号数,因此只能在当前指令下面的256个地址单元范围内进行查表。

【例3-3】以查表的方法将累加器中的十六进制数转换为ASCII码,结果放在累加器中。假设子程序起始地址为2000H,ASCII码表起始地址为3000H。程序段如下:

978-7-111-61780-8-Chapter03-16.jpg

4.数据交换指令(5条)

数据交换主要是在内部RAM单元与累加器A之间进行,有整字节和半字节两种交换。

(1)整字节交换指令

地址单元与累加器A进行8位数据交换,共有如下3条指令:

978-7-111-61780-8-Chapter03-17.jpg

这3条指令所完成的功能是将累加器A与源操作数所指出的数据相互交换。

(2)半字节交换指令

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

该指令实现地址单元与累加器A低4位的半字节数据交换。仅有一条将累加器A与寄存器间接寻址地址的半字节交换指令。

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

SWAP A ;(ACC.7~ACC.4)←→(ACC.3~ACC.0)

该指令主要完成累加器ACC的高4位与低4位互换。

由于十六进制数或BCD码都是以4位二进制数表示,因此XCHD和SWAP指令主要用于实现十六进制数或BCD码的数位交换。数据交换主要是在内部RAM单元与累加器A之间进行。

例如,将片内RAM中30H单元高4位与31H单元高4位的数据互相交换,两个单元的低4位不变,可用以下程序段实现:

MOV R0, #30H

MOV A, 31H

XCHD A, @R0

XCH A, @R0

MOV 31H, A

5.堆栈操作指令(2条)

堆栈操作有入栈和出栈两种。相应有两条指令:

978-7-111-61780-8-Chapter03-18.jpg

第一条指令称为进栈指令,其功能为先将堆栈指针SP的内部加1,然后将内部RAM中低128单元或特殊功能寄存器内容压入SP所指示的单元中。第二条指令称为出栈指令,其功能为先将堆栈指针所指示单元的内容弹出送内部RAM低128单元或特殊功能寄存器,然后将SP内容减1。堆栈指针SP总是指向堆栈的栈顶。

堆栈操作实际上是通过堆栈指针SP进行读写操作的,是以SP为间址寄寻址方式;因为SP是唯一的,所以在指令中把通过SP的间接寻址的操作数项隐含了,只表示出直接寻址的操作数项。

【例3-4】分析以下程序的运行结果。

MOV R1, #3FH

MOV A, #4EH

PUSH A

PUSH 01H

POP A

POP 01H

执行结果为(R1)=4EH,(A)=3FH,两者进行了数据交换。其中01H表示工作寄存器R1的直接地址。

通过此例得知,使用堆栈时应注意入栈和出栈的顺序,以保证正确地恢复现场。

3.3.2 算术运算类指令

AT89S51/52的算术运算类指令相当丰富。算术运算类指令主要是对8位无符号数据进行算术操作,其中包括加法、减法、加1、减1以及乘法和除法运算指令;借助溢出标志,可对有符号数进行补码运算;借助进位标志,可进行多精度加、减运算;也可以对BCD码进行运算。

算术运算指令都影响程序状态标志寄存器PSW的相关标志位。对这一类指令要特别注意正确地判断运算结果对标志位的影响。

1.加法指令(4条)

978-7-111-61780-8-Chapter03-19.jpg

这组指令完成的功能是将源操作数所指出的内容与累加器A相加,其结果存在A中。8位二进制数加法运算指令的一个加数总是累加器A,而另一加数可由不同寻址方法得到,其相加结果再送回累加器A。

加法运算影响PSW位的状态。在加法运算中,如果位3有进位,则辅助进位标志AC置1,否则AC清0;如果位7有进位,则进位标志CY置1,否则CY清0。两个带符号数相加,还有溢出的问题。若溢出标位OV置1,则表示和有溢出。

例如,(A)=0B2H,(R0)=97H,执行ADD A,R0指令。

运算结果为(A)=49H,(AC)=0,(CY)=1,(OV)=1,(P)=1。若0B2H和97H是两个无符号数,则结果为149H,运算是正确的;反之,若为两个带符号数,则由于有溢出而表明结果是错误的,因为两个负数相加不可能得到正数的和。

2.带进位加法指令(4条)

978-7-111-61780-8-Chapter03-20.jpg

这组指令的功能是把源操作数所指出的内容和累加器内容及进位标志CY相加,运算结果送入累加器A。该指令共有3个数参加运算,即累加器A、不同寻址方式的加数以及进位标志CY,其余与加法指令ADD相同。运算结果对PSW各位的影响同上述加法指令。

带进位加法指令常用于多字节数的加法运算,在低位字节相加时要考虑低字节有可能向高字节进位。因此,在做多字节加法运算时,必须使用带进位的加法指令。

【例3-5】两个双字节无符号数相加,被加数放在内部RAM中30H单元(高字节)和31H单元(低字节),加数放在内部RAM中40H单元(高字节)和41H单元(低字节),编写程序实现将和保存到30H单元(高字节)和40H单元(低字节)中。

程序段如下:

978-7-111-61780-8-Chapter03-21.jpg

相加结果占据被加数单元。但由于可能产生进位,所以在高字节相加时,还要考虑低位字节相加后的进位。程序第一行需要将进位标志清0。

3.带借位减法指令(4条)

978-7-111-61780-8-Chapter03-22.jpg

978-7-111-61780-8-Chapter03-23.jpg

这些指令的功能是从累加器A中减去不同寻址方式的操作数以及进位标志CY状态,其差再存储在累加器A中。

减法运算指令执行结果影响PSW的进位位CY、溢出位OV、半进位位AC和奇偶校验位P。

在多字节减法运算中,被减数的低字节有时会向高字节产生借位(即CY置1),所以在多字节运算中必须用带借位减法指令。在进行单字节减法或多字节的低8位字节减法运算时,应先将程序状态标志寄存器PSW的进位位CY清0。

减法运算只有带借位减法指令,而没有不带借位的减法指令。若进行不带借位的减法运算,只需用CLR C指令先把进位标志位清0即可。

带借位减法指令影响PSW的状态。如果位3有借位,则AC置1,否则清0;如果位7有借位,则CY置1,否则CY清0;此外两个带符号数相减也有溢出的问题,如溢出位OV置1,则表示有溢出出现。例如,(A)=0C7H,(R2)=54H,(CY)=1,执行SUBB A,R2指令。运算结果为(A)=72H,(CY)=0,(OV)=1,若C9H和54H是两个无符号数,则结果74H是正确的;反之,若为两个带符号数,则由于有溢出而表明结果是错误的,因为负数减正数其差不可能是正数。

4.加1指令(5条)

978-7-111-61780-8-Chapter03-24.jpg

这些指令可以对累加器、寄存器、内部RAM单元以及数据指针进行加1操作。加1指令的操作一般不影响程序状态字PSW的状态,除了在累加器A进行加1过程中对PSW的奇偶校验位P有影响外,即使对数据指针DPTR在加1过程中低8位有进位,也是直接进上高8位而不置位进位标志CY,指令INC DPTR也是唯一的一条16位加1指令。

5.减1指令(4条)

978-7-111-61780-8-Chapter03-25.jpg

这些指令可以进行累加器、寄存器以及内部RAM单元的减1操作。减1操作不影响程序状态字PSW的状态。此外还应注意,在AT89S51/52指令系统中,只有数据指针DPTR加1指令,而没有DPTR减1指令。

6.乘除指令(2条)

AT89S51/52指令系统有乘除指令各一条,它们都是单字节指令。乘除指令是整个指令系统中执行时间最长的指令,共需要4个机器周期,对于12MHz晶振的单片机,一次乘除时间为4μs。

(1)乘法指令

MUL AB ;BA←A×B

乘法指令实现两个8位无符号数相乘,两个乘数分别存储在累加器A和寄存器B中,所得乘积为16位,低8位存储在A中,高8位存储在B中。

乘法运算影响PSW的状态,进位标志位CY总是被清0,溢出标志位状态与乘积有关,若乘积小于0FFH(相乘以后B中的内容为0),则OV清0,否则OV置1。

(2)除法指令

DIV AB ;A←商(A/B),B←余数(A/B)

除法指令实现两个8位无符号数的除法运算,其中被除数存储在累加器A中,除数存储在寄存器B中;指令执行后,商存储于A中,余数存储于B中。

除法运算影响PSW的状态,进位标志位CY总是被清0,溢出标志位OV状态则反映除数情况,当除数为0(相除之前B中内容为0)时,OV置1,表明除法没有意义,无法进行;否则OV清0。

7.十进制加法调整指令(1条)

这是一条专用于对BCD码加法运算的结果进行修正的指令,其指令格式如下:

DA A

由于ADD和ADDC指令都是二进制数加法指令,对二进制数和十六进制数的加法运算都能得到正确的结果。但对于十进制数(BCD码)的加法运算,指令系统中并没有专门的指令,因此只能借助于二进制加法指令,即以二进制加法指令来进行BCD码的加法运算。但二进制数加法指令不能完全适用于BCD码十进制数的加法运算,因此在使用ADD和ADDC指令对十进制数进行加法运算之后,要对结果做有条件的修正。这就是所谓的十进制调整问题。

例如,执行BCD码加法运算ADD A,#87H,已知累加器A中BCD码为76H。

指令执行结果为(A)=0FDH。显然结果是不正确的,出错的原因在于BCD码是4位二进制编码,4位二进制数进位是逢16进1,但BCD码只用了其中的10个数,逢10进1,中间相差6。为此,对BCD码进行加法运算时,需要进行调整,才能得到正确的结果。调整的方法是把结果加6修正。

十进制调整的修正方法如下:

1)累加器低4位大于9或辅助进位位(AC)=1,则低4位加6修正:A←(A)+06H。

2)累加器高4位大于9或进位标志位(CY)=1,则高4位加6修正:A←(A)+60H。

这条指令必须紧跟在ADD或ADDC指令之后,且这里的ADD或ADDC的操作是对压缩的BCD数进行运算,不能直接对减法和乘除修正。DA指令不影响溢出标志。

例如,(A)=76H,执行指令:

ADD A, #87H

DA A

结果为(A)=63H,(CY)=1,结果正确。

3.3.3 逻辑运算类指令

AT89S51/52单片机有与、或和异或3种逻辑运算指令,以及移位指令共24条。这一类指令主要是用于对两个操作数按位进行与、或和异或逻辑操作,操作结果送到累加器A或直接寻址单元。移位、取反、清除等操作也包括在这一类指令中。这些指令执行后一般不影响程序状态字寄存器PSW,仅当目的操作数为累加器A时对奇偶标志位有影响。

1.逻辑与运算指令(6条)

逻辑与运算是按位进行的,逻辑与运算用符号∧表示。6条逻辑与运算指令如下:

978-7-111-61780-8-Chapter03-26.jpg

这类指令的功能是将两个指定的操作数按位相与,结果存储到目的操作数中。执行后一般不影响程序状态字寄存器PSW,仅当目的操作数为累加器A时对奇偶标志位P有影响。其中前4条指令运算结果存储在A中,而后两条指今的运算结果则存储在直接寻址的地址单元中。

当需要将字节中某几位屏蔽或清0时,可以将该字节与立即数相与,需要屏蔽或清0的位与0相与,不改变的位与1相与。

例如,(A)=3FH,将累加器A中低4位屏蔽。

ANL A, #0F0H

执行结果为(A)=30H。

2.逻辑或运算指令(6条)

逻辑或运算是按位进行的,逻辑或运算用符号∨表示,6条逻辑或运算指令如下:

978-7-111-61780-8-Chapter03-27.jpg

这类指令的功能是将两个指定的操作数按位相或,结果存储到目的操作数中。执行后一般不影响程序状态字寄存器PSW,仅当目的操作数为累加器A时对奇偶标志位P有影响。其中前4条指令运算结果存储在A中,而后两条指今的运算结果则存储在直接寻址的地址单元中。

当需要将字节中某几位置1时,可以将该字节与立即数相或,需要置1的位与1相或,不改变的位与0相或。

【例3-6】将内部RAM中30H单元的低4位传送到P0口的低4位,但P0口的高4位保持不变。程序段如下:

978-7-111-61780-8-Chapter03-28.jpg

3.逻辑异或运算指令(6条)

逻辑异或运算是按位进行的,异或运算的符号用表示,6条异或运算指令如下:

978-7-111-61780-8-Chapter03-29.jpg

这类指令的功能是将两个指定的操作数按位相异或,结果存储到目的操作数中。执行后一般不影响程序状态字寄存器PSW,仅当目的操作数为累加器A时对奇偶标志位P有影响。其中前4条指令运算结果存储在A中,而后两条指今的运算结果则存储在直接寻址的地址单元中。

4.累加器清零取反指令(2条)

978-7-111-61780-8-Chapter03-30.jpg

逻辑运算是按位进行的,当只改变字节数据的某几位,而其余位不变时,不能使用直接传送的方法,只能通过逻辑运算完成。累加器的按位取反实际上是逻辑非运算。

5.移位指令

AT89S51/52的移位指令只能对累加器A进行移位,有不带进位的循环左、右移和带进位的循环左、右移指令4条。

(1)累加器内容循环左移

RL A

该指令完成将累加器A中的8位二进制数都向左移动1位,最左边1位移动到最右边1位,即ACC.(n+1)←ACC.n(n=0~6),ACC.0←ACC.7。

(2)累加器内容循环右移

RR A

该指令完成将累加器A中的8位二进制数都向右移动1位,最右边1位移动到最左边1位,即ACC.n←ACC.(n+1)(n=0~6),ACC.7←ACC.0。

(3)累加器带进位标志循环左移

RLC A

该指令完成将累加器A中的8位二进制数同CY一起向左移动1位,CY移动到ACC最右边1位,ACC中最左边1位移动到CY,即ACC.(n+1)←ACC.n(n=0~6),ACC.0←CY,CY←ACC.7。

(4)累加器带进位标志循环右移

RRC A

该指令完成将累加器A中的8位二进制数同CY一起向右移动1位,CY移动到ACC最左边1位,ACC中最右边1位移动到CY,即ACC.n←ACC.(n+1)(n=0~6),ACC.7←CY,CY←ACC.0。

3.3.4 控制转移类指令

程序的顺序执行是由PC自动加1实现的。要改变程序的执行顺序,实现程序转移,可以通过强迫改变PC值的方法来实现,这就是控制转移类指令的基本功能。这类指令的功能主要是控制程序从原顺序执行地址转移到其他指令地址上。

控制转移类指令包括无条件转移指令、条件转移指令、子程序调用及返回指令等。这些指令多数不影响程序状态标志寄存器PSW。

1.无条件转移指令(4条)

不规定条件的程序转移称为无条件转移。AT89S51单片机共有4条无条件转移指令:

978-7-111-61780-8-Chapter03-31.jpg

1)指令LJMP addr16为长转移指令,指令执行后把16位地址(addr16)送PC,从而实现程序在64KB范围内的转移。其转移范围大,故称为长转移。长转移指令是三字节指令,依次是操作码、高8位地址和低8位地址。

2)指令AJMP addr11为绝对转移指令,AJMP指令的功能是构造程序转移的目的地址,实现程序转移。指令功能与LJMP相同,差别在于该指令所能转移的最大范围只有2KB。绝对转移指令是两字节指令,其中第一字节的低5位为指令操作码,其余11位为转移地址,用于替换PC的低11位内容,以形成新的PC值,由于addr11的最小值为000H,最大值为7FFH,因此绝对转移指令转移范围是2KB。在实际编程中,通常只给出转移目的地址标号即可,由汇编程序计算出转移地址。

3)SJMP是相对寻址方式转移指令,其中re1为相对地址偏移量。指令功能是计算出目的地址,并按偏移量re1计算得到的目的地址实现程序的相对转移。计算公式为:目的地址=(PC)+2+re1。re1为相对偏移量,是一个带符号的8位二进制补码数,其范围为-128~+127,因此所能实现的程序转移是双向的。

为方便起见,在汇编程序中都有计算偏移量的功能。用户编写汇编源程序时,只需要在相对转移指令中直接写上要转向的地址标号就可以了。程序汇编时由汇编程序自动计算和填入偏移量。

此外,在汇编语言程序中,为等待中断或程序结束,常有使程序原地等待的需要,对此可使用SJMP指令完成:

HERE: SJMP HERE

HERE:SJMP $ ;在汇编语言中,以$代表PC的当前值

4)变址寻址转移指令。

JMP @A+DPTR ;PC(A)+(DPTR)

这是一条一字节转移指令,转移的目的地址由A的内容和DPTR内容之和来确定,即目的地址=(A)+(DPTR)。本指令以DPTR内容为基址,而以A的内容作变址。因此只要把DPTR的值固定,而给A赋以不同的值,即可实现程序的多分支转移。

【例3-7】根据R1中的值转向不同的程序段执行。程序如下:

978-7-111-61780-8-Chapter03-32.jpg

2.条件转移指令

所谓条件转移就是程序转移是有条件的。执行条件转移指令时,如指令中规定的条件满足,则进行程序转移,否则程序顺序执行。条件转移有如下指令:

(1)累加器判零转移指令

978-7-111-61780-8-Chapter03-33.jpg

这两条指令都是两字节指令,是有条件的相对转移指令,以re1为偏移量。

【例3-8】将内部RAM中30H为首地址的16个数据传送到内部RAM中50H为首地址的单元中,遇到传送的数据为零时不予传送。程序如下:

978-7-111-61780-8-Chapter03-34.jpg

978-7-111-61780-8-Chapter03-35.jpg

(2)数值比较转移指令

数值比较转移指令把两个操作数进行比较,比较结果作为条件来控制程序的转移。以是否相等作为条件来控制程序转移,共有4条指令:

978-7-111-61780-8-Chapter03-36.jpg

数值比较转移指令是三字节指令。指令完成的功能是比较前两个无符号操作数的大小,若相等,则顺序执行,否则转移到偏移量所指出的地址执行,另外还会根据大小情况对进位位CY赋值。在AT89S51/52单片机中没有专门的数值比较指令,两个数的数值比较可利用这4条指令来实现,即按指令执行后CY的状态来判断数值大小。若(CY)=0,则左操作数>右操作数,若(CY)=1,则左操作数<右操作数。

【例3-9】将内部RAM中30H为首地址的16个数据传送到内部RAM中50H为首地址的单元中,遇到传送的数据为零时不予传送。

978-7-111-61780-8-Chapter03-37.jpg

(3)减1不为零转移指令

这是一组把减1与条件转移两种功能结合在一起的指令,共有如下两条指令:

978-7-111-61780-8-Chapter03-38.jpg

其完成的功能为将寄存器或直接寻址单元内容减1,如所得结果为0,则程序顺序执行,如没有减到0,则程序转移。

这两条指令主要用于控制程序循环。如预先把寄存器或内部RAM单元赋值循环次数,则利用减1条件转移指令,以减1后是否为0作为转移条件,即可实现按次数控制循环。

【例3-10】将内部RAM中30H为首地址的16个数据传送到内部RAM中50H为首地址的单元中,遇到传送的数据为零时不予传送。

978-7-111-61780-8-Chapter03-39.jpg

3.子程序调用与返回指令

子程序结构是一种重要的程序结构。在一个程序中经常遇到反复多次执行某程序段的情况,如果重复书写这个程序段,会使程序变得冗长而杂乱。对此,可采用子程序结构,即把重复的程序段编写为一个子程序,通过主程序调用而使用它,这样不但减少了编程工作量,而且也缩短了程序的长度。

调用子程序的程序称为主程序,主程序在调用子程序之后需要返回主程序,调用和返回构成了子程序调用的完整过程。为了实现这一过程,必须有子程序调用指令和返回指令。调用指令在主程序中使用,而返回指令则应该是子程序的最后一条指令。执行完这条指令之后,程序返回主程序断点处继续执行。

AT89S51/52共有两条子程序调用指令:

(1)绝对调用指令

这是一条两字节指令,其指令格式为

978-7-111-61780-8-Chapter03-40.jpg

子程序调用范围是2KB,其构造目的地址是在PC+2的基础上,以指令提供的11位地址取代PC的低11位,而PC的高5位不变。

在指令中提供了子程序入口地址的低11位,这11位地址的A7~A0在指令的第二字节中,A10~A8则占据第一字节的高3位。

为了实现子程序调用,该指令需要完成断点保护。断点保护是通过自动方式的堆栈操作实现的,即把加2以后的PC值自动送堆栈保存起来,待子程序返回时再送回PC。因为指令给出了子程序入口地址的低11位,因此本指令的子程序调用范围是2KB。

(2)长调用指令

978-7-111-61780-8-Chapter03-41.jpg

本指令是三字节指令,调用地址在指令中直接给出。指令执行后,断点进栈保存,调用addr16地址的子程序。长调用指令的子程序调用范围是64KB。addr16就是被调用子程序的入口地址,使用比较方便,但三字节指令较长,占用存储空间较多。

(3)返回指令

返回指令共有两条:

978-7-111-61780-8-Chapter03-42.jpg

子程序返回指令执行子程序返回功能,从堆找中自动取出断点地址送给程序计数器PC,使程序在主程序断点处继续向下执行。

中断服务子程序返回指令,除具有上述子程序返回指令所具有的全部功能之外,还有清除中断响应时被置位的优先级状态、开放较低级中断和恢复中断逻辑等功能。

(4)空操作指令

NOP ;(PC)←(PC)+1

空操作指令也算一条控制指令,即控制CPU不做任何操作,只消耗一个机器周期的时间。空操作指令是单字节指令,因此执行后PC加1,时间延续一个机器周期。NOP指令常用于程序的等待或时间的延迟。

3.3.5 位操作类指令

出于控制应用的需要,AT89S51/52单片机具有较强的布尔变量处理能力。所谓布尔变量即开关变量,以位(bit)为单位进行运算和操作。

在硬件方面,为了实现布尔变量处理,AT89S51有一个布尔处理机。所谓布尔处理机实际上就是一位的微处理机,它以进位标志作为累加位,以内部RAM位寻址区的128个可寻址位和特殊功能寄存器中的可寻址位作为存储位。

在软件方面,AT89S51单片机的指令系统中有一个进行布尔变量操作的指令子集,可以进行布尔变量的传送、运算及控制转移等操作。

1.位传送指令

位传送操作就是可寻址位与累加位CY之间的相互传送,共有两条指令:

978-7-111-61780-8-Chapter03-43.jpg

这两条指令主要用于对位操作累加器C进行数据传送,均为双字节指令。

前一条指令的功能是将某指定位的内容送入位累加器C中,不影响其他标志。后一条指令的功能是将C的内容传送到指定位,在对端口操作时,先读入端口8位的全部内容,然后把C的内容传送到指定位,再把8位内容传送到相应端口的锁存器。指令中的C就是CY。由于没有两个可寻址位之间的传送指令,因此它们之间无法实现直接传送。如需要这种传送,应使用这两条指令以CY作中介实现之。

2.位置位指令

978-7-111-61780-8-Chapter03-44.jpg

3.位复位指令

978-7-111-61780-8-Chapter03-45.jpg

4.位逻辑运算指令

位运算都是逻辑运算,有与、或和非三种,共6条指令。

978-7-111-61780-8-Chapter03-46.jpg

在布尔变量操作指令中,没有位的异或运算,如需要时可由多条上述位操作指令实现。通过位逻辑运算,可以对各种组合逻辑电路进行模拟,即用软件方法来获得组合电路的逻辑功能。

5.位控制转移指令

位控制转移指令就是以位的状态作为实现程序转移的判断条件。

1)以C状态为条件的转移指令,共两条指令。

978-7-111-61780-8-Chapter03-47.jpg

2)以位状态为条件的转移指令,共3条指令。

978-7-111-61780-8-Chapter03-48.jpg

这3条指令都是三字节指令,因此如果状态满足则程序转移,否则程序顺序执行。位控制转移指令就是以位的状态作为实现程序转移的判断条件。

3.3.6 伪指令

伪指令不属于指令集中的指令,在汇编时不产生目标代码,不影响程序的执行,仅指明在汇编时执行一些特殊的操作。

1.定义起始地址伪指令ORG(Origin)

格式:ORG 操作数

说明:操作数为一个16位的地址,它指出了下面指令的目标代码的第一个字节的程序存储器地址。在一个源程序中,可以多次定义ORG伪指令,但要求规定的地址由小到大安排,各段之间地址不允许重复。

2.定义赋值伪指令EQU(Equate)

格式:字符名称 EQU 操作数

说明:该指令是用来给字符名称赋值。在同一个源程序中,任何一个字符名称只能赋值一次。赋值以后,其值在整个源程序中的值是固定的,不可改变。对所赋值的字符名称必须先定义赋值后才能使用。其操作数可以是8位或16位的二进制数,也可以是事先定义的表达式。

3.定义数据地址赋值伪指令DATA

格式:字符名称 DATA 操作数

说明:DATA伪指令的功能和EQU伪指令相似,不同之处是DATA伪指令所定义的字符名称可先使用后定义,也可先定义后使用。在程序中它常用来定义数据地址。

4.定义字节数据伪指令DB(Define Byte)

格式:DB 数据表

说明:该伪指令是用来定义若干字节数据从指定的地址单元开始存储在程序存储器中。数据表是由8位二进制数或由加单引号的字符组成的,中间用逗号间隔,每行的最后一个数据不用逗号。

DB伪指令确定数据表中第一个数据的单元地址可以由ORG伪指令规定首地址。

5.定义双字节数据伪指令DW(Define Word)

格式:DW 数据表

说明:该伪指令与DB伪指令的不同之处是,DW定义的是双字节数据,而DB定义的是单字节数据,其他用法都相同。在汇编时,每个双字节的高8位数据要排在低地址单元,低8位数据排在高地址单元。

6.定义预留空间伪指令DS(Define Storage)

格式:DS 操作数

说明:该伪指令是用于告诉汇编程序,从指定的地址单元开始,保留由操作数设定的字节数空间作为备用空间。要注意的是DB、DW和DS伪指令只能用于程序存储器,而不能用于数据存储器。

7.定义位地址赋值伪指令BIT

格式:字符名称 BIT 位地址

说明:该伪指令只能用于有位地址的位(片内RAM和SFR块中),把位地址赋予规定的字符名称,常用于位操作的程序中。

8.定义汇编结束伪指令END

格式:END

说明:汇编结束伪指令END是用来告诉汇编程序,此源程序到此结束。在一个程序中,只允许出现一条END伪指令,而且必须安排在源程序的末尾。