3.5.1 无条件转移指令

这类指令的功能是程序无条件地转移到各自指定的目标地址去执行,不同的指令形成的目标地址不同。
1. 短转移指令SJMP
SJMP指令用于实现短转移。它是无条件转移指令,可以使程序跳转到当前程序计数器PC±127范围内的目标地址。
SJMP指令的主要格式:
示例程序:
SJMP指令执行过程中不影响任何标志位。相对偏移量rel的计算是由汇编程序自动完成的,程序员只需要指定目标地址的标号即可。
2.绝对转移指令AJMP
AJMP指令用于实现绝对转移。它也是无条件转移指令,可以在当前程序段内(2K范围内)实现转移。
AJMP指令的主要格式:
AJMP指令的目标地址合成过程如下:
- AJMP是一个2字节指令,其机器码格式为:[a10 0001 0xxx] [a7 a6 a5 a4 a3 a2 a1 a0]
- 其中xxx为页内地址的高3位(a10 a9 a8),第二个字节为页内地址的低8位
目标地址的合成规则:
- 保持PC的高5位不变(PC15~PC11)
- 用AJMP指令中的11位地址码(addr11)替换PC的低11位(PC10~PC0)
这就意味着:
- AJMP只能在2K字节范围内跳转(2^11 = 2048字节)
- 跳转目标地址必须与当前指令在同一个2K字节段内
举例说明:如果当前PC = 0x2567,执行AJMP 0x0123时:
- 保持高5位0x2不变
- 低11位替换为0x123
- 最终的目标地址为0x2123
示例程序:
与SJMP类似,AJMP指令执行过程中也不影响任何标志位。目标地址的计算由汇编程序完成,程序员只需指定目标地址或标号即可。
3.长转移指令LJMP
LJMP指令用于实现长转移。它是无条件转移指令,可以跳转到64K程序存储空间的任意地址。
LJMP指令的主要格式:
特点说明:
- LJMP是一个3字节指令,第一个字节是操作码,后两个字节是16位目标地址
- 可以跳转到整个64K程序存储空间的任意地址,没有距离限制
- 执行过程中不影响任何标志位
示例程序:
与前面介绍的SJMP和AJMP相比,LJMP的跳转范围最大,但指令长度也最长,执行时间也最长。在实际编程中,应根据跳转距离的需求选择合适的转移指令。
4. 间接转移指令JMP
JMP指令用于实现间接转移。它是无条件转移指令,其目标地址是由累加器A和数据指针DPTR的内容动态确定的。
JMP指令有两种主要格式:
特点说明:
- 目标地址是动态计算的,可以在程序运行时根据实际情况确定跳转位置
- 常用于实现跳转表(程序分支表)功能
- 执行过程中不影响任何标志位
示例程序(使用跳转表):
在这个例子中,通过R0中的值(0-3)来选择要执行的子程序。程序先将DPTR指向跳转表,然后根据R0的值计算偏移量,最后使用JMP @A+DPTR跳转到相应的子程序。
3.5.2 条件转移指令
1. 累加器判零转移指令
累加器判零转移指令包括JZ和JNZ两条指令,它们根据累加器A的内容是否为零来进行条件转移。
满足条件时,相当于SJMP;不满足条件时,程序顺序向下执行
JZ(Jump if Zero)指令
当累加器A的内容为0时,程序转移到指定地址;若不为0,则继续执行下一条指令。
指令格式:
示例程序:
JNZ(Jump if Not Zero)指令
当累加器A的内容不为0时,程序转移到指定地址;若为0,则继续执行下一条指令。
指令格式:
示例程序:
这两条指令都是短转移指令,转移范围为PC±127。执行过程中不影响任何标志位。
2.数值比较转移指令CJNE
CJNE(Compare and Jump if Not Equal)指令用于比较两个操作数,如果不相等则转移到指定地址。这是一个功能强大的条件转移指令,可以用于多种比较场景。
CJNE指令有以下几种格式:
特点说明:
- 比较结果处理:若两操作数不相等,则转移到rel指定的地址;若相等,则执行下一条指令
- 标志位影响:比较后会根据第一个操作数是否小于第二个操作数来设置CY标志位
- 若第一个操作数小于第二个操作数,则CY = 1
- 若第一个操作数大于或等于第二个操作数,则CY = 0
- 这样通过检查CY标志位,就可以进一步判断两个操作数的大小关系。
- 转移范围:属于短转移指令,转移范围为PC±127
示例程序1(判断数值大小):
示例程序2(查找数组中的值):
3.5.3 循环转移指令DJNZ
DJNZ(Decrement and Jump if Not Zero)指令是一个专门用于实现循环的条件转移指令。它将指定的字节减1,如果结果不为0则转移到指定地址。
DJNZ指令有两种格式:
特点说明:
- 操作过程:先将操作数减1,然后判断结果是否为0
- 转移条件:若结果不为0,则转移到rel指定的地址;若为0,则执行下一条指令
- 转移范围:属于短转移指令,转移范围为PC±127
- 标志位影响:执行过程中不影响任何标志位
示例程序1(简单循环):
示例程序2(嵌套循环):
DJNZ指令是实现循环结构最常用的指令之一,它将减1操作和条件跳转合并为一条指令,使代码更加简洁高效。
3.5.4 子程序调用指令
子程序调用指令用于调用子程序,主要包括ACALL和LCALL两种指令。这些指令在执行时会将当前程序计数器PC的内容保存到堆栈中,然后跳转到子程序的起始地址执行。
1. ACALL(Absolute Call)指令
ACALL指令用于调用2K程序存储空间内的子程序。它是一个绝对地址调用指令。
指令格式:
ACALL的机器码格式与AJMP相同。合成目标地址的方式也相同:
- 使用当前PC的高5位和指令中的11位地址码构成16位目标地址
- 只能在当前2K地址空间内调用子程序
这就是为什么ACALL也被称为"页内调用指令"。
示例程序:
2. LCALL(Long Call)指令
LCALL指令用于调用64K程序存储空间内的任意地址的子程序。它是一个长地址调用指令。
指令格式:
示例程序:
特点说明:
- 堆栈操作:执行调用指令时,会自动将PC内容保存到堆栈中
- 返回方式:子程序通过RET指令返回到主程序继续执行
- 地址范围:ACALL限于2K范围内,LCALL可达64K范围内任意地址
- 标志位影响:两种调用指令都不影响任何标志位
3.5.5 返回指令
返回指令用于从子程序或中断服务程序返回到主程序继续执行。主要包括RET和RETI两种指令。
1. RET(Return)指令
RET指令用于从子程序返回到主程序。执行时,它会从堆栈中取出之前保存的程序计数器PC的值,使程序转到该地址继续执行。
指令格式:
示例程序:
2. RETI(Return from Interrupt)指令
RETI指令用于从中断服务程序返回到主程序。除了恢复PC值外,还会恢复中断系统的现场。
指令格式:
示例程序:
特点说明:
- 堆栈操作:两种返回指令都会从堆栈中弹出返回地址
- 中断系统:RETI会同时恢复中断系统的状态,而RET不会
- 使用场合:RET用于普通子程序返回,RETI专门用于中断服务程序返回
- 标志位影响:两种返回指令都不影响任何标志位
3.5.6 空操作指令NOP
NOP(No Operation)指令是一个空操作指令,执行时不进行任何操作,仅消耗一个机器周期。
指令格式:
主要用途:
- 延时目的:需要精确延时时可以使用NOP指令
- 程序调试:可以用NOP替换其他指令进行程序调试
- 指令对齐:在需要时用于填充和对齐程序代码
示例程序:
特点说明:
- 执行时间:消耗1个机器周期
- 标志位影响:不影响任何标志位
- 机器码长度:占用1个字节的程序存储空间