第四章汇编语言及程序设计伪指令不是真正的指令,在汇编时不产生机器代码。伪指令的功能主要是用来对汇编过程进行某种控制。采用机器汇编的方法时,源程序必须通过汇编程序的处理,才能转换为计算机识别和执行的机器语言。
为此,在源程序中应有向汇编程序发出的指示信息,
告诉汇编程序如何完成汇编工作。如用伪指令给程序分配一定的存储区、定义符号、指定暂存数据的 RAM
区等。
§ 4.1 伪指令一般用于确定汇编语言源程序或某数据块在内存存储的首地址
ORG 2000H
START,MOV A,#10H

END
在一个源程序中,可以多次使用 ORG规定不同程序段的起始地址,但定义的地址顺序应该是从小到大,不允许交叉、重叠。
1,ORG(起始汇编)伪指令
ORG 2000H

ORG 2500H

ORG 3000H

ORG 2500H

ORG 2000H

ORG 3000H

END是汇编语言源程序的结束标志,常用于汇编语言源程序末尾,表示汇编结束。一个源程序只能有一个 END命令,且置于程序的最后。在 END以后所写的指令,汇编程序都不予处理。
2,END(结束汇编)伪指令字符名 EQU 数据或汇编符
ORG 2000H
KA EQU R1
M1 EQU 20H
STRT EQU 2500H
MOV R0,#M1
MOV KA,A

ACALL STRT

END
3,EQU(赋值)伪指令
①,字符名”不是标号,故它与 EQU之间不能用,,”
隔开;
②,字符名”必须先赋值后使用,只能赋值一次;
K1 EQU 30H
MOV A,K1+1
③ 在有些 MCS-51汇编程序中,EQU定义的“字符名”
不能在表达式中运算。如下面语句就是 错误的。
字符名 DATA 表达式
① 表达式允许是一个数据或地址,也可以是包含被定义的“字符名”在内的表达式,但不能是汇编符号,
如 R0~ R7等
② DATA伪指令可放在程序的任何位置,比 EQU伪指令灵活
4,DATA(赋值)伪指令
ORG 2000H
M DATA 20H
DELAY XDATA 08AFH
MOV A,M

LCALL DELAY

END
③ DATA伪指令一般用于定义程序中所用的 8位或 16位的数据或地址,但在有些汇编程序中,只允许 DATA语句定义 8位数据或地址,定义 16位的数据或地址时,需使用 XDATA语句
DB伪指令可用来为汇编语言源程序在内存的某区域中定义一个或一串字节。
[标号,] DB 项或项表
ORG 2000H
TAB1,DB 30H,8AH,7FH,73
DB '5','A','BCD'
5,DB(定义字节)伪指令
(2000H)=30H
(2001H)=8AH
(2002H)=7FH
(2003H)=49H ;十进制数 73以十六进制数存放
(2004H)=35H ; 35H是数字 5的 ASCII码
(2005H)=41H ; 41H是字母 A的 ASCII码
(2006H)=42H ; 42H是字符串 'BCD'中 B的 ASCII码
(2007H)=43H ; 43H是字符串 'BCD'中 C的 ASCII码
(2008H)=44H ; 44H是字符串 'BCD'中 D的 ASCII码
DW伪指令称为定义字伪指令,用于为源程序在内存某个区域定义一个字或一串字。其格式为:
[标号,] DW 项或项表
ORG 1500H
TAB2,DW 1234H,80H
(1500H)=12H,(1501H)=34H,
(1502H)=00H,(1503H)=80H
6,DW(定义字)伪指令
DS伪指令称为定义存储空间伪指令。
[标号,] DS 表达式
ORG 1000H
DS 20H
DB 30H,8FH
汇编后从 1000H开始,预留 32(20H)个字节的内存单元,然后从 1020H开始,按照下一条 DB指令赋值,
即 (1020H)=30H,(1021H)=8FH。
7,DS(定义存储空间)伪指令
BIT伪指令称为位地址赋值伪指令,用于给以符号形式的位地址赋值。
字符名 BIT 位地址
ORG 0500H
K1 BIT 20H
K2 BIT 30H
Y BIT P1.0
BG,MOV C,K1
ANL C,K2
MOV Y,C

END
8,BIT(位地址赋值)伪指令
§ 4.2 汇编语言的程序设计顺序结构分支结构循环结构查表结构子程序结构顺序结构程序是最简单的程序结构,也称为直线结构程序。这种程序中既无分支、循环,也不调用子程序,
程序按顺序一条一条地执行指令。
【 例 】 拆字程序。 将 30H单元内的两位 BCD码拆开并转换成 ASCII码,将转换后的 ASCII码放在 31H和 32H
单元,并让低位 ASCII码放在 32H单元。
1,顺序结构程序设计
ORG 2000H
MOV A,30H
ANL A,#0FH
ADD A,#30H
MOV 32H,A
MOV A,30H
SWAP A
ANL A,#0FH
ADD A,#30H
MOV 31H,A
SJMP $
END
例,将 60H单元中的 8位无符号数转换成三位 BCD码,
并存放在 BAI(百位),SHI(十位)和 GE(个位)
三个单元中。
ORG 2000H
BAIW DATA 40H
SHIW DATA 41H
GEW DATA 42H
MOV A,60H
MOV B,#100
DIV AB
MOV BAIW,A
MOV A,B
MOV B,#10
DIV AB
MOV SHIW,A
MOV GEW,B
SJMP $
END
例,将两个三字节无符号数相加,其中一个加数在内部 RAM的 32H,31H和 30H单元;另一个加数在内部 RAM
的 35H,34H和 33H单元,要求相加后的和存入 32H,31H
和 30H单元,进位存入位寻址区的 20H单元中。
ORG 2000H
MOV R0,30H
MOV R1,33H
MOV A,@R0
ADD A,@R1
MOV @R0,A
INC R0
INC R1
MOV A,@R0
ADDC A,@R1
MOV @R0,A
INC R0
INC R1
MOV A,@R0
ADDC A,@R1
MOV @R0,A
MOV 20H,C
END
例,16位数求补。已知 16位二进制数在 R1,R0中,
将此 16位二进制数求补,求补结果存入内部 RAM
31H,30H单元。 ORG 2000H
MOV A,R0
CPL A
ADD A,#01H
MOV 30H,A
MOV A,R1
CPL A
ADDC A,#00H
MOV 31H,A
END
分支结构程序的特点就是程序中含有转移指令分支程序的设计要点如下:
( 1)先建立可供条件转移指令测试的条件;
( 2)选用合适的条件转移指令;
( 3)在转移的目的地址处设定标号。
在 MCS-51指令系统中,通过条件判断,实现单分支程序转移的指令有 JZ,JNZ,CJNE和 DJNZ等。
此外还有以位状态作为条件进行程序分支的指令,如
JC,JNC,JB,JNB和 JBC等。使用这些指令可以完成以 0,1、正、负,以及相等、不相等作为各种条件判断依据的程序转移。
2,分支结构程序设计例 求单字节有符号二进制数的补码
ORG 2000H
JNB ACC.7,NEG
MOV C,ACC.7
MOV 00H,C
CPL A
ADD A,#1
MOV C,00H
MOV ACC.7,C
NEG,SJMP $
END
例,已知 VAR单元中有一自变量 X,请按如下条件编出求函数值 Z并将它存入 FUN单元的程序。
ORG 2000H
VAR DATA 40H
FUN DATA 41H
START,MOV A,VAR
JZ SAVE
JNB ACC.7,ZHEN
MOV A,#0FFH
SJMP SAVE
ZHEN,MOV A,#01H
SAVE,MOV FUN,A
SJMP $
END
ORG 2000H
VAR DATA 40H
FUN DATA 41H
START,MOV A,VAR
CJNE A,#0,NEQ
SJMP SAVE
NEQ,JNB ACC.7,ZHEN;
MOV A,#0FFH
SJMP SAVE
ZHEN,MOV A,#01H
SAVE,MOV FUN,A
SJMP $
END
ORG 2000H
VAR DATA 40H
FUN DATA 41H
START,MOV A,VAR
JZ SAVE
MOV R1,#0FFH
JB ACC.7,NEG
MOV R1,#01H
NEG,MOV A,R1
SAVE,MOV FUN,A
SJMP $
END
例,两个带符号数分别存于 ONE和 TWO单元,试编程比较大小,并将大的数存入 MAX单元。
若 X-Y为正,则
OV=0,X>Y
OV=1,X<Y
若 X-Y为负,则
OV=0,X<Y
OV=1,X>Y
ORG 2000H
ONE DATA 30H
TWO DATA 31H
MAX DATA 32H
CLR C
MOV A,ONE
SUBB A,TWO
JZ XMAX
JB ACC.7,NEG
JB OV,YMAX
SJMP XMAX
NEG,JB OV,XMAX
YMAX,MOV A,TWO
SJMP SAVE
XMAX,MOV A,ONE
SAVE,MOV MAX,A
SJMP $
END
3.循环结构程序设计
( 1)循环初始化,
循环初始化程序段一般位于循环程序的开头,
位于循环体外,用于设置循环过程工作单元的初始值。例如,设置循环次数计数器、地址指针初值等
( 2)循环处理:
循环处理程序段位于循环体内,是需要重复执行的程序段部分。
( 4)循环结束:循环结束程序段用于处理循环程序的最终结果以及恢复各工作单元的初始值。在循环次数已知的情况下,用计数方法控制循环的终止。循环次数未知的情况下,可根据某种条件判断决定是否终止循环。
( 3)循环控制:循环控制程序段也位于循环体内,
用于判断循环条件是否满足,不满足则转去执行循环处理程序部分,否则,退出循环。一般采用
DJNZ指令来自动修改控制变量并结束循环。
例,将内部数据存储器 30H~ 7FH单元中的内容送到外部数据存储器以 1000H开始的连续单元中去。
LOOP,MOV A,@R0
MOVX @DPTR,A
INC R0
INC DPTR
DJNZ R7,LOOP
SJMP $
END
ORG 2000H
TAB1 EQU 1000H
MOV R0,#30H
MOV DPTR,#TAB1
MOV R7,#50H
例,已知内部 RAM的 ADDR1单元开始有一无符号数据块,块长在 LEN单元,请编出求数据块中各数累加和并存数外部 RAM的 SUM1单元的程序。
LOOP,ADD A,@R1
INC R1
CHECK:DJNZ R2,LOOP
MOVX @DPTR,A
SJMP $
END
ORG 2000H
ADDR1 EQU 30H
LEN EQU 20H
SUM1 EQU 2000H
MOV DPTR,#SUM1
CLR A
MOV R2,LEN
MOV R1,#ADDR1
INC R2
SJMP CHECK
NEXT,ADD A,@R1
INC R1
DJNZ R2,NEXT
MOVX @DPTR,A
SJMP $
END
ORG 2000H
ADDR1 EQU 30H
LEN EQU 20H
SUM1 EQU 2000H
MOV DPTR,#SUM1
CLR A
MOV R2,LEN
MOV R1,#ADDR1
NEXT1,JC NEXT
MOV MAX,A
NEXT,INC R1
DJNZ LEN,LOOP
SJMP $
END
例,已知内部 RAM ADDR1为起始地址的数据块内部数据是无符号数,块长在 LEN单元内,请编程求出数据块中的最大值并存入 MAX单元。
ORG 2000H
ADDR1 DATA 50H
LEN DATA 30H
MAX DATA 32H
MOV MAX,#00H
MOV R1,#ADDR1
LOOP,MOV A,@R1
CJNE A,MAX,NEXT1
4.查表结构程序设计所谓查表就是根据存放在 ROM中的数据表格的项数来查找和它对应的表中值。即:把事先计算或实验数据按一定顺序编成表格,存于 ROM中,然后根据输入参数值,从表中取出结果。
例,求函数 Y= X!( X= 0,…,7)的值。设自变量存放在 ADDR1单元,表头的地址为 TAB1,表中每个数据占两个字节,Y值为双字节,存放在寄存器 R2R3中,
R3存放 Y值低字节,请编出查表程序。
ORG 2000H
ADDR1 EQU 20H
START,MOV A,ADDR1
ADD A,ADDR1
MOV R3,A
ADD A,#07H
MOVC A,@A+PC
XCH A,R3
ADD A,#04H
MOVC A,@A+PC
MOV R2,A
SJMP $
TAB1,DB 01,00,01,00,02,00,06,00
DB 24H,00,20H,01,20H,07,40H,50H
END
例,已知 R0低四位有一个十六进制数( 0~F中的一个),
请编出能把它转换成相应 ASCII码并送入 R0的程序。
ORG 2000H
MOV A,R0
ANL A,#0FH
CJNE A,#10,NEXT1
NEXT1:JNC NEXT2
ADD A,#30H
SJMP SAVE
NEXT2:ADD A,#37H
SAVE,MOV R0,A
SJMP $
END
ORG 2000H
MOV A,R0
ANL A,#0FH
ADD A,#90H
DA A
ADDC A,#40H
DA A
MOV R0,A
SJMP $
END
ORG 2000H
MOV A,R0
ANL A,#0FH
ADD A,#03H
MOVC A,@A+PC
MOV R0,A
SJMP $
TAB,DB ‘0’,’1’,’2’,’3’,’4’
DB ‘5’,’6’,’7’,’8’,’9’
DB ‘A’,’B’,’C’,’D’,’E’,’F’
END
5,子程序结构程序设计子程序在结构上应具有通用性、独立性和可调用性
① 子程序的第一条指令地址称为子程序的始地址或入口地址。该指令前必须有标号,标号应以子程序任务定名。例如求和子程序常以 ADD1为标号。
②主程序调用子程序是通过安排在主程序中的调用指令实现的,在子程序末尾放置 RET子程序返回指令。
③ 子程序调用和返回指令能自动保护和恢复断点地址,但对需要保护的工作寄存器、特殊寄存器和内存单元中的内容,就必须在子程序开始和末尾( RET指令前)安排保护和恢复的指令。
⑤ 子程序参数可以分为入口参数和出口参数两类:
入口参数是指子程序需要的原始参数,由调用它的主程序通过约定工作寄存器 R0~ R7、特殊功能寄存器 SFR、
内存单元或堆栈等预先传送给子程序使用;出口参数是由子程序根据入口参数执行程序后获得的结果参数,应由子程序通过约定的工作寄存器 R0~ R7、特殊功能寄存器 SFR、内存单元或堆栈等传递给主程序使用。
④ 为使所编子程序可以放在 64KB程序存储器的任何地方并能被主程序调用,子程序内容通常使用相对转移指令而不使用长转移指令,以便汇编时生成浮动代码。
例,在寄存器 R2中存放两位 16进制数,请编制程序将其分别转换为 ASCII码并且存入 M1单元和
M1+ 1单元。
ORG 2000H
M DATA 40H
MOV SP,#60H
MOV DPTR,#TAB1
PUSH 02H
ACALL ASCH
POP M1
MOV A,R2
SWAP A
PUSH ACC
ASCALL ASCH
POP M1+1
SJMP $
ASCH:DEC SP
DEC SP
POP ACC
ANL A,#0FH
MOVC A,@A+DPTR
PUSH ACC
INC SP
INC SP
RET
TAB1,DB ‘01234567’
DB ‘89ABCDEF’
END
例,设 AD1和 AD2单元内部有两个数 a和 b,请编制
c= a2+ b2的程序,并把 c送入 AD3单元。假设 a和
b均为小于 10的整数。
ORG 2000H
AD1 DATA 30H
AD2 DATA 31H
AD3 DATA 32H
MOV A,AD1
ACALL SQR
MOV AD3,A
MOV A,AD2
ACALL SQR
ADD A,AD3
MOV AD3,A
SJMP $
SQR:MOV B,A
MUL AB
RET
END