第2章 89C51指令系统
2.1 汇编语言
2.2 MCS-51单片机的指令系统
2.3 汇编程序的
标号是程序员根据编程需要给指令设定的符号地址,可有可无;标号由1~8个字符组成,第一个字符必须是英文字,不能是数字或其它符号;标号后必须用冒号。
操作码指明执行什么性质和类型的操作 ,如数据传送操作,加法操作等。
2.1 汇编语言
2.1.1 指令的格式
操作数指明操作的数本身或者是操作数所在的地址。操作数一般有以下几种形式:没有操作数项,操作数隐含在操作码中,如NOP指令;只有一个操作数,如INC A指令;有两个操作数,如MOV A, #20H指令,操作数之间以逗号相隔;有三个操作数,如CJNE A,#00H,NEXT指令,操作数之间也以逗号相隔。
注释是对指令的解释说明,用以提高程序的可读性;注释前必须加分号。
2.1.2 指令中的常用符号
Rn: 表示当前工作寄存器R0~R7中的一个。
@Ri: 表示寄存器间接寻址,常常作间接寻址的地址指针。其中Ri代表R0和R1寄存器中的一个。
Direct: 表示内部数据存贮器单元的地址及特殊功能寄存器SFR的地址,对SFR而言,既可使用它的物理地址,也可直接使用它的名字。
#date: 表示8位立即数,即8位常数,取值范围为#00H~#0FFH
#date16: 表示16位立即数,即16位常数,取值范围为#0000H~#0FFFFH
addr16: 表示16位地址
addr11: 表示11位地址
rel: 用补码形式表示的地址偏移量,取值范围为- 128~+127。
Bit: 表示内部RAM和SFR中的具有位寻址功能的位地址。SFR中的位地址可以直接出现在指令中,为了阅读方便,往往也可用SFR的名字和所在的数位表示。如:表示PSW中奇偶校验位,可写成D0H,也可写成PSW.0的形式出现在指令中。
@: 表示间接寻址寄存器或基址寄存器的前缀符号。
$: 表示当前指令的地址。
/ : 位操作数的前缀,表示对该位操作数取反,如/bit。
×: 片内RAM的直接地址或寄存器。
(×): 由×寻址的单元中的内容。
寻址就是寻找指令中操作数或操作数所在的地址。
所谓寻址方式,就是如何找到存放操作数的地址,把操作数提取出来的
。
2.1.3 指令系统的寻址方式
1、立即寻址
立即寻址是指操作数在指令中直接给出,作为指令的一部分存放在代码段里。
例如2.1: MOV A,#30H; A←30H
MOV DPTR, #1234H; DPTR←234H
2、直接寻址
直接寻址是将操作数的地址直接存放在指令中。
例2.2: MOV PSW,# 20H ;
例2.3: MOV A,30H; A←(30H)
3、寄存器寻址
将操作数存放于通用寄存器中,以寄存器的内容为操作数的寻址方式。通用寄存器指A、B 、DPTR以及R0~R7 。
例2.4: CLR A
INC DPTR
ADD R5,# 20H
4、寄存器间接寻址
寄存器间接寻址是以寄存器中内容为地址,以该地址中内容为操作数的寻址方式,即操作数是通过寄存器间接得到的。用来存放操作数地址的寄存器称为指针。指针只能用R0、R1和DPTR
寻址范围:内部数据存储器、外部数据存储器
注意:为了与寄存器寻址区别开,寄存器间接寻址方式要在寄存器前加@; 间接寻址不能对SFR寻址。
例2.5: 设(R0)=25H,内部RAM (25H)=37H,
MOV A,@R0
指令的执行结果是: (A)=37H。 其指令操作过程示意图如图所示。
图2.1 寄存器间接寻址示意图
37H
A
25H
37H
25H
R0
地址
RAM
5、变址寻址
将基址寄存器与变址寄存器的内容相加,结果作为操作数的地址。DPTR或PC是基址寄存器,累加器A是变址寄存器。该类寻址方式主要用于查表操作。
例2.6:设(A)=02H,(DPTR)=2000H,外部ROM中,(2002H)=55H
执行指令 MOVC A,@A+DPTR
结果是 (A)=55H
程序
器
2000H
DPTR
02H
A
2002H
55H
02H
2000H
55H
图2.2 变址寻址示意图
6、相对寻址
以当前程序计数器PC的内容为基础,加上指令给出的一字节补码数(偏移量)形成新的PC值的寻址方式,新的PC值作为跳转指令的转移地址(也称目的地址)。
图2-3 相对寻址示意图
例2.7:1000H: SJMP 38H
7、位寻址
位寻址,是指对片内RAM中20H~2FH中的128个位地址,以及SFR中的11个可进行位寻址的寄存器中的位地址寻址。
例2.8: ① MOV C,20H ,
② MOV A,20H
①指令是位寻址指令,它是将位寻址区中位地址为20H中的内容,送给位累加器C,传送的是一位二进制数。②指令是字节地址寻址指令,此指令是将内部RAM中20H单元中的内容送给累加器A,传送的是8位二进制数。
2.2 MCS-51单片机的指令系统
51系列单片机指令系统由111条指令组成。
MCS-51指令系统可分为五大类:
数据传送指令(28条);
算术运算指令(24条);
逻辑运算及移位指令(25条);
控制转移指令(17条);
位操作指令或布尔操作(17条)
2.2.1 数据传送指令
数据传送操作是把数据从源地址传送到目的地址,指令执行后源地址内容不变,目的操作数被源操作数所代替。
1. 内部数据传送指令
(1). 以累加器A为目的操作数的指令
汇编指令格式 操作 字节 周期
MOV A, Rn ; (Rn)→A 1 1
MOV A, direct ; (direct)→A 2 1
MOV A, @Ri ; ((Ri))→A 1 1
MOV A,#data ; #data→A 2 1
(2). 以寄存器Rn为目的操作数的指令(3条)
汇编指令格式 操作 字节 周期
MOV Rn , A ; (A)→Rn 1 1
MOV Rn, direct ; (direct)→Rn 2 2
MOV Rn,#data ; #data→ Rn 2 1
这组指令的功能是把源操作数所指定的内容送到当前工作寄存器组R0~R7中的某个寄存器。源操作数有寄存器寻址、直接寻址和立即数寻址三种方式。
注意:89C51指令系统中没有“MOV Rn,Rn”传送指令。
问题:是否可以进行寄存器之间的直接寻址传送?如欲进行MOV R1,R2,可否用指令MOV R1,02H?
(3). 以直接地址为目的操作数的指令(5条)
汇编指令格式 操作 字节 周期
MOV direct,A ; (A)→direct 2 1
MOV direct,Rn ; (Rn)→direct 2 2
MOV direct,direct; (源direct)→ 3 2
(目的direct)
MOV direct,@Ri ; ((Ri))→direct 2 2
MOV direct,#data ; #data→direct 3 2
(4). 以间接地址为目的操作数的指令(3条)
汇编指令格式 操作 字节 周期
MOV @Ri , A ; (A)→(Ri) 1 1
MOV @Ri , direct ; (direct)→(Ri) 2 2
MOV @Ri ,#data ; #data→(Ri) 2 1
(Ri)表示Ri中的内容为指定的RAM单元。
(5). 以DPTR为目的操作数 (1条)
汇编指令格式 操作 字节 周期
MOV DPTR , #DATA16 ; dataH→DPH, 3 2
dataL→DPL
这是唯一的16位立即数传送指令,其功能是把16位常数送入DPTR。DPTR由DPH和DPL组成。
如执行MOV DPTR,#1234H指令,结果为 (DPTR)= 1234H。
2、外部RAM及I/O端口与累加器A之间的数据传送
CPU访问片外PAM只能采用寄存器间接寻址的方式,并且只能通过累加器
编指令格式 操作 字节 周期
MOVX A,@Ri ; ((Ri))→A,且使/RD=0 1 2
MOVX A,@DPTR ;((DPTR))→A,使/RD=0 1 2
MOVX @Ri,A ; (A)→(Ri),使/WR=0 1 2
MOVX @DPTR,A ; (A)→(DPTR),使/WR=0 1 2
在MCS-51系统中,由于扩展I/O端口与外部RAM统一编址,即扩展I/O端口地址占用外部RAM地址空间的某一单元,因此外部RAM及扩展I/O端口的读写操作指令、操作时序完全相同。只能通过累加器A存取外部RAM和扩展I/O端口。
① 使用@DPTR寻址的指令,访问64K范围。
② 使用@Ri寻址的指令,访问256B范围。
例2.13:已知片外RAM (2000H)=33H, 读外部RAM的2000H单元的程序段:
MOVX DPTR ,#2000H
MOVX A ,@DPTR
指令执行后,(A)=33H
例2.14:将累加器A的内容送到外部2000H单元的程序段:
MOV P2 , #20H
MOV R0 , 00H
MOVX @R0,A
3、累加器A与程序存储器ROM之间的数据传送指令 (查表指令)
MOVC A , @A+PC
MOVC A , @A+DPTR
例2.15: ORG 8000H
MOV A,#30H
MOVC A,@A+PC
…
ORG 8030H
DB ‘ABCDEFGHIJ’
上述查表指令执行后,将8003H+30H=8033H地址所对应的程序存储器中的内容44H(字符‘D’的ASCII码)送到累加器A中。
4、数据交换
(1)字节交换指令
XCH A,Rn
XCH A ,direct
XCH A,@Ri
(2)半字节交换指令
XCHD A,@Ri
半字节交换操作
五、堆栈操作
堆栈是在片内RAM中按“先进后出,后进先出”原则设置的专用存储区。设置堆栈操作的目的是为了保护断点和现场,以便在子程序或中断服务子程序运行结束后,能正确返回主程序。
数据的进栈、出栈由指针SP统一管理。堆栈的操作有如下两条专用指令:
PUSH direct ;SP←(SP+1),((SP))←(direct)
POP direct ; direct ←((SP)),SP ← SP-1
例2.16: 设(SP)=30H, (50H)=43, 执行指令
PUSH 50H
结果:(SP)=31H, (51H)=43H,
执行过程如图2.5所示。
例2.17:设(SP)=35H, (35H)=66H, 执行指令
POP 40H
结果:(40H)=66H,(SP)=34H,
执行过程如图2.6所示。
图2.5 PUSH指令示意图
××
片 内
43H
50H
31H
30H
SP
××
40H
执行前
片内
43H
50H
31H
30H
43H
××
SP
40H
执行前PUSH指令后
图2.6 POP指令示意图
片内
40H
11H
10H
SP
50H
片内
50H
35H
10H
66H
××
SP
40H
66H
66H
××
××
执行前
执行POP指令后
2.2.2 算术运算类指令
算术运算结果将进位CY、半进位AC、溢出位OV三个标志位置位或复位,只有加1和减1指令不影响这些标志位。
1、加法指令
ADD A,Rn ;A←(A) +( Rn)
ADD A,direct ;A← (A) +(direct)
ADD A,@Ri ;A← (A)+ ((Ri))
2、带进位加指令
ADDC A,Rn ;A←(A)+ (Rn) + C
ADDC A,direct ;A←(A)+(direct)+ C
ADDC A,@Ri ;A←(A)+(Ri)+ C
ADDC A,#data ;A←(A)+ #data + C
3、带借位减指令
SUBB A,Rn ;A← (A )-(Rn) - C
SUBB A,direct ;A← (A )-(direct)- C
SUBB A,@Ri ;A← (A) –(Ri)- C
SUBB A,#data ;A← (A )- data – C
4、乘法指令
MUL AB ; BA← A×B
MUL指令实现累加器A和B寄存器中的两个8位无符号数相乘,16位乘积的低8位放在累加器A中,高8位放在B寄存器中。
例2.20: (A)=30H,(B)=60H,
执行 MUL AB
结果: (A)=00H,(B)=12H。
5、除法指令
DIV AB
A/B→商在A中,余数在B中
DIV指令实现累加器A和B寄存器中的两个8位无符号相除,其中商存放累加器A中,余数存放在B中。
例2.21 (A)=0B4H(即180),(B)=18H (即24)
执行 DIV AB
结果为 (A)=07H…商 (B)=0CH…余数,(Cy0=0 ,(OV)=0 , (P)=1
6、加1指令
INC A ;A← (A) + 1
INC Rn ;Rn← (Rn) + 1
INC direct ;direct← (direct)+ 1
INC @Ri ;(Ri)←((Ri))+ 1
INC DPTR ;DPTR←( DPTR) + 1
7、减1指令
DEC A ;A← (A) - 1
DEC Rn ;Rn← (Rn) - 1
DEC direct ;direct← (direct)- 1
DEC @Ri ;(Ri)←(Ri)- 1
加1减1指令,通常配合寄存器间接寻址指令,用于修改地址指针。
8. 十进制调整指令
DA A
该指令专用于BCD码加法运算的十进制调整
该指令一般是跟在ADD或ADDC指令之后,并且是两个压缩型BCD数相加。使用该指令是为了把累加器A中和进行调整。调整的实质是将十六进制的加法运算转换成十进制,具体调整的方法为:
① 若累加器A的低4位大于9(A-F),或者辅助进位位AC=1,则累加器A的内容加06H(A←(A)+06H),且将AC置“1”。
② 若累加器A的高4位大于9(A-F),或进位位Cy=1,则累加器A的内容加60H(A←(A)+60H),且将Cy置“1”。
调整后,辅助进位位AC表示十进数中个位向十位的进位,进位标志Cy表示十位向百位的进位。
例2.22:(A)=65BCD,(B)=78BCD,Cy =0
ADD A,B
DA A
指令执行后,(A)=43BCD,(Cy) =1。
2.2.3 逻辑运算与循环类指令
1、逻辑“与”指令
ANL A,Rn ; A ←(A)∧Rn)
ANL A,direct ; A←(A)∧(direct)
ANL A,#data ; A←(A)∧data
ANL A,@Ri ; A←(A)∧((Ri))
ANL direct,A ; direct←(direct)∧(A)
ANL direct,#data ; direct ←(direct)∧#data
ANL A,#data 该指令可用于对目的操作数的某一位或某几位清零
例2.23 A NL P1 ,#0FH P1口锁存器的高4位清零,低4位不变。
2、逻辑“或”指令
ORL A,Rn ;A ←(A)∨(Rn),n=0~7
ORL A,direct ; A ←(A)∨(direct)
ORL A,#data ; A← (A)∨ data
ORL A,@Ri ; A ←(A)∨((Ri)),i=0,1
ORL direct,A ;direct←(direct)∨(A)
ORL direct,#data ;direct←(direct)∨#data
ORL A,#data 该指令可用于对目的操作数的某一位或某几位取反
例2.25 (P1)=05H,(A)=33H,
执行指令 ORL P1,A
3、逻辑“异或”指令
XRL A,Rn ; A←(A) ⊕(Rn)
XRL A,direct ;A ←(A) ⊕(direct)
XRL A,@Ri ;A ←(A)⊕((Ri)),i=0,1
XRL A,#data ;A ←(A)⊕#data
XRL direct,A ;direct←(direct)⊕(A)
XRL direct,#data ;direct←(direct)⊕ #data XRL A,#data 该指令可用于对目的操作数的某一位或某几位置1
例2.26. 设(A)=90H,(R2)=72H 指令执行
XRL A, R2
结果:(A)=0E2H,(R2)=72H。
4、求反与清零指令
① CLR A 功能是累加器A清“0”。不影响Cy、Ac、OV等标志。
② CPL A 功能是将累加器A的内容按位逻辑取反,不影响标志。
例 2.28: 设 (A) =00110110B=36;
执行指令: CPL A
结果: (A) =11001001B=C9H
5、循环指令
① RL A
② RR A
③ RLC A
④ RRC A
⑤ 累加器ACC半字节交换指令
SWAP A ; (A0~3) (A4~7)
2.2.4 程序转移类指令
1、无条件转移指令
① 绝对(短)转移指令
AJMP addr11 ;PC10~0 ← addr11
这是一条2K字节范围内的无条件跳转指令,转移的目标地址必须与AJMP下一条指令的地址的高5位地址码A15-A11相同。
执行指令时, PC先加2,然后把addrll送入PC.10~PC.0,PC.15~PC.11保持不变。由于该指令只修改PC的部分内容,所以通过该指令形成的目的地址只在2K内变化。
② 长转移指令
LJMP addr16 ;PC ← addr16
把指令第二、第三个字节的内容即指令提供的16位目的地址送入PC,然后程序无条件地转移到目标地址处。
因为addr16是一个16位二进制地址,地址范围0000H~FFFFH,因此可在64KB范围内转移。
③ 短(相对)转移指令
SJMP rel ;PC ← PC + 2 + rel
指令功能是先使程序计数器PC加2,然后指令提供的有符号的地址偏移量rel和PC相加,得到目的地址。转移的范围为-128-+127字节 。
④间接转移指令(散转指令)
JMP @A+DPTR ;PC ← A + DPTR
指令功能是将累加器A中8位无符号数二进制数与数据指针DPTR的内容相加,以形成目的地址送入PC,实现无条件转移操作。
该指令的特点是转移地址可以在程序运行中加以改变。因此这条指令具有多分支转移的功能,该功能称为散转功能,间接长转移指令又称为散转指令。
书: 例2.30
RL A
MOV DPTR,#TAB ;将TAB代表的地址送入DPTR
JMP @A+DPTR ;跳转
TAB: AJMP ROUT0 ;跳转ROUT0开始的程序段
TAB+2: AJMP ROUT1 ;跳转ROUT1开始的程序段
TAB+4: AJMP ROUT2 ;跳转ROUT2开始的程序段
TAB+6: AJMP ROUT3 ;跳转ROUT3开始的程序段
...
ROUT0:
...
ROUT1:
...
ROUT2:
...
ROUT3:
2、条件转移指令
条件转移指令的操作是判断指定的条件,如果条件满足则转移,不满足则顺序执行。该类指令都采用相对寻址方式,转移范围共256字节 (-128~127B)。当条件满足时,把PC的当前值(下一条指令的第一个字节的地址)与相对偏移量rel相加形成转移的目标地址。
① 累加器判零转移指令
JZ rel ; A=0, (PC)←(PC)+ 2 + rel
JNZ rel ; A≠0, (PC)←(PC)+ 2 + re
② 比较转移指令
CJNE A,#data,rel
CJNE A,direct,rel
CJNE Rn,#data,rel
CJNE @Ri,#data,rel
例2.31: MOV A,R0
CJNE A,#10H,L1 ;
MOV R1,#0 ;
AJMP L3
L1: JC L2
MOV R1,#0AAH ;
AJMP L3
L2: MOV R1,#0FFH
L3: MP L3
因此最终结果是:本程序执行前,
如果R0=10H,则R1=00H;
如果R0>10H,则R1=0AAH;
如果R0<10H,则R1=0FFH。
③ 减1非0转移指令
DJNZ Rn,rel ; Rn ←(Rn)-1,
若(Rn)≠0, (PC)←(PC)+ 2 + rel;
若(Rn)=0,(PC)←(PC)+ 2
指令功能:工作寄存器Rn减1不等于0,则,转移到偏移量所指向的地址,否则程序往下执行。
DJNZ direct,rel ;direct←(direct)-1,
若 direct≠0, (PC)←(PC)+ 2 + rel;
若 direct=0, (PC)←(PC)+ 2
指令功能:直接地址单元中的内容减1不等于0,则转移到偏移量所指向的地址,否则程序往下执行
④ 位转移指令
JC rel
若Cy=1,则转移 (PC←PC+2+rel);否则程序顺序执行
JNC rel
若Cy=0,则转移(PC←PC+2+rel);否则程序顺序执
JB bit,rel
若(bit)=1,则转移(PC←PC+3+rel);否则程序顺序 执行
JNB bit,rel
若(bit)=0,则转移(PC←PC+3+rel);否则程序顺序执行
(1)调用子程序指令
在程序设计中,通常将反复出现、具有通用性和功能相对独立的程序段设计成子程序。子程序可以有效地缩短程序长度、节约存储空间;可被其他程序共享以及便于模块化、便于阅渎、调试和修改。
2.2.5 调用子程序及返回指令
① 长调用指令
LCALL addr16 ;
PC←PC+3,SP←SP+1,(SP)←PC7~10
;SP←SP+1,(SP)←PC15~8, PC←addr16
长调用指令的16位目标地址由指令直接给出,所以子程序可放在64KB空间的任何地方。
指令的执行过程是把本指令的第2、3个字节分别装入PC的高8位和低8位)获得子程序的入口地址,并把该断点地址入栈(断点地址保护)。;
② 绝对调用指令
ACALL addr11
;PC ←PC+2, SP←SP+1,(SP)←PC7~0
;SP ← SP+1,(SP)← PC15~8, PC10~0←addr11
指令执行过程:
PC加2(本指令代码为两个字节)获得下一条指令的地址,
把该断点地址(当前的PC值)入栈,
将断点地址的高五位与11位目标地址(指令代码第一字节的高3位,以及第二字节的八位)连接构成16位的子程序入口地址,使程序转向子程序。
注意:
调用子程序的入口地址和ACALL指令的下一条指令的地址,其高五位必须相同,因此子程序的入口地址和ACALL指令下一条指的第一个字节必须在同一个2KB范围内。
2 返回指令
RET
;PC15~8← (SP),SP←SP-1
;PC7~0← (SP),SP←SP-1
返回指令的功能是恢复断点地址,即从堆栈中取出断点地址送给PC,子程序通过RET指令返回主程序。
RETI
;PC15~8←(SP),SP←SP-1
;PC7~0 ←(SP),SP←SP-1
功能与RET指令相似,两指令不同之处是该指令清除了中断响应时被置“1”的内部中断优先级寄存器的优先级状态。
2-2-6 位操作指令
1、位数据传送指令
MOV C,bit ;C←(bit)
MOV bit,C ;bit←C
例2.32 MOV C, 06H
;(20H).6→Cy 06H是内部RAM 20H字节位6的位地址。
例2.33 MOV P1.0, C
;Cy→P1.0 2、位状态修改指令
CLR C ;C←0
CLR bit ;(bit)←0
CPL C ;C←
CPL bit ;(bit)←(bit)
SETB C ;C←1
SETB bit ;(bit)←1
这组指令将操作数指出的位清“0”、求反、置“1”, 不影响其它标志。
例2.34: SETB 3DH; 将27H.5位置1
CLR C; Cy位清0
2、位状态修改指令
3、位逻辑运算指令
ANL C,bit ;C←C∧(bit)
ANL C,/bit ;C←C∧(bit)
ORL C,bit ;C←C∨(bit)
ORL C,/bit ;C←C∨(bit
2-2-7 空操作指令
NOP ;PC ← PC+1
这条指令除了使PC加1,消耗一个机器周期外,没有执行任何操作。可用于短时间的延时
2. 3 汇编语言程序设计
2.3.1 常用的伪指令
1. ORG 汇编起始地址命令
格式:ORG nn
例2.35: ORG 1000H
ST: MOV A, R1
…
上述指令
了其后一段程序的起始地址为1000H,并指定了标号ST的地址为1000H。
2. END 汇编结束命令
用于汇编语言源程序的末尾,表示源程序到此结束。在机器汇编时,对END后面的指令不予处理。
3. DB 定义字节数据命令
格式:[名字:] DB n1, n2, n3,………,nN
例3.36: ORG 1000H
TAB1: DB ‘ABC’ 100,32H
从1000H开始的存储单元的内容如图1:
4. DW 定义字数据命令
格式:[名字:] DW nn1, nn2,……,nnN
例3.37: ORG 2000H
TAB2:DW 1020H, 1234H, 100
汇编后存储单元的内容如图2
…
32H
64H
43H
41H
42H
1000H
ROM
1001H
1002H
1003H
1004H
5. DS 定义存储区命令
格式: [名字:] DS X
从指定的地址开始,保留X字节的存储单元。
例3.38 : ORG 6000H
L1:DS 02H
L2:DB 88H,35H
汇编后,从6000H开始保留2个字节单元,从6002H单元开始按DB命令给内存单元赋值:(6002H)=88H(6003H)=35H
6. EQU(Equat)赋值命令
格式:字符名 EQU 数或汇编符号
把字符名赋予一个数或特定的汇编符号。赋值后,指令中可用该符号名来表示数或汇编符号。
例3.39: CH1 EQU 2000H
X EQU R1
通过EQU命令把CH1等值为数值2000H,X等值于寄存器R1。
7 . DATA 数据地址赋值命令
格式:字符名 DATA nn
DATA命令是将数据地址或代码地址赋予规定的字符名称。
8. BIT 定义位地址符号命令
格式:字符名 BIT bit
将位地址bit赋予所定义的字符名。
例3.40: L0 BIT P1.1
该指令把位地址P1.1赋给了变量 L0
2.3.2 程序设计的步骤
1. 程序设计的一般
(1)任务
;
(2)分析问题,确定算法和工作步骤;
(4)分配内存,确定程序与数据区存放地 址,画出程序流程图;
(5)编写汇编语言的源程序;
(6)上机调试、修改,最终确定程序。
1. 顺序程序设计
程序按顺序一条一条地执行指令。
例2.41: 两个4为BCD码分别放在片内RAM 30H、31H和40H、41H中,求它们的和并将和存放在片内RAM 50H、51H、52H中,低地址放低位数。
参考程序如下:(考虑最高位可能有进位)
ORG 1000H
MOV A, 30H ;最低位送入累加器A
ADD A,40H
DA A ;BCD码调整
MOV 50H,A ;存放和的最低位
MOV A,31H
ADDC A,41H
DA A ;BCD码调整
MOV 51H,A ;存放和的高位
CLR C
MOV A,#00H
ADDC A,#00H ;保留最高位进位
MOV 52H, A
SJMP $ ;暂停
END
例3.41、把片外8000H中的数拆成高、低半字节,分别送入40H、41H两个单元中
ORG 0000H
MOV R0, #40H ;设R0为地址指针
MOV DPTR, #8000H ;指定的字节
MOVX A, @DPTR
MOV B, A ;暂存
SWAP A ;交换
ANL A, #0FH ;屏敝高位
MOV @R0 , A
INC R0
MOV A, B
ANL A, #0FH ;指定字节的内容屏敝高位
MOV @R0, A
LOOP: SJMP LOOP
END
3.分支程序
程序分支是根据条件对程序的执行进行判断,满足条件则进行程序转移,不满足条件就顺序执行程序。分支程序又分为单分支和多分支结构。
例3.42 假设有两个数在内部RAM 单元的40H 和41H 中现在要求找出其中较大的一个数并将较大的数存入40H 中,将较小的一个数存入41H 中
ORG 1000H
MOV A, 40H
CLR C
SUBB A, 41H
JNC WAIT
MOV A, 40H
XCH A, 41H
MOV 40H, A
WAIT:SJMP $
END
3.多分支程序结构
多分支程序通过多个条件来实现转移,一个条件形成两路分支,在其中的一个分支继续进行条件判断,形成下一级分支,从而实现分支的嵌套。
例3.42 见书
ORG 1000H
MOV A, 40H ;取出第一个数
CLR C
SUBB A, 41H ;与第二个数比较
JNC WAIT ;第一个数≧第二数,转到结束
MOV A, 40H
XCH A,41H ;两个数交换i
MOV 40H, A
WAIT:SJMP $
END
例3.44: 求符号函数Y
ORG 0010H
START: MOV A, 30H
JZ MM
J NB ACC.7, LL
MOV A, #0FFH;
AJMP MM LL: MOV A, #01H
MM: MOV 31H, A
END
3. 散转程序
散转指令的操作是16位地址指针DPTR的内容和A中无符号数相加,形成地址,装入程序计数器PC中。
例2.45:根据R3的内容,转至对应的分支程序。设R3的内容为0~255,对应的处理程序地址分别为ROUT00~ROUT7FH。
JMP_128: MOV A,R3
RL A ;A乘以2
MOV DPTR,#JMPTAB ;散转的起始地址
JMP @A+DPTR
JMPTAB: AJMP ROUT00
AJMP ROUT01 ; 128个子程序首址
┇ ┇
AJMP ROUT7F
4. 循环程序
在程序运行中需要多次反复执行某段程序段,这时可以在程序中设置一些条件,使该段程序从分支出口出来,又回到入口,继续重复执行该段程序。
循环结构程序主要由以下四部分组成
循环初始化
循环体
循环控制
循环结束
①单重循环
例2.46: 把片内RAM以30H为首地址的数据块依次传送到片外RAM以2000H为首地址的区域内,数据块的长度在工作寄存器R2中。
ORG 000H
MOV R0, #30H ;建立源地址指针
MOV DPTR , #2000H ;建立目的地址指针
LOOP: MOV A, @R0 ;取数
MOVX @DPTR, A ;保存到目标地址中
INC R0 ;源地址加
INC DPTR ;目的地址加
DJNZ R2, LOOP ;判断数据是否移完
SJMP $
END
② 多重循环
循环体内还包含循环体程序,称循环嵌套,或称多重循环。在多重循环中,不允许循环体相互交叉,也不允许从外层循环跳入内层循环,否则将出错。双重循环的流程图如图
例3.47: 片内RAM从30H单元开始存放了10个无符号的数,将它们按照由小到大的顺序排列
ORG 0100H
SORT: MOV R0, #30H ;置数据块首地址
MOV R1, #09H ;置每次冒泡比较次数
CLR 20H ;交换标志位清0
LOOP: MOV A, @R0 ;取前数
INC R0
MOV B, @R0 ;取后一个数
CJNE A, B, SS ;比较两个数的大小
SS: JC ZZZ ;若前一个数<后一个数,转移,不交换
MOV @R0, A
DEC R0
MOV @R0, B
INC R0 ;交换数据
SETB 20H ;有交换,标志位置1
ZZZ: DJNZ R1, LOOP
JB 20H, SORT ;若有交换,继续进行下一轮冒泡
SJMP $
END
4. 查表程序
查表程序广泛应用于显示、打印字符的转换以及数据补偿、计算、转换等程序中。
( 1)用DPTR作为基址的查表程序
通常由三步完成
①将所查表格的首地址存入DPTR中;
②将所查表格的项数即所需读取的表格元素在表中的位置是第几项送到累加器A中;
③执行查表指令 MOVC A,@A+DPTR,把表中读取的数据送回到累加器A中。
。
(2)用PC作为基址的查表程序
MOVC A,@A+PC
该指令执行时先将所查表格的项数送到累加器A中,再进行地址调整,把偏移量加到A中 。
偏移地址(DATA) 计算方式为 :
DATA = 表格首地址-(该指令所在的地址+1),
用ADD A,#DATA
执行完这条指令后PC的内容不变,只要改变A中值,即可将表格各位数据读出
例3.49:已知30H的低4位有一位十六进制数,把它转成ASCⅡ 码送30H中。
ORG 0000H
MOV A,30H
ANL A,#0FH ;屏蔽高四位
ADD A,#(TAB-HTA-1) ;加偏移量
HTA: MOVC A,@A+PC ;查表
MOV 30H,A ;30H ← A
TAB:DB 30H,31H,33H,34H,35H,36H,37H,38H,39H
DB 41H,42H,43H,44H,45H,46H
SJMP $
END
例3.50:见书
RE: MOV DPTR, #TAB
MOV A,31H
CLR C
RLC A ;X*2,双字节表,低字节左移一位
MOV 31H, A
XCH A, 30H
RLC A ;高字节左移
XCH A, 30H
MOV A,31H
ADD A, DPL ;加表首地址
MOV DPL, A
MOV A, DPH
ADDC A, 30H
MOV DPH, A
CLR A
MOVC A, @A+DPTR ;取出温度数据高位
MOV 30H ,A
INC DPTR
CLR A
MOVC A, @A+DPTR ;取出温度数据低位
MOV 31H, A
RET
TAB: DW ××
6.子程序设计
(1).子程序设计时注意事项:
① 子程序的入口地址:
给子程序赋一个名字,实际为入口地址的符号地址
②子程序的参数传递
入口参数——主程序在指定位置提供给子程序的数据。主调程序在调用子程序前,应将入口参数放在指定的空间以便传给子程序,子程序运行后将在这些空间得到需要处理的数据或数据所在的地址。
出口参数——子程序运行结束前,把处理好的结果送到指定的位置,以便返回主程序后,主程序可以从指定位置得到需要的结果,这类子程序返回主程序的参数就是出口参数。
参数传递的方法
主要有三种传递方法
利用寄存器或片内RAM传送参数。
利用寄存器传送参数的地址。
利用堆栈传送参数。
③保护与恢复现场:
保护现场:压栈指令PUSH
恢复现场:弹出指令POP
④ 子程序嵌套
子程序可以嵌套,子程序运行时,通过子程序中调用指令,调用另外子程序。
5. 子程序的返回
子程序运行完后,通过子程序中最后1条指令RET,返回原来的主程序。
例3.50 把A中的4位二进制数转成ASCII码,结果存入A中
入口参数:待转换的二进制数在A中。
出口参数:转换后的ASCII码在A中
ZHCX: CJNE A ,#0AH,NEXT
NEXT :JC ASC1
ADD A , #07H
ASC1: ADD A,#30H
RET
例3.52 ASCII码转换成十六进制数
入口参数:待转换的 ASCII 码在R2中。
出口参数:转换后的十六进制数在R3中。
XP: MOV A,R2
CLR C
SUBB A,#30H
CLR C
JNB ACC.4,M1
SUBB A,#7
M1: MOV R3,A
SJMP $
例3.52 双字节BCD码整数转换成双字节十六进制整数
BH2: M OV A,R3 ;将低字节转换成十六进制
LCALL BCD1
MOV R3,A
MOV A,R2 ;将高字节转换成十六进制
LCALL BCD1
MOV B,#100 ;扩大一百倍
MUL AB
ADD A,R3 ;和低字节按十六进制相加
MOV R3,A
CLR A
ADDC A,B
MOV R2,A
SJMP $
BCD1: MOV B,#10H ;分离十位和个位
DIV AB
MOV R4,B ;暂存个位
MOV B,#10 ;将十位转换成十六进制
MUL AB
ADD A,R4 ;十六进制加上个位
RET
例3.53 二进制数转成十进制数(BCD码)
入口参数:待转换的 二进制数在R2中。
出口参数:转换为的三位BCD码,存放在R3(百位),R4(十位),R5(个位)中
MOV A, R2 ;取来二进制.
MOV B, #100
DIV AB ;除以100
MOV R3, A ;A中是百位数.
MOV A, #10
XCH A, B
DIV AB ;再除以10
MOV R4, A ; A中是十位数.
MOV R5, B ;B中的数是个位
RET