3.3 指令系统
51单片机指令系统的111条指令可分为5大类,下面分别介绍各类指令的格式、功能、寻址方式及应用。
3.3.1 数据传送类指令
1.数据传送类指令的特点
数据传送指令是最常用的一类指令,共有29条,可以通过累加器进行数据传送,还可以在数据存储器之间或工作寄存器与数据存储器之间直接进行数据传送。
该类指令一般是把源操作数传送到目的操作数,源操作数可以采用寄存器、寄存器间接、直接、立即、基址加变址5种寻址方式;目的操作数可以采用寄存器、寄存器间接、直接3种寻址方式。指令执行后,源操作数不变,目的操作数修改为源操作数。
数据传送类指令一般不影响标志位,只有堆栈操作可以直接修改程序状态字PSW,对目的操作数为A的指令将影响奇偶标志P位。
数据传送类指令按存储空间可分为5类。数据传送类指令表见附录A。
2.数据传送类指令
(1)片内数据传送指令
1)以累加器A为目的操作数的指令有以下形式:
该组指令的功能是把源操作数传送给累加器A。
【例3-1】 数据传送指令示例。
2)以工作寄存器Rn为目的操作数的指令有以下形式:
【例3-2】 将A的内容传送至R1;30H单元的内容传送至R3;立即数80H传送至R7,用以下指令完成。
3)以直接地址为目的操作数的指令有以下形式:
【例3-3】 将A的内容传送至30H单元;R7的内容传送至20H单元;立即数0FH传送至27H单元;40H单元内容传送至50H单元。用以下指令完成:
4)以间接地址为目的操作数的指令:
该组指令的功能:把源操作数所指定的内容传送至以R0或R1为地址指针的片内RAM单元中。
源操作数有寄存器寻址、直接寻址和立即寻址3种方式;目的操作数为寄存器间接寻址。
【例3-4】 将20H开始的32个单元全部清零。
5)16位数据传送指令有以下唯一形式:
该指令的功能:把16位立即数传送至16位数据指针寄存器DPTR。
当要访问片外RAM或I/O端口时,一般用于将片外RAM或I/O端口的地址赋给DPTR。
【例3-5】 将外部RAM的8000H单元的内容传送至A中。
(2)片外数据存储器传送指令
片外数据存储器传送指令有以下形式:
单片机内部与片外数据存储器是通过累加器A进行数据传送的。
片外数据存储器的16位地址只能通过P0口和P2口输出,低8位地址由P0口送出,高8位地址由P2口送出,在地址输出有效且低8位地址被锁存后,P0口作为数据总线进行数据传送。
CPU对片外RAM的访问只能用寄存器间接寻址的方式,且仅有4条指令。以DPTR(16位)作间接寻址时,寻址的范围达64KB;以Ri(8位)作间接寻址时,仅能寻址256B的范围。而且片外RAM的数据只能和累加器A之间进行数据传送。
必须指出的是,51单片机指令系统中没有设置访问外设的专用I/O指令,且片外扩展的I/O端口与片外RAM是统一编址的,即I/O端口可看作独占片外RAM的一个地址单元,因此对片外I/O端口的访问均可使用这类指令。
【例3-6】 有一输入设备,其端口地址为2040H,该端口数据为41H,将此数据存入片内RAM的20H单元。
用以下指令完成:
执行结果:片内20H单元的内容为41H。
【例3-7】 有一输出设备,其端口地址为2041H,将片内RAM的20H单元的数据41H输出给该设备。用以下指令完成:
执行结果:片外2041H端口的内容为41H。
【例3-8】 把片外RAM的2000H单元中的数61H取出,传送到片外RAM的3FFFH单元中去。在片外RAM之间传送数据也必须通过累加器A来完成,指令段如下。
执行结果:3FFFH单元的内容为61H。
(3)程序存储器数据传送指令
程序存储器数据传送指令有以下两种形式。
51单片机指令系统中,这两条指令主要用于查表技术,在使用时应注意以下几点。
1)A的内容为8位无符号数,即表格的变化范围为256B。
2)PC的内容为当前值。由于CPU在读取本指令时,PC已指向下一条指令,故PC作基址寄存器时,已不是原PC值,而是PC+1(因为本指令是单字节指令)。
3)MOVC A,@A+PC与MOVC A,@A+DPTR两条指令的区别:
前者查表的范围与存放该指令的地址有关,由于PC的值已经确定,以及8位累加器A的限制,数据表格只能存放在该指令后面的256个字节单元之内。而后者查表范围通过改变DPTR的值可达整个程序存储器64KB的任何地址空间(即DPTR的值为表格首地址),其数据表格可以为各个程序模块共享。
4)将要查表的数据字作为偏移量送累加器A中,通过改变变址寄存器A的内容即可改变表格中的位置,执行该指令即可获得所需的内容(即将该位置单元的内容传送给A)。因此,可以根据需要设计表格的内容,将A的内容作为偏移量以实现换码。
【例3-9】 LED显示器0~9的字形显示段码在程序存储器中的存放情况(数据表)如下。
从段码表中取出“3”并送LED(设外部端口地址为1200H)显示,可用以下指令完成。
执行结果:A=0B0H,PC=2107H。字符“3”的段码送1200H显示。
【例3-10】 在程序存储器中,有一表示数字字符的ASCII代码的数据表格,表格的起始地址为7000H。
将A中的数字2转换为字符“2”的ASCII代码,可用以下指令完成。
执行结果:A=32H,PC=100AH。
(4)数据交换指令
数据交换指令有以下形式。
1)字节交换指令:
2)低半字节交换指令:
3)累加器A的高、低半字节交换指令:
【例3-11】 数据交换指令示例。
1)设A=3FH,R0=20H,(20H)=46H(即内部RAM20H单元的内容为46H)。
执行指令:
执行结果:A=46H,(20H)=3FH。
2)A=7FH,R0=20,(20H)=35H。
执行指令:
执行结果:A=75H,(20H)=3FH。
3)将20H单元的内容与A的内容互换,然后将A的高4位存入R1指向的内部RAM单元中的低4位,A的低4位存入该单元的高4位。
可由下列指令完成。
由以上传送类指令可以看出:指令的功能主要由助记符和寻址方式来体现,只要掌握了助记符的含义和与之相对应的操作数的寻址方式,指令是很容易理解的。
必须强调的是,累加器A是一个特别重要的寄存器,无论A作目的寄存器还是源寄存器,CPU对它都有专用指令。
由于累加器A位于片内RAM的高128B(SFR)的存储空间,其字节地址为E0H,也可以采用直接地址来寻址。例如:
也可以用
上面两条指令的执行结果都是将Rn的内容传送至A中。再如:
由此可以看出,完成某一功能采用不同的指令,其占用存储单元的数量及指令执行的时间(尤其在循环结构程序中)有较大的差别。因而,在程序设计过程允许的情况下,应尽可能地使用含有累加器A的指令,以利于减少程序在存储器中的存储单元占有量,提高程序的运行速度。
注意:在上述指令中,寄存器Rn是由PSW中的RS1、RS0来选定,Rn对应该工作寄存器组的R0~R7中的某一个;直接地址direct为片内RAM的00H~7FH单元及80H~FFH中的某些专用寄存器单元;在间接寻址@Ri中,只能用当前工作寄存器R0或R1作地址指针,可用MOV访问片内RAM的00H~7FH单元。由于Ri为8位存储器,用MOVX访问片外RAM时,间接寻址@Ri寻址范围只能在0~255的存储单元内。
(5)堆栈操作指令
堆栈操作指令有以下形式。
在51单片机中,堆栈只能设定在片内RAM中,由SP指向栈顶单元。
PUSH指令是入栈(或称压栈或进栈)指令,其功能是先将堆栈指针SP的内容加1,然后将直接寻址direct单元中的数压入到SP所指示的单元中。
POP是出栈(或称弹出)指令,其功能是先将堆栈指针SP所指示的单元内容弹出到直接寻址direct单元中,然后将SP的内容减1,SP始终指向栈顶。
使用堆栈时,一般需重新设定SP的初始值。因为系统复位或上电时,SP的值为07H,而07H是CPU的工作寄存器区的一个单元地址,为了不占用寄存器区的07H单元,一般应在需使用堆栈前,由用户给SP设置初值(栈底)。但应注意不能超出堆栈的深度。一般SP的值可以设置为1FH以上的片内RAM单元。
堆栈操作指令一般用在中断处理或子程序过程中,若需要保护现场数据(如内部RAM单元的内容),首先执行现场数据的入栈指令,用于保护现场;中断处理或子程序结束前再使用出栈指令恢复现场数据。
【例3-12】 堆栈操作指令示例。
1)设堆栈栈底为30H,将现场A和DPTR的内容压栈。
已知A=12H,DPTR=3456H。
可由以下指令完成。
执行结果:SP=33H,片内RAM的31H、32H、33H单元的内容分别为12H、56H、34H。
2)将本例“1)”中已压栈的内容弹出到原处,即恢复现场。
可由以下指令完成。
执行结果:SP=30H,A=12H,DPTR=3456H。
3.3.2 算术运算类指令
1.算术运算类指令特点
算术运算类指令共有24条,包括加、减、乘、除4种基本的算术运算指令。
该类指令的主要功能如下。
1)对8位无符号数进行直接的运算。
2)借助溢出标志对有符号的二进制整数进行加减运算。
3)借助进位标志,可以实现多字节的加减运算。
4)对压缩的BCD数进行运算(压缩BCD数,是指在1个字节中存放2位BCD数)。
5)算术运算指令对程序状态字PSW中的Cy、AC、OV三个标志都有影响,根据运算的结果可将它们置1或清0。但是加1和减1指令不影响这些标志。
算术运算类指令用到的助记符有:ADD、ADDC、SUBB、INC、DEC、DA、MUL和DIV 8种,其指令见附录A。
2.加法指令
(1)不带进位的加法指令
不带进位的加法指令有以下形式。
这4条指令的功能是完成A中的数与源操作数所确定的内容按二进制运算相加,其和送入目的操作数累加器A中。
若参加运算的数为两个无符号数,其数值范围为0~255,运算结果超出此范围,则CPU自动置进位标志位Cy=1(否则Cy=0),由此可判断运算结果是否溢出。
若参加运算的数为两个补码表示的有符号数,其数值范围为-128~+127,运算结果超出此范围,则CPU自动置溢出标志位OV=1(否则OV=0),由此可判断运算结果是否溢出。另外还可通过溢出表达式来判断运算结果是否溢出:
OV=D6→7⊕D7→C
式中,D6→7表示第6位向第7位有进位,D7→C表示第7位向Cy有进位,运算结果是否溢出可以通过这两种情况进行异或来判断。
【例3-13】 已知A=B5H,R1=96H,执行指令:
ADD A,R1
运算结果:A=4BH,OV=D6→7⊕D7→C=0⊕1=1,其和产生溢出。
则标志位:Cy=1,AC=0,OV=1。
(2)带进位加法指令
带进位加法指令有以下形式。
该组指令的功能:将指令中指出的源操作数与A的内容及进位标志位Cy的值相加,结果送A。此类指令常用于多字节加法运算中。
【例3-14】 设A=0AEH,(20H)=81H,Cy=1,求两数的和及对标志位的影响。
执行结果为:A=0AEH+81H+1=30H,Cy=1,AC=1,OV=1。
(3)加1指令
加1指令有以下形式。
该组指令的功能是把操作数指定的单元或寄存器的内容加1。
【例3-15】 设R0=7EH,DPTR=10FEH,(7EH)=0FFH,(7FH)=38H,执行下列指令:
执行结果:(7EH)=00H,R0=7FH,(7FH)=39H,DPTR=1101H。
(4)十进制调整指令
十进制调整指令形式如下。
指令的功能:将存放于A中的两个BCD码(十进制数)的和进行十进制调整,使A中的结果为正确的BCD码数。
由于算术逻辑单元ALU只能作二进制运算,如果进行BCD码运算的结果超过9,必须对结果进行修正。此时只需在加法指令之后紧跟一条这样的指令,即可根据标志位Cy、AC和累加器的内容对结果自动进行修正,使之成为正确的BCD码形式。
【例3-16】 若有BCD码:A=56H,R3=67H,两数相加仍用BCD码的两位数表示,结果为23H,执行以下指令:
则结果为:A=23H,Cy=1。
注意:DA A指令只能用在加法指令(ADD、ADDC或INC)之后,DA A指令影响Cy,不影响OV。
3.减法指令
(1)带借位减法指令
带借位减法指令有以下形式。
该组指令的功能:从累加器A中减去源操作数指定的内容和标志位Cy,结果存入累加器A中。
指令执行后影响Cy、AC、OV及P等标志,根据这些标志可分析两数差值情况:
当两个无符号数相减时,若Cy=1,表明被减数小于减数,此时必须将累加器A中的值连同借位一并考虑才是正确结果。
当两个有符号数相减时,若同号相减,则不发生溢出,OV=0,结果正确。异号相减时,若OV=0,表明没有发生溢出;若OV=1,表明发生溢出,从而导致运算结果发生错误。
【例3-17】 设A=0DBH,R1=73H,Cy=1。
执行指令:
结果为:A=67H,Cy=0,AC=0,OV=0。
(2)减1指令
减1指令有以下几种形式。
该组指令的功能:将指定的操作数的内容减1。若操作数为00H,则减1后下溢为0FFH,不影响标志位,只有DEC A影响标志位P。
4.乘法指令
乘法指令的形式如下。
该指令的功能:把累加器A和寄存器B中的两个8位无符号数相乘,乘积又送回A、B内,A中存放低位字节,B中存放高位字节。若乘积大于255,即B中非0,则溢出标志OV=1,否则OV=0,而Cy总为0。
【例3-18】 设A=50H,B=32H,执行指令:
执行结果:A=0A0H,B=0FH,OV=1,Cy=0。
5.除法指令
除法指令的形式如下。
该指令的功能:把A中的8位无符号数除以B中的8位无符号数,商存放在A中,余数存放在B中。Cy和OV均清零。若除数为0,执行该指令后结果不定,并将OV置1。
【例3-19】 设A=0FAH(250),B=14H(20),执行指令:
执行结果为:A=0CH(12),B=0AH(10),OV=0,Cy=0。
3.3.3 逻辑运算类指令
逻辑操作指令共24条,所有指令均对8位二进制数按位进行逻辑运算。
逻辑运算类指令无进位,一般不影响标志位。
1.双操作数逻辑运算指令
(1)逻辑“与”指令
逻辑“与”指令有以下形式。
该组指令的功能:将源操作数和目的操作数按对应位进行逻辑“与”运算,并将结果存入目的地址(前4条指令为A,后2条指令为直接寻址的direct单元)中。
与运算规则是:与“0”相与,本位为“0”(即屏蔽);与“1”相与,本位不变。
逻辑“与”指令常用于屏蔽操作数中的某些位。
【例3-20】 设A=0AAH,将A的低4位保持不变,高4位屏蔽,然后将其经P1口输出。
可执行以下指令:
执行结果为A=0AH(高4位清零,低4位不变)。
逻辑“与”指令也可用于判断某些位是否为1。如对于有符号数运算结果的最高位(D7)为1,则说明该数为负数。如:
该指令段表示累加器A与寄存器R1的数据相加的结果为负数时,程序转至标号LOP处执行。
(2)逻辑“或”指令
逻辑“或”指令有以下形式。
该组指令的功能:将源操作数和目的操作数按对应位进行逻辑“或”运算,并将结果存入目的地址(前4条指令为A,后2条指令为直接寻址的direct单元)中。
或运算规则是:与“1”相或,本位为“1”;与“0”相或,本位不变。
【例3-21】 已知A=0D4H,执行指令:
执行结果为A=0DFH(高4位不变,低4位置1)。
(3)逻辑“异或”指令
逻辑“异或”指令有以下形式。
该组指令的功能是:将源操作数和目的操作数按对应位进行逻辑“异或”运算,并将结果存入目的地址(前4条指令为A,后2条指令为直接寻址的direct单元)中。
异或运算的运算规则是:与“1”异或,本位为非(即求反);与“0”异或,本位不变。
【例3-22】 A=0D4H,执行指令:
执行结果为A=0DBH(高4位不变,低4位求反)。
对于相等的两个数,则异或结果为0,由此可判断两数是否相等。
2.单操作数逻辑运算指令
单操作数逻辑运算指令有以下两种形式。
(1)累加器A清零指令
累加器A清零指令:
(2)累加器A求反指令
累加器A求反指令:
【例3-23】 利用求反指令,对40H单元内容求补(即求反加1)。
可执行以下指令。
3.累加器A循环移位指令
(1)累加器A循环移位指令
累加器A循环移位指令有以下形式。
该组指令不影响标志位。
当A的最高位(D7)为0时,执行一次RL指令相当于对A进行一次乘2操作。
当A的最低位(D0)为0时,执行一次RR指令相当于对A进行一次除2操作。
该指令连续执行4次,与指令SWAP A的执行结果相同。
(2)带进位位Cy的累加器A循环移位指令
带进位位Cy的累加器A循环移位指令有以下形式。
3.3.4 控制转移类指令
程序一般是顺序执行的(由程序计数器PC自动递增实现),但有时因为操作的需要或比较复杂的程序,需要改变程序的执行顺序,即将程序跳转到某一指定的地址(即将该地址赋给PC)后再执行,此时就要用到控制转移指令。
控制转移指令共17条,可分为4类:无条件转移指令、条件转移指令、空操作指令及子程序调用与返回指令。
1.无条件转移指令
不受任何条件限制的转移指令称为无条件转移指令。51单片机无条件转移指令有以下类型。
(1)长转移指令
长转移指令的形式如下。
该指令功能:把16位地址(addr16)送给PC,从而实现程序转移。允许转移的目标地址在整个程序存储器空间。
在实际使用时,addr16常用标号表示,该标号即为程序要转移的目标地址,在汇编时把该标号汇编为16位地址。
【例3-24】 某单片机的监控程序的起始地址为8000H,要求单片机开机后自动执行监控程序。
单片机开机后程序计数器PC为复位状态,即(PC)=0000H。为使开机后自动转向8000H处执行,则必须在0000H单元存放一条转移指令:
(2)绝对转移指令
绝对转移指令的形式如下。
该指令功能是把PC当前值(加2修改后的值)的高5位与指令中的11位地址拼接在一起,共同形成16位目标地址送给PC,从而使程序转移。允许转移的目标地址在程序存储器现行地址的2K(即211)字节的空间内。
在实际使用时,addr11常用标号表示,注意所引用的标号必须与该指令下面第一条指令处于同一个2KB范围内,否则会发生地址溢出错误。该标号即为程序要转移的目标地址,在汇编时把该标号汇编为16位地址。
(3)相对转移指令(亦称短转移指令)
相对转移指令的形式如下。
该指令的功能:根据指令中给出的相对偏移量rel[相对于当前PC=(PC)+2],计算出程序将要转移的目标地址(PC)+2+rel,把该目标地址送给PC。
注意,相对偏移量rel是一个用补码形式表示的有符号数,其范围为-128~+127,所以该指令控制程序转移的空间不能超出这个范围,故称短转移指令。
在实际使用时,rel常用标号来表示,该标号即为程序要转移的目标地址。
【例3-25】 在程序存储器0100H单元开始存储有下列程序段,则程序执行完SJMP指令后,自动转向LOOP处执行。分析标号LOOP的地址是怎样形成的,并计算相对转移指令SJMP中的偏移量rel。
分析:程序中标号LOOP所代表的指令地址是0131H,在取出0100H单元的SJMP指令后,PC的当前值为(PC)+2=0100H+2=0102H,目标地址为PC的当前值加rel,即LOOP=(PC)+2+rel。
求出相对偏移量为rel=LOOP-(PC)-2=0131H-0100H-2=2FH。
在实际应用中常使用该指令完成程序“原地踏步”的功能,等待中断事件的发生,可用以下指令:
LOOP:SJMP LOOP
或
SJMP $
以上两条指令执行的结果是相同的。
(4)间接长转移指令(相对长转移指令)
间接长转移指令的形式如下。
该指令也称散转指令,其功能是把累加器A中8位无符号数与数据指针DPTR的16位数相加,结果作为下一条指令地址送入PC,指令执行后不改变A和DPTR中的内容,也不影响标志位。
该指令可根据A的内容进行跳转,而A的内容又可随意改变,故可形成程序分支。本指令跳转范围为64KB。
例如,下面程序段可根据A的值决定转移的目标地址,形成多分支散转结构。
注意:由于本指令和AJMP指令均为双字节指令,故A的内容必须为偶数。
2.条件转移指令
所谓条件转移指令是指根据指令中给定的判断条件决定程序是否转移。
当条件满足时,就按指令给定的相对偏移量进行转移;否则,程序顺序执行。
51单片机的条件转移指令中目标地址的形成属于相对寻址,其指令转移范围、偏移量的计算及目标地址标号的使用均同SJMP指令。
51单片机的条件转移指令有以下类型。
(1)累加器判零转移指令
累加器判零转移指令有以下形式。
这两条指令均为双字节指令,以累加器A的内容是否为0作为转移的条件。本指令执行前,累加器A应有确定的值。
(2)比较不相等转移指令
比较不相等转移指令有以下4种形式。
1)指令格式:
该指令的功能:若(A)>data,则PC←(PC)+3+rel,且Cy=0(满足条件相对转移)。若(A)<data,则PC←(PC)+3+rel,且Cy=1(满足条件相对转移)。否则,PC←(PC)+3且Cy=0(顺序执行)。
2)指令格式:
该指令的功能:若(A)>(direct),则PC←(PC)+3+rel,且Cy=0(满足条件相对转移)。若(A)<(direct),则PC←(PC)+3+rel,且Cy=1(满足条件相对转移)。否则,PC←(PC)+3且Cy=0(顺序执行)。
3)指令格式:
该指令的功能:若(Rn)>data,则PC←(PC)+3+rel,且Cy=0(满足条件相对转移)。若(Rn)<data,则PC←(PC)+3+rel,且Cy=1(满足条件相对转移)。否则,PC←(PC)+3且Cy=0(顺序执行)。
4)指令格式:
该指令的功能:若((Ri))>data,则PC←(PC)+3+rel,且Cy=0(满足条件相对转移)。若((Ri))<data,则PC←(PC)+3+rel,且Cy=1(满足条件相对转移)。否则,PC←(PC)+3且Cy=0(顺序执行)。
该组指令为三字节指令,其功能是比较前面两个操作数(无符号数)的大小,若两数不相等为条件满足,则作相对转移,由偏移量rel指定地址;若相等为条件不满足,则顺序执行下一条指令。
注意:两数在比较时按减法操作并影响标志位Cy,但指令的执行结果不影响任何一个操作数内容。
【例3-26】 将数据00H~0FH写入RAM的30H~3FH单元。
可执行以下指令。
(3)减1不为0转移指令
减1不为0转移指令有以下形式。
该组指令中第一条指令为双字节指令,第二条指令为三字节指令。
该组指令对控制已知循环次数的循环过程十分有用,在应用程序中需要多次重复执行某程序段时,可指定任何一个工作寄存器Rn或RAM的direct单元为循环计数器,对计数器赋初值以后,每完成一次循环,执行该指令使计数器减1,直到计数器值为0时循环结束。
【例3-27】 设计一个延时1ms的子程序,设晶振频率为12MHz,一个机器周期为1µs,可由以下指令完成。
此程序中LOOP为循环程序的入口,由DJNZ指令判断R7是否为“0”来决定是否进入循环,循环体执行一次需4个机器周期,R7的内容255即为循环次数,该程序段的总执行时间为
(1+4×255+2)μs=1023µs≈1ms
由此可看出,循环时间的长短可通过循环次数来控制,延时时间为100ms的子程序可对该程序修改如下。
条件转移指令还包括根据位状态判断是否转移,详见本章3.3.6节位操作类指令。
3.空操作指令
空操作指令的形式如下。
NOP指令是唯一的一条不使CPU产生任何操作控制的指令,该指令的功能是使程序计数器PC加1,在执行时间上消耗12个时钟周期,因此常用NOP指令实现等待或延时。
3.3.5 子程序调用与返回指令
在程序设计时,常常有一些程序段被多次反复执行,为了缩短程序,节省存储空间,把具有通用意义且逻辑上相对独立的某些程序段编写成子程序。当某个程序(可以是主程序或子程序)需要引用该子程序时,可通过子程序调用指令转向该子程序执行,当子程序执行完毕,可通过子程序返回指令返回到子程序调用指令的下一条指令继续执行原程序。
在调用子程序过程中需要解决以下问题。
1)保护断点。所谓断点是指子程序调用指令的下一条指令的第一个字节地址。
为了使子程序执行之后能正确返回,需要把断点送入堆栈保存,当子程序执行完毕,再从堆栈中取出该断点送回PC,继续执行原来的程序。保护断点是系统自动执行的,不需要用户程序处理。
2)建立子程序入口。子程序入口是指子程序中第一条指令的第一个字节地址,即子程序调用指令给出的目标地址。在执行调用指令时,需将子程序的入口地址送入程序计数器PC,以便执行子程序。
3)保护现场。所谓保护现场是指在执行子程序前,需要保存程序中正在使用的存储单元和寄存器的内容。这些内容有可能在执行子程序时丢失,所以,执行子程序前,可通过指令将这些内容压入堆栈保存。
51单片机子程序调用与返回指令有以下形式。
(1)绝对调用指令
绝对调用指令格式如下。
该指令为双字节指令。
从程序存储器取出该指令后,PC自动加2指向下一条指令的首地址(断点地址),然后执行该指令,其功能是:首先保护断点,将PC的值压栈保护(先压低位,后压高位),接着将指令中的11位目标地址(addr11)送入PC的低11位与PC的高5位合成一个程序要转移的目标地址,即子程序入口地址,从而转去执行被调用的子程序。
ACALL指令由于只给出11位目标地址,所以,目标地址只能在ACALL的下一条指令2KB的空间范围内。
该指令执行速度相对较快。
(2)长调用指令
长调用指令格式如下。
该指令为三字节指令。
从程序存储器取出该指令后,PC自动加3指向下一条指令的首地址(断点地址),然后执行该指令,其功能是:首先保护断点,将PC的值压栈保护(先压低位,后压高位),接着将指令中的16位目标地址(addr16)送入PC,即子程序入口地址,从而转去执行被调用的子程序。
该指令提供16位目标地址,可调用64KB范围内的任意子程序。在实际应用时,addr16常用被调用子程序第一条指令的标号(地址)表示。
(3)一般子程序返回指令
子程序返回指令格式如下。
当程序执行到本指令时,自动从堆栈中取出断点地址送给PC,程序返回断点[即调用指令(ACALL或LCALL)的下一条指令处]继续往下执行。
RET指令为子程序的最后一条指令。
(4)中断子程序返回指令
中断子程序返回指令格式如下。
该指令除具有RET指令的功能外,在返回断点的同时,RETI还要释放中断逻辑以接受新的中断请求。中断服务程序(中断子程序)必须用RETI返回。
RETI指令为中断子程序的最后一条指令。
3.3.6 位操作类指令
51单片机的一大特点是在硬件结构中有一个位处理机和位寻址空间,在指令系统中设有专门处理布尔(位)变量的指令子集,又称位操作指令。
在位处理机中,借用进位标志Cy来存放逻辑运算结果,大部分位操作指令都涉及Cy,因此,它相当于位处理机的“累加器”,称“位累加器”,用符号C表示。位操作指令以位(bit)为单位进行运算和操作。
位操作指令共17条,所有的位操作指令均采用位(直接)寻址方式,在进行位操作时,51单片机汇编语言中的位地址可用以下4种方式表示。
1)直接位地址方式。如0E0H为累加器A的D0位的位地址,标志位F0的位地址为0D5H。
2)点操作符表示方式。用操作符“.”将具有位操作功能单元的字节地址或寄存器名与所操作的位序号(0~7)分隔。例如,PSW.5说明是程序状态字的第5位,即F0。
3)位名称方式。对于可以位寻址的特殊功能寄存器,在指令中直接采用位定义名称。
例如,EA为中断允许寄存器的第7位。
4)用户定义名方式。如用伪指令“OUT BIT P1.0”定义后,允许指令中用OUT代替P1.0。
1.位传送指令
位传送指令有以下形式。
指令中其中一个操作数必须是进位标志C,bit可表示任何直接位地址。
【例3-28】 将ACC中的最高位送入P1.0输出,可执行以下指令。
2.位置位和复位指令
(1)位置位指令
位置位指令有以下形式。
(2)位复位指令
位复位指令有以下形式。
采用这类指令可以对布尔累加器C和指定位置1或清零。
例如:
3.位逻辑运算指令
(1)位逻辑“与”指令
位逻辑“与”指令有以下形式。
该组指令的功能是:进位标志Cy与直接寻址位的布尔值进行位逻辑“与”运算,结果送入Cy。
注意:bit前的斜杠表示对(bit)求反,求反后再与Cy的内容进行逻辑操作,但并不改变bit原来的值。
(2)位逻辑“或”指令
位逻辑“或”指令有以下形式。
该组指令的功能是:进位标志Cy与直接寻址位的布尔值进行位逻辑“或”运算,结果送入Cy。
(3)位逻辑“非”指令
位逻辑“非”指令有以下形式。
该组指令的功能是:对进位标志Cy或直接寻址位bit的布尔值进行位逻辑“非”运算,结果送入Cy或bit。
【例3-29】 由P1.0、P1.1输入两个位数据(“0”或“1”)存放在位地址X、Y中,使Z满足逻辑关系式:,Z经P1.3输出。
可执行以下指令。
4.位条件转移指令
(1)位累加器Cy状态判断转移指令
位累加器Cy状态判断转移指令有以下形式。
该组指令为双字节指令。
该组指令通常与CJNE指令一起使用,可以比较出两个数的大小,从而形成大于、小于、等于3个分支。
(2)位状态判断转移指令
位状态判断转移指令有以下形式。
该组指令为三字节指令。
【例3-30】 测试P1口的P1.7位,若该位为1,将片内30H单元的内容输出到P2口,否则,读入P1口的状态存入片内20H单元。可执行以下指令。