《单片机原理及应用》 第3章 MCS-51单片机指令系统与程序设计

第 3 章 MCS - 51 单片机指令系统与程序设计

3.1 MCS - 51 指令系统与指令的执行

3.1.1 指令系统概述

MCS - 51 单片机的指令系统是一套规定好的指令集合,用于控制单片机完成各种操作。这些指令可以分为不同的类型,包括数据传送、算术运算、逻辑运算、控制转移和位操作等指令。指令系统是单片机软件编程的基础,熟悉指令系统对于编写高效、准确的程序至关重要。MCS - 51 指令系统具有丰富的指令种类,能够满足各种应用场景的需求,例如工业控制、智能仪器仪表等领域。

3.1.2 指令的时序

  1. 时钟周期:是单片机最基本的时间单位,由外接晶体振荡器的频率决定。例如,若外接晶振频率为 ( f_{osc} = 12 \text{MHz} ),则时钟周期 ( T_{clock} = \frac{1}{f_{osc}} = \frac{1}{12 \times 10^{6}} \text{s} = 0.0833 \text{μs} )。
  2. 状态周期:一个状态周期由两个时钟周期组成。即 ( T_{state} = 2T_{clock} )。
  3. 机器周期:MCS - 51 单片机的一个机器周期由 6 个状态周期组成,也就是 12 个时钟周期。所以,当晶振频率为 ( 12 \text{MHz} ) 时,机器周期 ( T_{machine} = 12T_{clock} = 1 \text{μs} )。
  4. 指令周期:执行一条指令所需要的时间,以机器周期为单位。不同类型的指令,其指令周期不同。例如,单字节单周期指令的执行时间为 1 个机器周期,双字节单周期指令同样为 1 个机器周期,而乘法和除法指令则需要 4 个机器周期。

3.1.3 指令的执行过程

  1. 取指令阶段:程序计数器(PC)中存放着当前要执行指令的地址。在取指令阶段,PC 的值被送到地址总线上,然后从程序存储器中读取该地址对应的指令代码,并将其送入指令寄存器(IR)。同时,PC 的值自动加 1,指向下一条指令的地址。
  2. 指令译码阶段:存放在指令寄存器中的指令代码被送到指令译码器,指令译码器对指令进行分析,识别出指令的操作码和操作数,确定该指令要执行的操作。
  3. 执行指令阶段:根据指令译码的结果,单片机内部的各个功能部件协同工作,完成指令所规定的操作。例如,若指令是加法运算,运算器会从相应的寄存器或存储单元中取出操作数,进行加法运算,并将结果存放到指定的寄存器或存储单元中。

3.2 符号指令的寻址方式

3.2.1 寄存器寻址

寄存器寻址是指操作数存放在寄存器中,指令中直接给出寄存器的名称。例如,指令 MOV A, R0,表示将寄存器 R0 中的内容传送到累加器 A 中。在 MCS - 51 单片机中,可用于寄存器寻址的寄存器有工作寄存器 R0 - R7、累加器 A、寄存器 B、程序状态字寄存器 PSW 等。这种寻址方式的优点是操作速度快,因为寄存器位于单片机内部,访问速度比访问存储器快。

3.2.2 立即寻址

立即寻址是指在指令中直接给出操作数。例如,指令 MOV A, #30H,其中 #30H 就是立即数,表示将十六进制数 30H 传送到累加器 A 中。立即数前面通常用 # 符号表示。立即寻址主要用于给寄存器或存储单元赋初值,其特点是操作数直接包含在指令中,执行速度较快。

3.2.3 直接寻址

直接寻址是指在指令中直接给出操作数的存储单元地址。例如,指令 MOV A, 30H,表示将内部数据存储器地址为 30H 的单元中的内容传送到累加器 A 中。直接寻址可以访问内部数据存储器的低 128 字节(地址范围 00H - 7FH)以及特殊功能寄存器(SFR)。这种寻址方式适用于对特定存储单元进行操作的情况。

3.2.4 寄存器间接寻址

寄存器间接寻址是指操作数的地址存放在寄存器中,指令中给出的是寄存器的名称。例如,指令 MOV A, @R0,表示将以寄存器 R0 的内容为地址的内部数据存储器单元中的内容传送到累加器 A 中。可用于寄存器间接寻址的寄存器有 R0、R1 和数据指针 DPTR。其中,R0 和 R1 用于访问内部数据存储器低 128 字节(地址范围 00H - 7FH),DPTR 用于访问外部数据存储器(64KB 地址空间)。寄存器间接寻址为访问数组、表格等数据结构提供了方便。

3.2.5 变址寻址

变址寻址是以程序计数器 PC 或数据指针 DPTR 作为基址寄存器,以累加器 A 作为变址寄存器,两者内容相加形成操作数的地址。例如,指令 MOVC A, @A + DPTR,表示以 DPTR 的内容为基地址,A 的内容为偏移量,将程序存储器中相应地址单元的内容传送到累加器 A 中。变址寻址常用于访问程序存储器中的表格数据,通过改变累加器 A 的值,可以灵活地访问表格中的不同元素。

3.2.6 相对寻址

相对寻址是在转移指令中使用的一种寻址方式。它以当前程序计数器 PC 的值为基准,加上指令中给出的相对偏移量,形成转移目标地址。例如,指令 SJMP rel,其中 rel 就是相对偏移量。执行该指令时,PC 当前值加上 rel 的值,得到的结果就是转移后的目标地址。相对寻址主要用于实现程序的短距离转移,通常在条件转移指令中使用,方便根据程序运行的条件跳转到不同的地址继续执行程序。

3.2.7 位寻址

位寻址是对内部数据存储器的位寻址区(20H - 2FH)和特殊功能寄存器中的可寻址位进行操作。例如,指令 SETB 20H.0,表示将内部数据存储器 20H 单元的第 0 位置 1。位寻址为处理逻辑判断和标志位操作提供了便利,在一些需要进行位控制的应用中非常有用,如工业控制中的开关量控制。

3.3 常用指令

3.3.1 数据传送类指令

  1. 通用数据传送指令
    • MOV:用于在寄存器、存储单元之间传送数据。例如,MOV A, R1 将寄存器 R1 的内容传送到累加器 A;MOV 30H, A 将累加器 A 的内容传送到内部数据存储器 30H 单元。
    • MOVX:用于单片机与外部数据存储器之间的数据传送。例如,MOVX A, @DPTR 从外部数据存储器中以 DPTR 为地址的单元读取数据到累加器 A;MOVX @DPTR, A 将累加器 A 的数据写入外部数据存储器以 DPTR 为地址的单元。
    • MOVC:用于从程序存储器中读取数据到累加器 A,常与变址寻址方式配合使用。如 MOVC A, @A + PCMOVC A, @A + DPTR
  2. 堆栈操作指令
    • PUSH:将数据压入堆栈。例如,PUSH ACC 将累加器 A 的内容压入堆栈,堆栈指针 SP 自动加 1。
    • POP:从堆栈中弹出数据。例如,POP ACC 从堆栈中弹出数据到累加器 A,堆栈指针 SP 自动减 1。
  3. 数据交换指令
    • XCH:字节交换指令。例如,XCH A, R2 将累加器 A 和寄存器 R2 的内容进行交换。
    • XCHD:半字节交换指令。例如,XCHD A, @R0 将累加器 A 的低 4 位和以 R0 内容为地址的内部数据存储器单元的低 4 位进行交换。

3.3.2 加减运算指令

  1. 加法指令
    • ADD:不带进位加法指令。例如,ADD A, R3 将累加器 A 的内容与寄存器 R3 的内容相加,结果存放在累加器 A 中,同时根据运算结果设置程序状态字寄存器 PSW 中的进位标志 CY、辅助进位标志 AC 和溢出标志 OV 等。
    • ADDC:带进位加法指令。例如,ADDC A, 30H 将累加器 A 的内容与内部数据存储器 30H 单元的内容以及进位标志 CY 相加,结果存放在累加器 A 中,并更新 PSW 中的标志位。
  2. 减法指令
    • SUBB:带借位减法指令。例如,SUBB A, R4 将累加器 A 的内容减去寄存器 R4 的内容以及借位标志 CY,结果存放在累加器 A 中,同时更新 PSW 中的标志位。由于 MCS - 51 单片机没有不带借位的减法指令,若要进行不带借位减法,需先将 CY 清零。
  3. 增量和减量指令
    • INC:增量指令。例如,INC A 将累加器 A 的内容加 1;INC 40H 将内部数据存储器 40H 单元的内容加 1。
    • DEC:减量指令。例如,DEC R5 将寄存器 R5 的内容减 1;DEC @R1 将以 R1 内容为地址的内部数据存储器单元的内容减 1。

3.3.3 逻辑运算及移位类指令

  1. 逻辑与指令
    • ANL:用于对两个操作数进行按位与操作。例如,ANL A, #0FH 将累加器 A 的内容与立即数 0FH 进行按位与操作,结果存放在累加器 A 中,常用于屏蔽某些位(将不需要的位清零)。
  2. 逻辑或指令
    • ORL:用于对两个操作数进行按位或操作。例如,ORL A, R6 将累加器 A 的内容与寄存器 R6 的内容进行按位或操作,结果存放在累加器 A 中,可用于置某些位为 1。
  3. 逻辑异或指令
    • XRL:用于对两个操作数进行按位异或操作。例如,XRL A, 50H 将累加器 A 的内容与内部数据存储器 50H 单元的内容进行按位异或操作,结果存放在累加器 A 中,常用于对某些位取反。
  4. 移位指令
    • RL:循环左移指令。例如,RL A 将累加器 A 的内容循环左移一位,最高位进入最低位和 CY。
    • RR:循环右移指令。例如,RR A 将累加器 A 的内容循环右移一位,最低位进入最高位和 CY。
    • RLC:带进位循环左移指令。例如,RLC A 将累加器 A 的内容连同 CY 一起循环左移一位,CY 进入最低位,A 的最高位进入 CY。
    • RRC:带进位循环右移指令。例如,RRC A 将累加器 A 的内容连同 CY 一起循环右移一位,CY 进入最高位,A 的最低位进入 CY。

3.3.4 位操作指令

  1. 位传送指令
    • MOV C, bit:将指定的位(bit)传送到进位标志 CY 中。例如,MOV C, 20H.3 将内部数据存储器 20H 单元的第 3 位传送到 CY 中。
    • MOV bit, C:将进位标志 CY 的值传送到指定的位(bit)。例如,MOV 30H.1, C 将 CY 的值传送到内部数据存储器 30H 单元的第 1 位。
  2. 位状态控制指令
    • CLR C:将进位标志 CY 清零。
    • CLR bit:将指定的位(bit)清零。例如,CLR 25H.2 将内部数据存储器 25H 单元的第 2 位清零。
    • SETB C:将进位标志 CY 置 1。
    • SETB bit:将指定的位(bit)置 1。例如,SETB 40H.0 将内部数据存储器 40H 单元的第 0 位置 1。
  3. 位逻辑运算指令
    • ANL C, bit:将进位标志 CY 与指定的位(bit)进行逻辑与操作,结果存放在 CY 中。
    • ANL C, /bit:将进位标志 CY 与指定位(bit)的反进行逻辑与操作,结果存放在 CY 中。
    • ORL C, bit:将进位标志 CY 与指定的位(bit)进行逻辑或操作,结果存放在 CY 中。
    • ORL C, /bit:将进位标志 CY 与指定位(bit)的反进行逻辑或操作,结果存放在 CY 中。
  4. 位条件转移指令
    • JC rel:若进位标志 CY 为 1,则程序转移到相对地址 rel 处执行;否则,顺序执行下一条指令。
    • JNC rel:若进位标志 CY 为 0,则程序转移到相对地址 rel 处执行;否则,顺序执行下一条指令。
    • JB bit, rel:若指定的位(bit)为 1,则程序转移到相对地址 rel 处执行;否则,顺序执行下一条指令。
    • JNB bit, rel:若指定的位(bit)为 0,则程序转移到相对地址 rel 处执行;否则,顺序执行下一条指令。
    • JBC bit, rel:若指定的位(bit)为 1,则将该位清零,并程序转移到相对地址 rel 处执行;否则,顺序执行下一条指令。

3.3.5 伪指令

  1. ORG(Origin):规定程序或数据块的起始地址。例如,ORG 0100H 表示从地址 0100H 开始存放程序或数据。
  2. END:标志源程序的结束,汇编程序遇到 END 后不再继续汇编。
  3. DB(Define Byte):定义字节数据。例如,DB 30H, 40H, 'A' 定义了三个字节的数据,分别为十六进制数 30H、40H 和字符 A 的 ASCII 码。
  4. DW(Define Word):定义字数据(16 位)。例如,DW 1234H 定义了一个 16 位的数据 1234H,在存储器中按高字节在前、低字节在后的顺序存放。
  5. EQU(Equate):给一个符号赋一个值或地址。例如,COUNT EQU 30H 将符号 COUNT 赋值为 30H,之后在程序中可以使用 COUNT 代替 30H。
  6. BIT:定义位地址符号。例如,FLAG BIT 20H.0 将内部数据存储器 20H 单元的第 0 位定义为符号 FLAG,在程序中可以使用 FLAG 来操作该位。

3.4 汇编语言程序设计方法

以下为你展示《单片机原理及应用》中 3.4 汇编语言程序设计方法里各类型程序设计的代码示例,并对每行代码进行注释:

3.4.1 顺序程序设计

ORG 0000H ; 程序起始地址设为 0000H
START:
    MOV A, #30H ; 将立即数 30H 传送到累加器 A
    MOV B, #20H ; 将立即数 20H 传送到寄存器 B
    ADD A, B ; 累加器 A 中的值与寄存器 B 中的值相加,结果存于 A
    MOV 40H, A ; 将累加器 A 的结果存到内部数据存储器 40H 单元
    SJMP $ ; 程序结束,原地踏步,$ 表示当前指令地址
END ; 汇编结束标志

3.4.2 分支程序设计

假设比较两个数大小,将较大的数存放到指定单元。

ORG 0000H ; 程序起始地址设为 0000H
START:
    MOV A, #30H ; 将立即数 30H 传送到累加器 A
    MOV B, #40H ; 将立即数 40H 传送到寄存器 B
    CJNE A, B, COMPARE ; 比较 A 和 B 的值,若不相等则跳转到 COMPARE 处执行
EQUAL:
    MOV 50H, A ; 若 A 和 B 相等,将 A 的值存到 50H 单元
    SJMP END_PROGRAM ; 跳转到程序结束处
COMPARE:
    JNC GREATER ; 如果 A >= B(无借位),跳转到 GREATER 处执行
    MOV 50H, B ; 若 A < B,将 B 的值存到 50H 单元
    SJMP END_PROGRAM ; 跳转到程序结束处
GREATER:
    MOV 50H, A ; 若 A >= B,将 A 的值存到 50H 单元
END_PROGRAM:
    SJMP $ ; 程序结束,原地踏步
END ; 汇编结束标志

3.4.3 循环程序设计

以累加 1 到 100 的和为例。

ORG 0000H ; 程序起始地址设为 0000H
START:
    MOV A, #00H ; 初始化累加器 A 为 0
    MOV R0, #01H ; 初始化寄存器 R0 为 1,用于计数
LOOP:
    ADD A, R0 ; 将 R0 的值加到累加器 A
    INC R0 ; R0 的值加 1
    CJNE R0, #65H, LOOP ; 比较 R0 是否等于 100(64H + 1 = 65H),若不等则继续循环
    MOV 40H, A ; 将累加结果存到内部数据存储器 40H 单元
    SJMP $ ; 程序结束,原地踏步
END ; 汇编结束标志

3.4.4 多重循环程序设计

以延时程序为例,通过双重循环实现较长时间的延时。

ORG 0000H ; 程序起始地址设为 0000H
START:
    MOV R1, #100 ; 外层循环计数器 R1 初始化为 100
OUTER_LOOP:
    MOV R2, #250 ; 内层循环计数器 R2 初始化为 250
INNER_LOOP:
    DJNZ R2, INNER_LOOP ; R2 减 1,若不为 0 则继续内层循环
    DJNZ R1, OUTER_LOOP ; R1 减 1,若不为 0 则继续外层循环
    SJMP $ ; 程序结束,原地踏步
END ; 汇编结束标志

3.4.5 子程序设计

设计一个简单的延时子程序,并在主程序中调用。

ORG 0000H ; 程序起始地址设为 0000H
START:
    ACALL DELAY ; 调用延时子程序
    SJMP $ ; 程序结束,原地踏步

; 延时子程序
DELAY:
    MOV R3, #250 ; 延时子程序中,初始化寄存器 R3 为 250
DELAY_LOOP:
    DJNZ R3, DELAY_LOOP ; R3 减 1,若不为 0 则继续循环
    RET ; 返回主程序
END ; 汇编结束标志

以上代码基于 MCS - 51 单片机汇编语言编写,不同单片机的指令集可能略有差异,实际应用中需根据具体单片机型号进行调整。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

请向我看齐

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值