通常情况下,程序的执行是按顺序进行的,这是由PC自动加1实现的。有时因任务要求,需要改变程序的执行顺序,这时就需要改变程序计数器PC中的内容,这种情况称作程序转移。控制转移类指令都能改变程序计数器PC的内容。
MCS-51系列单片机有比较丰富的控制转移指令,包括无条件转移指令、条件转移指令和子程序调用及返回指令,这类指令一般不影响标志位。
1.无条件转移指令
MCS-51系列单片机有4条无条件转移指令,提供了不同的转移范围和方式,可使程序无条件地转到指令所提供的地址上去。
(1)长转移指令
LJMP addr16 ;PC←addr16
该指令在操作数位置上提供了16位目的地址addr16,其功能是把指令中给出的16位的目的地址addr16送入程序计数器PC,使程序无条件转移到addr16处执行。16位地址可以寻址64KB,所以用这条可以转移到64KB程序存储器的任何位置,故称为“长转移”。长转移指令是三字节指令,依次是操作码、高8位地址和低8位地址。
(2)绝对转移指令
AJMP addr11 ;PC←(PC)+2,PC10~0←addr11
这是一条两字节指令,是2KB范围内的无条件转移指令。AJMP把MCS-51单片机的64KB程序存储器空间划分为32个区,每个区是2KB。转移的目标必须与AJMP下一条指令的第一个字节在同一个2KB范围内,即目标地址必须与AJMP下一条指令的地址的高5位地址码A15~A11相同,否则,将引起混乱。
绝对转移指令的执行分为两步:
第一步,取指令。此时PC自身加2指向下一条指令的起始地址(称为PC当前值)。
第二步,用指令中给出的11位地址替换PC当前值的低11位,PC高5位保持不变,形成新的PC地址——即转移的目的地址。
11位地址的范围为00000000000~11111111111,即可转移的范围是2KB。转移可以向前也可以向后,如图3-8所示。但要注意转移到的位置是要与PC+2的地址在同一个2KB区域,而不一定与AJMP指令的地址在同一个2KB区域。例如AJMP指令地址为1FFFH,加2以后为2001H,因此可以转移的区域为2000 H~27FFH的区域。
图3-8 AJMP指令的转移范围
【例3-4】 分析下面绝对转移指令的执行情况:
1234H:AJMP 0781H
解 在指令执行前,(PC)=1234H;取出该指令后,PC当前值=(PC)+2=1236H,指令执行过程就是用指令给出的11位地址11110000001B替换PC当前值的低11位,即新的PC值为1781H,所以指令执行的结果就是转移到1781H处执行新的程序。
应注意:只有转移的目的地址在2KB范围之内时,才可以使用AJMP指令,超出2KB范围,应使用长转移指令LJMP。
(3)短转移指令
SJMP rel ;PC←(PC)+2,PC←(PC)+rel
SJMP是无条件相对短转移指令,该指令为双字节指令,rel是相对转移的8位有符号偏移量,指令的执行分两步完成:
第一步,取指令。此时PC自身加2构成PC的当前值
第二步,将PC当前值与偏移量rel相加形成转移的目的地址。即
目的地址=(PC)+2+rel
rel是一个带符号的相对偏移量,其范围为-128~+127,负数表示向后转移,正数表示向前转移。
这条指令的优点是:指令给出的是相对转移地址,不具体指出地址值。这样,当程序地址发生变化时,只要相对地址不发生变化,该指令就不需要做任何改动。
通常,在用汇编语言编写程序时、在rel位置上直接以符号地址形式给出转移的目的地址,而由汇编程序在汇编过程中自动计算和填入偏移量,可以省去人工计算偏移量的工作。
(4)散转指令(又称变址寻址转移指令)
JMP @A+DPTR ;PC←(A)+(DPTR)
指令采用的是变址寻址方式,该指令的功能是把累加器A中的8位无符数与基址寄存器DPTR中的16位地址相加,所得的和作为目的地址送入PC。指令执行后不改变A和DPTR中的内容,也不影响任何标志位。
这条指令的特点是转移地址可以在程序运行中加以改变。例如,在DPTR中装入多分支转移指令表的首地址,而由累加器A中的内容来动态选择该时刻应该转向哪一条指令分支,实现由一条指令完成多分支转移的功能。
2.条件转移指令
条件转移指令是指当某种条件满足时,转移才进行;而条件不满足时,程序就按顺序往下执行。
条件转移指令有如下指令:
(1)累加器判零转移指令
这是一组以累加器A的内容是否为零作为判断条件的转移指令。JZ指令的功能是:累加器(A)=0则转移;否则就按顺序执行。JNZ指令的操作正好与之相反。
这两条指令都是两字节的相对转移指令,rel是8位的有符号数,为相对转移偏移量。与短转移指令中的rel一样,在编写源程序时,经常用标号来代替,只是在翻译成机器码时,才由汇编程序换算成8位相对地址。
(2)比较不相等转移指令
比较不相等转移指令共有4条,其差别只在于操作数的寻址方式不同。
该组指令在执行时首先对两个规定的操作数进行比较,然后根据比较的结果来决定是否发生转移,若两个操作数相等,程序按顺序往下执行;若两个操作数不相等,则进行转移。指令执行时,还要根据两个操作数的大小来设置进位标志Cy,若目的操作数大于、等于源操作数,则Cy=0;若目的操作数小于源操作数,则Cy=1;为进一步的分支转移创造条件。通常在该组指令之后,选用以Cy为条件的转移指令,则可以判别两个数的大小。(www.daowen.com)
在使用CJNE指令时应注意以下几点:
1)比较条件转移指令都是三字节指令,因此PC当前值=PC+3(PC是该指令所在地址),转移的目的地址应是PC加上3以后再加偏移量rel。
2)比较操作实际就是做减法操作,只是不保存减法所得到的差(即不改变两个操作数的内容),而将结果反映在标志位Cy上。
3)CJNE指令将参与比较的两个操作数当做无符号数看待并影响Cy标志。因此CJNE指令不能直接用于有符号数大小的比较。
若进行两个有符号数大小的比较,则应依据符号位和Cy位进行判别比较。
例如:根据A和立即数80 H比较的结果转移到标号NEXT,其转移的距离已经超过了256B,则可用以下指令来实现:
CJNZ与LJMP这两条指令的结合,可以实现在64KB范围内的条件转移。其中的SJMP NEXT2指令是在执行完两数相等的处理后,转移到继续执行的位置,以免也要去执行LJMP指令,造成程序逻辑上的混乱。
(3)减1不为零转移指令
这是一组把减1与条件转移两种功能结合在一起的指令。这组指令共有2条:
这组指令的操作是先将操作数Rn或direct内容减1,并保存结果,如果减1以后操作数不为零,则进行转移;如果减1以后操作数为零,则程序按顺序执行。
注意:第一条为2字节指令,第二条指令为3字节指令,这两条指令与DEC指令一样不影响PSW中的标志位。
这两条指令对于构成循环程序十分有用,可以指定任何一个工作寄存器或者内部RAM单元为计数器,对计数器赋以初值以后,就可以利用上述指令,若对计数器进行减1后不为零就进行循环操作,为0就结束循环,从而构成循环程序。
【例3-5】 编写程序,将内部RAM以DATA为起始地址的10个单元中的数据求和,并将结果送入SUM单元。设和不大于255。
解 对一组连续存放的数据进行操作时,一般都采用间接寻址,使用INC指令修改地址,可以使编程简单,利用减1条件转移指令很容易编成循环程序来完成10个数的相加。
以上介绍了MCS-51系列单片机中的各种条件转移指令 这些条件转移指令都是相。对转移指令,因此,转移的范围都是有限的。若要在大范围内实现条件转移,可将条件转移指令和长转移指令LJMP结合起来加以实现。
综上所述,可以看到条件转移指令的共同特点:
1)所有的条件转移指令都属于相对转移指令,转移范围相同,都在以PC当前值为基准的256B范围内(-128~+127);
2)计算转移地址的方法相同,即:转移地址=PC当前值+rel。
3.子程序调用及返回指令
在程序设计中,常常出现几个地方都需要进行功能完全相同的处理,如果重复编写这样的程序段,会使程序变得冗长而杂乱,对此,可以采用子程序,即把具有一定功能的程序段编写成子程序,通过主程序调用来使用它,这样不但减少了编程工作量,而且也缩短了程序的长度。
调用子程序的程序称之为主程序,主程序和子程序之间的调用关系可用图3-9表示。
图3-9 子程序调用示意图
从图3-9中可以看出,子程序调用会中断原有指令的执行顺序,转移到子程序的入口地址去执行子程序。与转移指令不同的是:子程序执行完毕后,要返回到原有程序被中断的位置,继续往下执行,而转移指令则不一定。因此,子程序调用指令必须具有将程序中断位置的地址保存起来的功能,断点都是在堆栈中加以保存,而堆栈的先入后出的存取方式恰好适合存放断点地址。
如果在子程序中还调用其他子程序,称为子程序嵌套;二层子程序嵌套过程如图3-10(a)所示。图3-10(b)为二层子程序调用后,堆栈中断点地址存放的情况。先存入断点地址1,程序转去执行子程序1,执行过程中又要调用子程序2。于是在堆栈中又存入断点地址2。存放时,先存地址低8位.后存地址高8位。从子程序返回时,先取出断点地址2,接着执行子程序1,然后取出断点地址1,继续执行主程序。
图3-10 子程序嵌套及断点地址存放
调用和返回构成了子程序调用的完整过程。为了实现这一过程.必须有子程序调用指令和返回指令。调用指令在主程序中使用,而返回指令则是子程序中的最后一条指令。
(1)子程序调用指令
MCS-51系列单片机共有两条子程序调用指令:
LCALL指令称为长调用指令,是三字节指令。指令的操作数部分给出了子程序的16位地址。该指令功能是:先将PC加3,指向下条指令地址(即断点地址),然后将断点地址压入堆栈,再把指令中的16位子程序入口地址装入PC,以使程序转到子程序入口处。长调用指令可调用存放在64KB程序存储器任意位置的子程序,即调用范围为64KB。
ACALL指令称为绝对调用指令,是两个字节的指令。绝对调用指令的功能是:先将PC加2,指向下条指令地址(即断点地址),然后将断点地址压入堆栈,再把指令中提供的子程序低11位入口地址装入PC的低11位上,PC的高5位保持不变,以使程序转移到对应的子程序入口处。子程序调用地址是由子程序的低11位地址与PC的高5位合并组成,所以调用范围为2KB。
使用时应注意:ACAIL指令所调用的子程序的入口地址必须在ACALL指令之后的2KB区域内。若把64KB内存空间以2KB字节为一页,共可分为32个页面,所调用的子程序应该与ACAIL下面的指令在同一个页面之内,即它们的地址高5位a15~a11应该相同。也就是说,在执行ACAIL指令时,子程序入口地址的高5位是不能任意设定的,只能由ACALL下面指令所在的位置来决定。因此,要注意ACALL指令和所调用的子程序的入口地址不能相距太远,否则就不能实现正确的调用。例如,当ACALL指令所在地址为2300H时,其高5位是00100,因此,可调用的范围是2300 H~27FFH。
(2)返回指令
RET指令被称为子程序返回指令,放在子程序的末尾。其功能是从堆栈中自动取出断点地址送入程序计数器PC,使程序返回到主程序断点处继续往下执行。
RETI指令是中断返回指令,放在中断服务子程序的末尾。其功能也是从堆栈中自动取出断点地址送入程序计数器PC,使程序返回到主程序断点处继续往下执行。同时还清除中断响应时被置位的优先级状态触发器,以告之中断系统已经结束中断服务程序的执行,恢复中断逻辑以接受新的中断请求。
使用时应注意:
1)RET和RETI不能互换使用;
2)在子程序或中断服务子程序中,PUSH指令和POP指令必须成对使用,否则,不能正确返回主程序断点位置。
4.空操作指令
NOP ;PC←(PC)+1
这是一条单字节指令。该指令不产生任何操作,只是使PC的内容加1,然后继续执行下一条指令,它又是一条单周期指令,执行时在时间上消耗一个机器周期,因此,NOP指令常用来实现等待或延时。
免责声明:以上内容源自网络,版权归原作者所有,如有侵犯您的原创版权请告知,我们将尽快删除相关内容。