3.1 指令格式与符号意义
3.1.1 指令格式
51单片机的指令格式由操作码和操作数两部分组成,操作码指示计算机执行什么操作,操作数指出参与操作的数据来源和操作结果存放的位置。
[标号:] 操作码 [操作数1][,操作数2][,操作数3] [;注释]
- 标号:是用户定义的符号,表示该指令在存储器中的地址,以字母开头,后跟字母、数字或下划线,以冒号结尾。
- 操作码:是指令的核心部分,用助记符表示,规定了指令的操作功能。
- 操作数:是指令执行的对象,根据指令的不同,操作数可以是0个、1个、2个或3个。
- 注释:是为了提高程序的可读性而添加的说明文字,以分号开头。
3.1.2 常用符号
在51单片机指令系统中,常用的符号有以下几种:
| 符号 | 含义 |
|---|---|
| Rn | 当前选中的工作寄存器组中的寄存器R0~R7 |
| direct | 8位内部数据存储器单元的地址,可以是内部RAM的单元地址(00H~7FH)或SFR的地址(80H~FFH) |
| #data | 8位立即数,即包含在指令中的8位常数 |
| #data16 | 16位立即数,即包含在指令中的16位常数 |
| addr16 | 16位目的地址,用于LCALL和LJMP指令,可指向64KB程序存储器地址空间的任何地方 |
| addr11 | 11位目的地址,用于ACALL和AJMP指令,转向地址必须与下一条指令的第一个字节在同一个2KB程序存储器地址空间内 |
| rel | 8位带符号的偏移量字节,用于相对转移指令,范围为-128~+127 |
| bit | 内部RAM或SFR中的直接寻址位 |
| @ | 间接寻址寄存器或基址寄存器的前缀 |
| / | 位操作数的取反操作前缀 |
| () | 表示括号内的内容为操作数的地址,该地址中的内容为操作数 |
| → | 表示数据的传送方向,将箭头左边的内容传送到箭头右边的单元中 |
3.2 寻址方式
51单片机有7种寻址方式,分别是立即寻址、直接寻址、寄存器寻址、寄存器间接寻址、变址寻址、相对寻址和位寻址。
立即寻址
操作数直接包含在指令中,作为指令的一部分存放在程序存储器中。立即数前面必须加"#"号作为前缀。
MOV A, #30H ; 将立即数30H传送到累加器A中
直接寻址
操作数的地址直接在指令中给出,可以访问内部RAM的低128B单元以及所有的特殊功能寄存器(SFR)。
MOV A, 30H ; 将内部RAM地址为30H的单元中的内容传送到累加器A中
寄存器寻址
操作数存放在寄存器中,指令中给出的是寄存器名。可以访问选定的工作寄存器组中的R0~R7、累加器A、通用寄存器B、数据指针DPTR等。
MOV A, R0 ; 将工作寄存器R0中的内容传送到累加器A中
寄存器间接寻址
操作数的地址存放在寄存器中,在寄存器名前加"@"符号表示间接寻址。可以访问内部RAM和外部RAM。
MOV R0, #30H
MOV A, @R0 ; 将R0所指向的内部RAM单元(30H)中的内容传送到累加器A中
变址寻址
以基址寄存器(DPTR或PC)的内容为基地址,以变址寄存器(A)的内容为偏移量,将两者相加形成的16位地址作为操作数的地址。主要用于访问程序存储器中的常数表格。
MOV DPTR, #1000H
MOV A, #05H
MOVC A, @A+DPTR ; 将程序存储器中地址为1005H单元中的内容传送到累加器A中
相对寻址
以当前程序计数器PC的内容为基地址,加上指令中给出的相对偏移量rel形成新的PC值,从而实现程序的转移。rel是一个带符号的8位二进制数,范围为-128~+127。
SJMP 08H ; 相对转移指令,转移的目标地址=当前PC值+2+08H
位寻址
对内部RAM的位寻址区(20H~2FH)和某些可位寻址的特殊功能寄存器进行位操作时的寻址方式。位寻址的位地址与直接寻址的字节地址形式上完全一样,主要由操作码来区分。
SETB 20H ; 将内部RAM位寻址区的20H位置1,即内部RAM 24H单元的D0位
要点提示
寻址方式是指指令中寻找操作数或操作数所在地址的方式。不同的寻址方式有不同的应用场景,选择合适的寻址方式可以提高程序的效率和灵活性。
3.3 数据传送类指令
数据传送类指令是最基本、最常用的一类指令,用于在单片机内部各功能部件之间以及单片机与外部设备之间进行数据的传送。数据传送类指令一般不影响标志位,只有堆栈操作可以直接修改程序状态字PSW。
内部RAM数据传送指令
| 指令 | 功能 | 字节数 | 周期数 |
|---|---|---|---|
| MOV A, Rn | A ← Rn | 1 | 1 |
| MOV A, direct | A ← (direct) | 2 | 1 |
| MOV A, @Ri | A ← (Ri) | 1 | 1 |
| MOV A, #data | A ← #data | 2 | 1 |
| MOV Rn, A | Rn ← A | 1 | 1 |
| MOV Rn, direct | Rn ← (direct) | 2 | 2 |
| MOV Rn, #data | Rn ← #data | 2 | 1 |
| MOV direct, A | (direct) ← A | 2 | 1 |
| MOV direct, Rn | (direct) ← Rn | 2 | 2 |
| MOV direct, direct | (direct) ← (direct) | 3 | 2 |
| MOV direct, @Ri | (direct) ← (Ri) | 2 | 2 |
| MOV direct, #data | (direct) ← #data | 3 | 2 |
| MOV @Ri, A | (Ri) ← A | 1 | 1 |
| MOV @Ri, direct | (Ri) ← (direct) | 2 | 2 |
| MOV @Ri, #data | (Ri) ← #data | 2 | 1 |
外部RAM数据传送指令
| 指令 | 功能 |
|---|---|
| MOVX A, @DPTR | A ← (DPTR),读取外部RAM |
| MOVX @DPTR, A | (DPTR) ← A,写入外部RAM |
| MOVX A, @Ri | A ← (Ri),读取外部RAM低256字节 |
| MOVX @Ri, A | (Ri) ← A,写入外部RAM低256字节 |
程序存储器数据传送指令
| 指令 | 功能 |
|---|---|
| MOVC A, @A+DPTR | A ← (A+DPTR),读取程序存储器 |
| MOVC A, @A+PC | A ← (A+PC),读取程序存储器 |
堆栈操作指令
| 指令 | 功能 | 字节数 | 周期数 |
|---|---|---|---|
| PUSH direct | 将直接地址单元中的内容压入堆栈 | 2 | 2 |
| POP direct | 将堆栈顶部的内容弹出到直接地址单元 | 2 | 2 |
数据交换指令
| 指令 | 功能 | 字节数 | 周期数 |
|---|---|---|---|
| XCH A, Rn | 将累加器A的内容与工作寄存器Rn的内容互换 | 1 | 1 |
| XCH A, direct | 将累加器A的内容与直接地址单元中的内容互换 | 2 | 1 |
| XCH A, @Ri | 将累加器A的内容与Ri所指向的内部RAM单元中的内容互换 | 1 | 1 |
| XCHD A, @Ri | 将累加器A的低4位与Ri所指向的内部RAM单元中的低4位互换,高4位不变 | 1 | 1 |
| SWAP A | 将累加器A的高4位与低4位互换 | 1 | 1 |
数据传送指令特点
数据传送指令的一般格式为:MOV 目的操作数, 源操作数。其功能是将源操作数的内容传送到目的操作数中,源操作数的内容不变。
3.4 算术运算类指令
算术运算类指令用于实现加、减、乘、除等算术运算,这类指令大多数会对程序状态字PSW中的进位标志CY、辅助进位标志AC、溢出标志OV和奇偶标志P产生影响。
加法指令
| 指令 | 功能 | 影响标志 |
|---|---|---|
| ADD A, Rn | A ← A + Rn | CY, AC, OV, P |
| ADD A, direct | A ← A + (direct) | CY, AC, OV, P |
| ADD A, @Ri | A ← A + (Ri) | CY, AC, OV, P |
| ADD A, #data | A ← A + #data | CY, AC, OV, P |
| ADDC A, Rn | A ← A + Rn + CY | CY, AC, OV, P |
| ADDC A, direct | A ← A + (direct) + CY | CY, AC, OV, P |
| ADDC A, @Ri | A ← A + (Ri) + CY | CY, AC, OV, P |
| ADDC A, #data | A ← A + #data + CY | CY, AC, OV, P |
减法指令
| 指令 | 功能 | 影响标志 |
|---|---|---|
| SUBB A, Rn | A ← A - Rn - CY | CY, AC, OV, P |
| SUBB A, direct | A ← A - (direct) - CY | CY, AC, OV, P |
| SUBB A, @Ri | A ← A - (Ri) - CY | CY, AC, OV, P |
| SUBB A, #data | A ← A - #data - CY | CY, AC, OV, P |
乘法和除法指令
| 指令 | 功能 | 影响标志 | 周期数 |
|---|---|---|---|
| MUL AB | A×B → BA,结果的高8位存放在B中,低8位存放在A中 | OV, P | 4 |
| DIV AB | A÷B → A(商), B(余数),商存放在A中,余数存放在B中 | OV, P | 4 |
加1和减1指令
| 指令 | 功能 | 字节数 | 周期数 |
|---|---|---|---|
| INC A | A ← A + 1 | 1 | 1 |
| INC Rn | Rn ← Rn + 1 | 1 | 1 |
| INC direct | (direct) ← (direct) + 1 | 2 | 1 |
| INC @Ri | (Ri) ← (Ri) + 1 | 1 | 1 |
| INC DPTR | DPTR ← DPTR + 1 | 1 | 2 |
| DEC A | A ← A - 1 | 1 | 1 |
| DEC Rn | Rn ← Rn - 1 | 1 | 1 |
| DEC direct | (direct) ← (direct) - 1 | 2 | 1 |
| DEC @Ri | (Ri) ← (Ri) - 1 | 1 | 1 |
注意事项
51单片机没有不带借位的减法指令,若要进行不带借位的减法运算,必须先将CY清零,然后再使用SUBB指令。
3.5 逻辑运算类指令
逻辑运算类指令用于实现逻辑与、逻辑或、逻辑异或、逻辑非等逻辑运算,以及循环移位操作。这类指令一般不影响标志位,只有带进位循环移位指令会影响CY标志。
逻辑与指令
| 指令 | 功能 |
|---|---|
| ANL A, Rn | A ← A ∧ Rn |
| ANL A, direct | A ← A ∧ (direct) |
| ANL A, @Ri | A ← A ∧ (Ri) |
| ANL A, #data | A ← A ∧ #data |
| ANL direct, A | (direct) ← (direct) ∧ A |
| ANL direct, #data | (direct) ← (direct) ∧ #data |
逻辑或指令
| 指令 | 功能 |
|---|---|
| ORL A, Rn | A ← A ∨ Rn |
| ORL A, direct | A ← A ∨ (direct) |
| ORL A, @Ri | A ← A ∨ (Ri) |
| ORL A, #data | A ← A ∨ #data |
| ORL direct, A | (direct) ← (direct) ∨ A |
| ORL direct, #data | (direct) ← (direct) ∨ #data |
逻辑异或指令
| 指令 | 功能 | 字节数 | 周期数 |
|---|---|---|---|
| XRL A, Rn | A ← A ⊻ Rn | 1 | 1 |
| XRL A, direct | A ← A ⊻ (direct) | 2 | 1 |
| XRL A, @Ri | A ← A ⊻ (Ri) | 1 | 1 |
| XRL A, #data | A ← A ⊻ #data | 2 | 1 |
| XRL direct, A | (direct) ← (direct) ⊻ A | 2 | 1 |
| XRL direct, #data | (direct) ← (direct) ⊻ #data | 3 | 2 |
循环移位指令
| 指令 | 功能 | 字节数 | 周期数 |
|---|---|---|---|
| RL A | 累加器A的内容循环左移一位 | 1 | 1 |
| RLC A | 累加器A的内容带进位标志CY循环左移一位 | 1 | 1 |
| RR A | 累加器A的内容循环右移一位 | 1 | 1 |
| RRC A | 累加器A的内容带进位标志CY循环右移一位 | 1 | 1 |
清零和取反指令
| 指令 | 功能 | 字节数 | 周期数 |
|---|---|---|---|
| CLR A | 将累加器A清零 | 1 | 1 |
| CPL A | 将累加器A的内容按位取反 | 1 | 1 |
逻辑运算应用
逻辑与指令常用于将某些位清零(屏蔽),逻辑或指令常用于将某些位置1,逻辑异或指令常用于将某些位取反。
3.6 控制转移类指令
控制转移类指令用于改变程序的执行顺序,实现程序的分支、循环和调用等功能。这类指令包括无条件转移指令、条件转移指令、子程序调用和返回指令以及空操作指令。
无条件转移指令
| 指令 | 功能 | 转移范围 | 字节数 | 周期数 |
|---|---|---|---|---|
| AJMP addr11 | 绝对转移,PC ← addr11 | 2KB范围内 | 2 | 2 |
| LJMP addr16 | 长转移,PC ← addr16 | 64KB范围内 | 3 | 2 |
| SJMP rel | 相对转移,PC ← PC + 2 + rel | -128~+127范围内 | 2 | 2 |
| JMP @A+DPTR | 间接转移,PC ← A + DPTR | 64KB范围内 | 1 | 2 |
条件转移指令
| 指令 | 功能 | 转移条件 | 字节数 |
|---|---|---|---|
| JZ rel | 累加器A为零则转移 | A = 0 | 2 |
| JNZ rel | 累加器A不为零则转移 | A ≠ 0 | 2 |
| CJNE A, direct, rel | 累加器A与直接地址单元内容不等则转移 | A ≠ (direct) | 3 |
| CJNE A, #data, rel | 累加器A与立即数不等则转移 | A ≠ #data | 3 |
| CJNE Rn, #data, rel | 工作寄存器Rn与立即数不等则转移 | Rn ≠ #data | 3 |
| CJNE @Ri, #data, rel | 间接寻址单元内容与立即数不等则转移 | (Ri) ≠ #data | 3 |
| DJNZ Rn, rel | 工作寄存器Rn减1不为零则转移 | Rn - 1 ≠ 0 | 2 |
| DJNZ direct, rel | 直接地址单元内容减1不为零则转移 | (direct) - 1 ≠ 0 | 3 |
子程序调用和返回指令
| 指令 | 功能 | 字节数 | 周期数 |
|---|---|---|---|
| ACALL addr11 | 绝对调用,调用2KB范围内的子程序 | 2 | 2 |
| LCALL addr16 | 长调用,调用64KB范围内的子程序 | 3 | 2 |
| RET | 子程序返回 | 1 | 2 |
| RETI | 中断返回 | 1 | 2 |
要点提示
DJNZ指令常用于实现循环控制,CJNE指令常用于实现条件判断。RET和RETI指令的区别在于RETI指令除了返回断点地址外,还会清除中断优先级状态,以便响应其他中断。
3.7 位操作类指令
位操作类指令是51单片机的一个重要特色,它可以直接对内部RAM中的位寻址区和特殊功能寄存器中的可位寻址位进行操作,包括位的传送、置位、清零、取反以及位条件转移等操作。
位传送指令
| 指令 | 功能 | 字节数 | 周期数 |
|---|---|---|---|
| MOV C, bit | CY ← bit | 2 | 1 |
| MOV bit, C | bit ← CY | 2 | 2 |
位置位和清零指令
| 指令 | 功能 | 字节数 | 周期数 |
|---|---|---|---|
| SETB C | CY ← 1 | 1 | 1 |
| SETB bit | bit ← 1 | 2 | 1 |
| CLR C | CY ← 0 | 1 | 1 |
| CLR bit | bit ← 0 | 2 | 1 |
位逻辑运算指令
| 指令 | 功能 | 字节数 | 周期数 |
|---|---|---|---|
| ANL C, bit | CY ← CY ∧ bit | 2 | 2 |
| ANL C, /bit | CY ← CY ∧ /bit | 2 | 2 |
| ORL C, bit | CY ← CY ∨ bit | 2 | 2 |
| ORL C, /bit | CY ← CY ∨ /bit | 2 | 2 |
| CPL C | CY ← /CY | 1 | 1 |
位条件转移指令
| 指令 | 功能 | 转移条件 | 字节数 |
|---|---|---|---|
| JC rel | 进位标志CY为1则转移 | CY = 1 | 2 |
| JNC rel | 进位标志CY为0则转移 | CY = 0 | 2 |
| JB bit, rel | 直接寻址位为1则转移 | bit = 1 | 3 |
| JNB bit, rel | 直接寻址位为0则转移 | bit = 0 | 3 |
| JBC bit, rel | 直接寻址位为1则转移,并将该位清零 | bit = 1 | 3 |
位操作优势
位操作指令可以直接对单个位进行操作,非常适合用于控制系统的开关控制、状态检测等应用场景,大大提高了程序的效率和灵活性。
3.8 伪指令
伪指令不是真正的指令,而是汇编语言程序中用于指示汇编程序如何进行汇编的命令。伪指令不产生机器代码,只在汇编过程中起作用。
ORG
用于指定程序或数据在存储器中的起始地址。
ORG 0000H ; 程序从0000H地址开始存放
END
用于指示汇编程序的结束,放在源程序的最后。
END ; 源程序结束
EQU
用于给符号名赋值,赋值后的符号名可以在程序中使用。
COUNT EQU 10 ; COUNT的值为10
DATA
用于定义数据字节,将数据存放在指定的存储单元中。
TAB: DATA 30H, 31H, 32H ; 定义数据表
DB
用于定义字节常数或字符串,从当前地址开始依次存放。
TAB: DB 'A', 'B', 'C' ; 定义字符串
DW
用于定义字常数(16位数据),从当前地址开始依次存放。
TAB: DW 1234H, 5678H ; 定义16位数据表
BIT
用于定义位地址符号,将位地址赋值给符号名。
FLAG BIT 20H ; FLAG代表位地址20H
DS
用于定义存储空间,保留指定数量的字节单元。
BUF: DS 10 ; 保留10个字节单元
伪指令特点
伪指令不产生机器代码,只在汇编过程中起作用。合理使用伪指令可以使程序更加清晰、易于维护,并提高程序的可移植性。
3.9 本章总结
本章详细介绍了51单片机的指令系统,包括指令格式、寻址方式、各类指令的功能和使用方法,以及伪指令的应用。掌握指令系统是进行单片机程序设计的基础。
核心要点
- 掌握7种寻址方式的特点和应用场景
- 熟练使用数据传送类指令进行数据操作
- 理解算术运算类指令对标志位的影响
- 掌握逻辑运算类指令的位操作应用
- 熟练使用控制转移类指令实现程序分支
- 掌握位操作类指令的位控制应用
学习建议
- 通过编写简单程序加深对指令的理解
- 注意指令的字节数和执行周期数
- 理解不同寻址方式的适用范围
- 掌握伪指令的使用方法
- 结合实际应用场景选择合适的指令
- 多做练习,熟练掌握各类指令
3.10 课后练习题
1 填空题
1. 51单片机指令系统共有____条指令,按字节数可分为单字节、双字节和____字节指令。
2. 51单片机的寻址方式共有____种,分别是立即寻址、直接寻址、寄存器寻址、寄存器间接寻址、变址寻址、相对寻址和____。
3. MOV A, #30H 指令中,源操作数采用的是____寻址方式,目的操作数采用的是____寻址方式。
4. 数据传送类指令中,____指令用于将累加器A与外部RAM进行数据交换。
5. ADD A, R0 指令执行后,若A=0FFH,R0=01H,则进位标志CY=____,累加器A=____。
6. 逻辑与指令ANL用于对两个操作数进行____运算,逻辑或指令ORL用于进行____运算。
7. 控制转移类指令中,LJMP是____转移指令,跳转范围是____KB。
8. 位操作类指令中,SETB P1.0 的功能是将P1口第0位置____,CLR ACC.7 的功能是将累加器第7位清零。
9. DJNZ Rn, rel 指令的功能是先将寄存器Rn的内容____,若结果不为0则转移到目标地址。
10. 伪指令ORG的作用是指定程序或数据在____中的起始地址。
2 单选题
1. 以下哪种寻址方式的操作数在指令中直接给出?
A. 直接寻址 B. 立即寻址 C. 寄存器寻址 D. 寄存器间接寻址
2. MOV A, @R0 指令中,源操作数的寻址方式是?
A. 直接寻址 B. 寄存器寻址 C. 寄存器间接寻址 D. 变址寻址
3. 执行 MOVX A, @DPTR 指令时,数据传输的方向是?
A. 从A到外部RAM B. 从外部RAM到A C. 从A到内部RAM D. 从内部RAM到A
4. ADDC A, R1 指令执行时,会将以下哪个标志位的值加入运算?
A. AC B. CY C. OV D. P
5. 执行 INC DPTR 指令后,DPTR的值会?
A. 减1 B. 加1 C. 清零 D. 不变
6. RL A 指令的功能是将累加器A的内容?
A. 循环右移一位 B. 循环左移一位 C. 带进位循环右移 D. 带进位循环左移
7. SJMP 指令的跳转范围是?
A. -128~+127 B. 0~64KB C. 0~2KB D. 0~4KB
8. JZ rel 指令的转移条件是?
A. A≠0 B. A=0 C. CY=1 D. CY=0
9. 以下哪条指令属于位操作类指令?
A. MOV A, #00H B. SETB TR0 C. ADD A, R2 D. LJMP MAIN
10. END 伪指令的作用是?
A. 定义常量 B. 指定起始地址 C. 结束汇编 D. 预留存储空间
3 编程题
1. 编写程序,将内部RAM中30H单元的内容传送到40H单元,将40H单元的内容传送到30H单元(交换两个单元的内容)。
2. 编写程序,计算内部RAM中30H和31H两个单元内容的和,结果存入32H单元。
3. 编写程序,将累加器A的低4位清零,高4位保持不变。
4. 编写程序,判断累加器A中的数值是否大于50H,若大于则将P1.0置1,否则置0。
5. 编写程序,实现延时子程序,延时时间约为10ms(晶振频率为12MHz)。