MCS-51单片机的程序转移指令共14条,可进一步细分为无条件转移指令、条件转移指令、子程序调用指令等。另有位条件转移类指令,已在位操作指令中进行了介绍。所有程序转移类指令执行时间都是两个机器周期。
无条件转移指令的功能是当程序碰到该指令时,无条件转移到该指令提供的地址去。MCS-51有4条无条件转移指令,分别提供了不同的转移范围和转移方式。
(1)绝对(短)转移指令。
AJMP addr11 ;PC10~0←addr11
说明:(1)本指令为2KB地址范围内的转移指令。转移的目的地址要求与AJMP指令后面一条指令在同一个2KB范围。MCS-51单片机的64KB程序存储器划分为32个连续的2KB空间。每一个2KB空间称为1页,如下所示。
(2)本指令为双字节指令。设addr11的各位是a10a9a8…a2a1a0,则指令
AJMP addr11的二进制机器码为a10a9a800001a7a6a5a4a3a2a1a0。
64KB程序存储器中页的具体划分如下。
0000H~07FFH、0800H~0FFFH、1000H~17FFH、1800H~1FFFH、2000H~27FFH、
2800H~2FFFH、3000H~37FFH、3800H~3FFFH、4000H~47FFH、4800H~4FFFH、
5000H~57FFH、5800H~5FFFH、6000H~67FFH、6800H~6FFFH、7000I~77FFH、
7800H~7FFFH、8000H~87FFH、8800H~8FFFH、9000H~97FFH、9800H~9FFFH、
A000H~A7FFH、A800H~AFFFH、B000H~B7FFH、B800H~BFFFH、C000H~C7FFH、
C800H~CFFFH、D000H~D7FFH、D800H~DFFFH、E000H~E7FFH、E800H~EFFFH、
F000H~F7FFH、F800H~FFFFH。
【例3-14】若在ROM中的07FDH和07FEH两地址单元处有一条AJMP指令,试问它向高地址方向跳转有无余地?
解:AJMP指令执行过程中,要求PC值的高5位不能发生变化。但是在执行本例的AJMP指令时PC内容已经等于是07FFH,若向高地址跳转就到0800H以后了,这样高5位地址就要发生变化,这是不允许的。换言之,07FFH是第0个2KB页面中的最后一个字节,因此从这里往高地址方向再无AJMP跳转的余地了。
上述表明,笼统地谈AJMP的跳转范围为2KB是不确切的,而应当说AJMP跳转的目的地址必须与AJMP后面一条指令位于同一个2KB页面范围之内。
(2)长转移指令。
LJMP addrl6 ;PC←addrl6
说明:本指令为64KB程序存储器空间的全范围转移指令,转移地址可为64KB地址值中的任一值。本指令为3字节指令。
(3)短(相对)转移指令。
SJMP rel ;PC←PC+2+rel
说明:本指令为相对转移指令。因为rel为1字节补码(偏移量),且SJMP rel指令为双字节指令,所以转移范围为-126D~+129D,共计256个单元。
例如,LOOPl:SJMP LOOP2。
如LOOPl标号处地址为0100H,LOOP2标号处地址为0130H,则目标地址为0130H,偏移量rel=0130H-0100H-2H=2EH。
如LOOPl标号处地址为0100H,LOOP2标号处地址为00E4H,则目标地址为00E4H,偏移量rel=00E4H-0100H-2H=-1EH,用补码表示rel=0E2H。
(4)间接转移指令。
JMP @A+DPTR ;PC←(A)+(DPTR)
该指令转移的目的地址是累加器A和DPTR的内容之和。该指令常用在分支程序中,又称为分支指令。通常将DPTR作为目标转移地址的基地址,根据A中不同的值实现程序的多分支转移。
例如,A=10H,DPTR=2000H,指令JMP@A+DPTR执行后,PC=2010H。也就是说,程序转移到2012H地址单元去执行。如A=20H,则转移到2022H地址单元执行。
【例3-15】要求当A=00H时,程序散转到KEY0;当A=01H时,散转到KEYI等。
解:据题意程序如下。
CLR C ;清进位位
RLC A ;累加器内容乘2
MOV DPTR,#TABLE
JMP @A+DPTR
……
TABLE:AJMP KEY0
AJMP KEYl
AJMP KEY2
……
条件转移是指程序发生转移是有条件的,若指令中所规定的条件满足,则程序发生转移,若不满足指令所规定的条件,则程序顺序执行。
条件转移指令发生转移时,都是以相对寻址方式得到目标地址,指令的执行过程是先进行条件判断,后决定程序的走向。指令的转移范围非常有限,仅为-128~+127共256。
(1)累加器为零(非零)转移指令。
JZ rel ;若A=0则转移(PC←PC+2+rel),若A≠0程序顺序执行
JNZ rel ;若A≠0则转移(PC←PC+2+rel),若A=0程序顺序执行
(2)减1非零转移指令。
DJNZ Rn,rel ;Rn←Rn-1,若Rn≠0,则转移(PC←PC+2+rel),
;若Rn=0,则程序顺序执行
DJNZ dir,rel ;dir←(dir)-1,若(dir)≠0,则转移(PC←PC+3+rel),
;若(dir)=0,则程序顺序执行
说明:DJNZ Rn,rel是双字节指令,DJNZ dir,rel是3字节指令,所以在满足转移的条件后,前者的结果是PC←PC+2+rel,后者的结果是PC←PC+3+rel。
(3)两数不等转移指令。
CJNE A,dir,rel ;若A≠(dir),则转移(PC←PC+3+-rel),否则程序顺序执行
CJNE A,#data,rel ;若A≠#data,则转移(PC←PC+3+rel),否则程序顺序执行
CJNE@Ri,#data,rel ;若((Ri))≠#data,则转移(PC←PC+3+rel),否则程序顺序执行
说明:CJNE指令对标志C有影响。若第一操作数大于或等于第二操作数,则C=0,如指令CJNE A,dir,rel中A>(dir);若第一操作数小于第二操作数,则C=1,如指令CJNE A,dir,rel中A<(dir)。利用对C的判断,可使这几条指令实现两操作数相等与否的判断,还可完成两数大小的比较。
例如,R2=23H,执行CJNE R2,#34H,$+08H指令后,程序转移到本条CJNE指令的首地址($)加08H后的地址单元去执行。
(4)相对偏移量rel的求法。
在短转移和条件转移中,用偏移量rel和转移指令所处的地址值来计算转移的目的地址,rel是1字节补码值,如果rel是正数的补码,程序往前转移;如果rel是负数的补码,程序往回转移。
设本条转移指令的首地址为As,指令长Bn(2或3)字节,要转移到的地址为目的地址An,这三者之间的关系为:
rel=An-(As+Bn)
在已知源地址、目的地址和指令长度时,可由上述公式计算rel的大小。
【例3-16】一条短转移指令“SJMP rel”的首地址为2010H单元。求:①转移到目的地址为2020H单元的rel;②转移到目的地址为2000H单元的rel。
解:“SJMP rel”是双字节指令,故Bn=2,则由题意知,As=2010H。所以
① rel=(2020H-2010H-2)补=(0EH)补=0EH
② rel=(2000H-2010H-2)补=(-12H)补=0EEH
在①中,rel是正数的补码,所以实现了向前(地址增大)方向的转移;在②中,rel是负数的补码,所以实现了向回(地址减小)方向的转移。
【例3-17】已知内部RAM的M1和M2单元中各有一个无符号8位二进制数,试编程比较它们的大小,并把大数送到MAX单元。
解:相应程序如下。
MOV A,M1
CJNE A,M2,LOOP
LOOP : JNC LOOPl
MOV A,M2
LOOP1: MOV MAX,A
RET
子程序的调用和返回指令共有4条。
(1)调用子程序指令。
LCALL addrl6 ;PC←PC+3, SP←SP+1,(SP)←PC7~0
;SP←SP+1,(SP)←PC15~8,PC←addrl6
ACALL addr11 ;PC←PC+2, SP←SP+1,(SP)←PC7~0
;SP←SP+1,(SP)←PC15~8,PC10~0←addr11
在程序设计时,通常把一些重复的操作或运算编成子程序独立出来以供调用。原来的程序称为主程序,主程序可以调用子程序。实现这种调用功能的指令称为调用指令。子程序通过子程序返回指令来实现程序返回。
LCALL指令可调用在64KB范围内所指定的子程序,为长调用指令,addrl6是子程序入口地址。执行时,先将断口地址(调用指令下面一条指令的地址)压入堆栈,然后将子程序入口地址装入PC,CPU转而执行子程序。
上述第二条指令ACALL为短调用指令(双字节指令),其执行过程类似LCALL指令。但是,由于指令只提供了11位子程序入口地址,因此被调用的子程序入口地址必须与调用指令ACALL的下一条指令的第一个字节位于相同的2KB存储区内。设addr11为a10a9a8…a2a1a0,则指令ACALL addr11的机器码为a10a9a810001a7a6a5a4a3a2a1a0。
(2)返回指令。
RET ;PC15~8←(SP),SP←SP-1
;PC7~0←(SP),SP←SP-1
RETI ;PC15~8←(SP),SP←SP-1
;PC7~0←(SP),SP←SP-1
第一条指令是子程序返回指令。指令的功能是:将堆栈内的断口地址弹出送入PC,使CPU返回到原断口地址处继续执行原程序。
第二条指令是中断返回指令。这条指令将堆栈内的断口地址弹出送入PC,使CPU返回到原断口地址处执行原程序,并清除内部相应的中断状态寄存器(该寄存器由CPU响应中断时置位)的内容。它只能用于中断服务程序。
返回指令置于子程序或中断服务程序的末尾,表示子程序或中断服务程序的结束。
NOP ;PC←PC+1
这是一条单字节指令。该指令执行时,不作任何操作(即空操作),仅将程序计数器PC的内容加1,使CPU指向下一条指令继续执行程序。这条指令常用来产生一个机器周期的时间延迟。
程序转移类指令汇总表如表3-6所示。
表3-6 程序转移类指令汇总表
助 记 符 |
功能说明 |
字 节 数 |
振荡器周期 |
LJMP addrl6 |
长转移 |
3 |
24 |
AJMP addr11 |
绝对转移 |
2 |
24 |
SJMP rel |
短转移(相对偏移) |
2 |
24 |
JMP @A+DPTR |
相对DPTR的间接转移 |
1 |
24 |
JZ rel |
累加器为零则转移 |
2 |
24 |
JNZ rel |
累加器为非零则转移 |
2 |
24 |
CJNE A,direct,rel |
比较直接寻址字节和A不相等则转移 |
3 |
24 |
CJNE A,#data,rel |
比较立即数和A不相等则转移 |
3 |
24 |
CJNE Rn,#data,rel |
比较立即数和寄存器不相等则转移 |
3 |
24 |
CJNE @Ri,#data,rel |
比较立即数和间接寻址RAM不相等则转移 |
3 |
24 |
DJNZ Rn,rel |
寄存器减“1”不为零则转移 |
3 |
24 |
续上表
助 记 符 |
功能说明 |
字 节 数 |
振荡器周期 |
DJNZ direct,rel |
直接寻址字节减“1”不为零则转移 |
3 |
24 |
ACALL addr11 |
绝对调用子程序 |
2 |
24 |
LCALL addr16 |
长调用子程序 |
3 |
24 |
RET |
从子程序返回 |
1 |
24 |
RETI |
从中断返回 |
1 |
24 |
NOP |
空操作 |
1 |
12 |