第四章 汇编语言程序设计
4-1 汇编程序的约定
4-2 程序设计步骤
4-3 直线程序
4-4 分支程序
4-5 循环程序
4-6 子程序
4-1 汇编程序约定汇编语言程序:
用汇编语言编写的,完成特定功能的指令序列。
汇编程序:
能将汇编语言 源程序 转换成机器语言 目标 程序的系统软件 。
汇编语言程序到机器语言程序的转换过程称为汇编。
1.手工汇编,人工查指令表汇编。用于设计短小程序或调试程序的场合。
2.机器汇编,用汇编程序进行汇编 。
源程序使用机器汇编要考虑汇编程序的约定
1) 按指令格式和语法规则编写程序。
常数的表示:
十进制数,20
十六进制数,87H,0F0H
二进制数,01011001B
字符,‘ H’
字符串:,Hello” 。
2) 使用伪指令提供汇编信息 。
汇编的主要任务:
1) 确定程序中每条汇编语言指令的指令机器码 。
2) 确定每条指令在存储器中的存放地址 。
3) 提供错误信息 。
4) 提供目标执行文件 ( *.OBJ/*.HEX)和列表文件
( *.LST) 。
一,汇编语言指令类型
1.机器指令,
指令系统中的全部指令,每条指令有对应的机器代码 。
2,伪指令,
汇编控制指令,仅提供汇编信息,没有指令代码 。
一,汇编语言指令类型
3,宏指令,
宏汇编功能:将需要多次反复执行的程序段定义成一个宏指令名(宏定义),编程时,可在程序中使用宏指令名来替代一段程序(宏调用)。
宏定义过程,
宏指令名 MACRO 形式参数
… ;定义程序段
ENDM
宏调用过程:
…
宏指令名 实际参数
…
宏指令名 实际参数二,汇编控制指令 (伪指令 )
常用伪指令及其功能:
1,ORG—起始地址指令:指明程序和数据块起始地址。
指令地址 机器码 源程序
ORG 2000H
2000H 78 30 MAIN,MOV R0,#30H
2002H E6 MOV A,@R0
…
ORG 3000H
3000H 23 DB 23H,100,‘A’
3001H 64
3002H 41
2,DB — 定义字节型常数指令 。
例,DB 12H,100,‘A’
4,EQU —等值。为标号或标识符赋值。
X1 EQU 2000H
X2 EQU 0FH
…
MAIN:MOV DPTR,#X1
ADD A,#X2
5,END —结束汇编指令。
例,START,…
…
END START
3,DW —定义字型常数指令 。
例,DW 1234H,5678H
4-2 汇编语言程序设计步骤一,确定方案和计算方法二,了解应用系统的硬件配置,性能指标 。
三,建立系统数学模型,确定控制算法和操作步骤 。
四,画程序流程图表示程序结构和程序功能五,编制源程序
1.合理分配存储器单元和了解 I/O接口地址。
2.按功能设计程序,明确各程序之间的相互关系。
3.用注释行说明程序,便于阅读和修改调试和修改。
开始
1
Y
N
常用程序结构,
直线程序、分支程序、循环程序、子程序
4-3 直线程序
直线程序又称简单程序,程序走向只有一条路径。
双字节变补程序 (设数据在 R4R5中 ):
MOV A,R5 ; 取低字节
CPL A
ADD A,#1 ; 低字节变补
MOV R5,A
MOV A,R4 ; 取高字节
CPL A
ADDC A,#0 ; 高字节变补
MOV R4,A
例 4-3-4 压缩式 BCD码分解成为单字节 BCD码。
MOV R0,#40H ; 设指针
MOV A,@R0 ; 取一个字节
MOV R2,A ; 暂存
ANL A,#0FH ; 清 0高半字节
INC R0
MOV @R0,A ; 保存数据个位
MOV A,R2
SWAP A ; 十位换到低半字节
ANL A,#0FH
INC R0
MOV @R0,A ; 保存数据十位片内 R A M
42H 0 十
41H 0 个
40H 十 个
4-4 分支程序由条件转移指令构成程序判断框部分,形成程序分支结构。
4-4-2 单重分支程序一个判断决策框,程序有两条出路。
两种分支结构:
条件满足?
N
影响条件
Y
处理段条件满足?
N
影响条件
Y
处理 1 处理 2
例 求 R2中补码绝对值,正数不变,
负数变补。
MOV A,R2
JNB ACC.7,NEXT; 为正数?
CPL A ; 负数变补
INC A
MOV R2,A
NEXT,SJMP NEXT ; 结束行李计价,当 G≤5,M=G× 3;
当 G> 5,M=G× 3+(G-5)× (5-3)
FRT,MOV A,40H ; 取行李重量计价单位 G
MOV R3,A
MOV B,#03H ; M=G× 3
MUL AB
MOV R2,A ;暂存 3G
MOV A,R3 ;取回 G
CJNE A,#05H,L1; G≤5?
SJMP WETC
L1,JC WETC ;是,转至 WETC
SUBB A,#05H ;否则 M=3G+2(G-5)
RLC A
ADD A,R2
WETC,MOV 41H,A ;存结果 M
RET
4-4-3 多重分支程序一.多次使用条件转移指令,形成两个以上判断框。
例 求符号函数 Y=SGN(X)
+1 当 X>0
SGN(X)= 0 当 X=0
-1 当 X<0
X= 0?
Y
取 X
N
Y= 0
Y= + 1
开始
Y=- 1
X< 0?
NY
保存 Y
结束图 4-4-4求符号函数流程图
SYMB,MOV A,40H ; 取 X
JZ STOR ; X=0,Y=X
JB ACC7,MINUS; X< 0
MOV A,# 1 ; X> 0,Y=+1
SJMP STOR
MINUS,MOV A,#0FFH; X< 0,Y= -1
STOR,MOV 41H,A ; 保存 Y
RET
二.按分支号转移如:分支号 =0,程序转移到 ADDR0处;当分支号 =1,
程序转移到 ADDR1处; … 。
(1)用地址表法。设分支号已存入 A。
MTJS,MOV DPTR,#TAB ; 取表首地址
CLR C ; 分支号× 2
RLC A
MOV R2,A
MOVC A,@ A+DPTR; 取分支地址低位
PUSH ACC ; 入栈保存
MOV A,R2
INC A
MOVC A,@ A+DPTR; 取分支地址高位
PUSH ACC ; 入栈保存
RET ; 分支地址 → PC,转移
TAB,DW ADDR0 ; 分支地址表
DW ADDR1
…
ADDR0,… ; 程序段 0 …
A =?
0
处理一处理二处理…
1 n
(2)转移表法。 用分支转移指令 JMP @A+DPTR。 设 R7R6=分支号
MTJS,MOV DPTR,#TAB; 指向表首地址
MOV A,R7 ; 分支号高字节× 3
MOV B,#03H
MUL AB ; 乘积不超过 1字节
ADD A,DPH
MOV DPH,A
MOV A,R6 ; 分支号低字节× 3
MOV B,#03H
MUL AB
XCH A,B
ADD A,DPH ; DPH←DPH+((R7,R6)× 3)高字节
MOV DPH,A
XCH A,B ; A←((R7,R6)× 3)低字节
JMP @ A+DPTR ; 实现多分支转移
TAB,LJMP ADDR0 ; 转移表
LJMP ADDR1
…
LJMP ADDRN
ADDR0,… ; 程序段 0 …
A+DPTR←TAB+R7R6 × 3
DPTR←TAB
JMP @A+DPTR
LJMP ROUT0 LJMP ROUT1 LJMP ROUTn
R6R7
3×
DPLDPH
A
+
4-5 循环程序包含多次重复执行的程序段,循环结构使程序紧凑。
4-5-1 循环程序的构成循环控制?
循环工作循环结束循环初始化
Y
N
各个环节任务:
一.初始化部分循环准备工作。如:清结果单元、
设指针、设循环控制变量初值等。
二.循环体循环工作部分:
需多次重复处理的工作。
循环控制部分:
1.修改指针和循环控制变量。
2.检测循环条件:满足循环条件,继续循环,否则退出循环。
三,结束部分处理和保存循环结果。
允许 0次循环的循环结构:在循环工作之前检测循环条件。
4-5-2 单重循环简单循环结构:循环体中不套循环。
例:求 n个单字节数据的累加,设数据串已在 43H起始单元,
数据串长度在 42H单元,累加和不超过 2个字节。
片内 R A M
X n
43H X1
42H n
41H SUM H
40H SUM L
SUM,MOV R0,#42H; 设指针
MOV A,@R0
MOV R2,A ; 循环计数器 ← n
CLR A ; 结果单元清 0
MOV R3,A
ADD1,INC R0 ; 修改指针
ADD A,@R0 ; 累加
JNC NEXT ; 处理进位
INC R3 ; 有进位,高字节加 1
NEXT,DJNZ R2,ADD1 ; 循环控制:数据是否加完?
MOV 40H,A ; 循环结束,保存结果
MOV 41H,R3
RET
循环控制方法:计数控制、特征标志控制。
一,计数控制:
设循环计数器,控制循环次数 。 正计数和倒计数两种方式 。
例:为一串 7位 ASCII码数据的 D7位加上奇校验,设数据存放在片外 RAM的 2101H起始单元,数据长度在 2100H单元 。 片外 R A M
2 1 0 2 H 0 1 1 0 1 0 0 0
2 1 0 1 H 0 0 1 0 1 1 0 1
2 1 0 0 H n
MOV DPTR,#2100H
MOVX A,@DPTR
MOV R2,A
NEXT,INC DPTR
MOVX A,@DPTR
ORL A,#80H
JNB P,PASS
MOVX @DPTR,A
PASS,DJNZ R2,NEXT
DONE,SJMP DONE
二,特征控制:设定循环结束标志实现循环控制。
例:找正数表最小值。正数表存在片外 RAM中以 LIST为起始单元,用 -1作为结束标志。
START,MOV DPTR,#LIST ; 数表首地址
MOV B,#127 ; 预置最小值
NEXT,MOVX A,@DPTR ; 取数
INC DPTR ; 修改指针
CJNE A,#-1,NEXT1; 是否为数表结尾?
SJMP DONE ; 循环结束
NEXT1,CJNE A,B,NEXT2 ; 比较
NEXT2,JNC NEXT
MOV B,A ; 保存较小值
SJMP NEXT
DONE,SJMP DONE
习题 统计一班考试为 100分和不及格人数,成绩单在 41H起始单元。
4-5-3 多重循环循环体中套循环结构。以双重循环使用较多。
例 将内存一串单字节无符号数升序排序。
步骤,
每次取相邻单元的两个数比较,决定是否需要交换数据位置。
第一次循环,比较 N-1次,取到数据表中最大值。
第二次循环,比较 N-2次,取到次大值。
…
第 N-1次循环:比较一次,排序结束。
片内 R A M
M A X
5
2
4
1
T A B → 3
内循环控制?
循环工作循环结束外循环控制?
内循环初始化开始外循环初始化
SORT,MOV A,#N-1 ; N个数据排序
MOV R4,A ; 外循环次数
LOOP1,MOV A,R4
MOV R3,A ; 内循环次数
MOV R0,#TAB ; 设数据指针
LOOP2,MOV A,@R0 ; 取二数
MOV B,A
INC R0
MOV A,@R0
CJNE A,B,L1 ; 比较
L1,JNC UNEX ; A≥B,不交换
DEC R0 ; 否则交换数据
XCH A,@R0
INC R0
MOV @R0,A
UNEX,DJNZ R3,LOOP2 ; 内循环结束?
DJNZ R4,LOOP1 ; 外循环结束?
RET
R3←R3 —1=0?
B ← ( R0)
A← ( R0 + 1 )
循环结束外循环次数 → R4
R4←R4 —1=0?
内循环次数 → R3
表首 TAB→R0
开始
A ≥ B?
(R0)←→(R0+1)
R0 ← R0+1
Y
N
软件延时程序。
用循环程序将指令重复多次执行,实现软件延时。
试计算延时程序的执行时间。
源程序 指令周期 (M) 指令执行次数习题
DELAY,MOV R6,#100 1
D1,MOV R7,#10 1
D2,NOP 1
DJNZ R7,D2 2
DJNZ R6,D1 2
RET 2
计算延时程序的执行时间 (设时钟 f=6MHz,M=1μ s)。
DELAY,MOV R6,#64H 1
I1,MOV R7,#0FFH 1
I2,DJNZ R7,I2 2
DJNZ R6,I1 2
RET 2
延时时间计算:(设时钟 f=12MHz)
t=(1× 1+1× 100+2× 100× 255+2× 100+2× 1)× M=51.3 ms
1
100
100× 255
100
1
4-6 子程序子程序:能完成某项特定功能的独立程序段,可被反复调用。
4-6-1 子程序设计一,子程序入口用标号作为子程序名 。
二,调用子程序之前设置好堆栈 。
三,用返回指令 RET结束子程序,并保证堆栈栈顶为调用程序的返回地址 。
四,子程序嵌套须考虑堆栈容量 。
五,提供足够的调用信息,
如:子程序名,子程序功能,入口参数和出口参数,子程序占用的硬件资源,子程序中调用的其他子程序名 。
主程序
C AL L S
C AL L S
子程序 S
R E T
4-6-4 子程序的类型按子程序与主程序之间传递参数的方式分类。
入口参数:调用子程序之前,需要传给子程序的参数 。
出口参数:子程序送回调用程序的结果参数 。
选用不同的参数传递方式 。
1.寄存器传送参数
2.存储器传送参数
3.堆栈传送参数设计子程序应满足通用性的要求,不针对具体数据编程。
如,1.子程序功能为求单字节数的立方:
A?A3,入口参数和出口参数为 A。
2.子程序功能为求单字节数的 n次方:
(41H)(42H)?(40H)A,入口参数为 (40H)和 A,
出口参数为 (42H)(41H)。
例:将 R4R5R6中三个字节数据对半分解,变成 6个字节,
存入显示缓冲区 (DISMEM0~ DISMEM5)。
1)子程序 UFOR1的功能:将 A累加器中单字节数据,对半分解成两个字节,存入 R0所指向的相邻两个单元
UFOR1,MOV @R0,#0
XCHD A,@R0 ; 保存低半字节
INC R0 ; 修改指针
MOV @R0,#0
SWAP A
XCHD A,@R0 ; 保存高半字节
RET
2)调用子程序 UFOR1之前,将待分解的内容送 A,存放地址送 R0。
R A M
R 0 + 1 → 0 A H
R0 → 0 A L
LED 数码管
5 4 3 2 1 0
R AM 显示缓冲区地址 数据
DI S M E M 5 0 R6 H
DI S M E M 4 0 R6 L
DI S M E M 3 0 R5 H
DI S M E M 2 0 R5 L
DI S M E M 1 0 R4 H
DI S M E M 0 0 R4 L
例 比较两个数据串是否完全相等,若完全相等,A=0;
否则 A=FFH。
PMT,MOV R2,A ; 设数串长度
CHC,MOV A,@R0 ; 各取数串中的一个数
MOV 42H,@R1
CJNE A,42H,NOM ; 是否相等?不相等转移
INC R0 ; 相等,修改指针
INC R1
DJNZ R2,CHC ; 全部比较完?
MOV A,#0 ; 完全相等
SJMP PEND
NOM,MOV A,#0FFH ; 不完全相等
PEND,RET
例,查表求出数据的 ASCII码,再以字符形式输出。
1)子程序 HEXASC功能:取出堆栈中数据,查表将低半字节转换成 ASCII码送累加器 A。
2)分别将待转换数据入栈,然后调用子程序 HEXASC。
33H
32H
31H
30H ×
RAM
41H 23
40H 01
MOV SP,#30H
PUSH 40H ; 入口参数入栈
LCALL HEXASC
POP A…
HEXASC,DEC SP ; 跳过返回地址
DEC SP
POP A ; 取入口参数
… ;查表求 ASCII码
PUSH A ; 保存出口参数
INC SP ; 指向返回地址
INC SP
RET
DB ‘0’,‘1’,… ; ASCII码表
4-7 算术运算程序
4-7-1 多字节加减运算程序
1.多字节加法子程序,Z=X+Y。
ADDS,CLR C
LOOP,MOV A,@R0
ADDC A,@R1 ; 加一字节
MOV @R0,A ; 存和一字节
INC R0 ; 修改指针
INC R1
DJNZ R2,LOOP ; 全部字节加完?
RET
Y H
R1 → Y L
X H
R0 → X L
习题 1编写十进制多字节加法子程序,Z=X+Y。
习题 2编写多字节减法子程序,Z=X-Y。
思考题 修改程序使运算结果保存到其他存储单元。
4-7-2 多字节无符号数乘除运算相加计算多字节乘法程序,步骤:
1.部分积清零。
2.检测乘数各位,
为 1则部分积对位加被乘数,否则加 0。
3.对位方法:被乘数左移或部分积右移。
初值,0 0~ 0
Cy R4R5 右移 R6R7并检测 Cy
+ R2R3 当 Cy=1
Cy R4R5 得部分积并右移对位乘积最后右移一次
110
× 101
110
000
+ 110
11110
例,双字节相乘 R2R3× R6R7?R4R5R6R7
解,部分积清零,右移检测乘数,决定部分积是否加被乘数,部分积右移对位。
循环
16
次相减计算多字节除法程序,步骤:
1.对齐高位被除数试减除数。
2.若够减商上 1,不够减商上 0且恢复余数。
3.余数左移或除数右移对位。
4.循环重复前 3步,直至取够相应位数的商。
例 R2R3R4R5÷ R6R7?R4R5 (余数?R2R3)
解 1.判断 R2R3< R6R7? 使商不大于 16位。
2.被除数左移 1位,试减除数。
3.若够减,商加 1并保留余数。
10111
0101/ 011101100101
01000101
10010101
10010101
10000101
011
Cy←R2R3←R4R5←0
- R6R7 + 1 够减
R2R3 不够减恢复余数循环
16
次
4-7-3 代码转换程序
(一 )十六进制数转换为 ASCII码
(二 )ASCII码转换为十六进制数
0~ 9的 ASCII码,30~ 39H,A~ F的 ASCII码,41~ 46H。
HASC,CJNE A,#0AH,N AHEX,CLR C
N,JNC N1 SUBB A,#30H
ADD A,#30H CJNE A,#0AH,N
SJMP SE N,JC N1
N1,ADD A,#37H SJMP AE
SE,RET N1,SUBB A,#11H
CJNE A,#06H,N2
N2,JNC ERR
ADD A,#0AH
SJMP AE
ERR,MOV A,#0FFH
AE,RET
(三 )BCD码与二进制数之间的转换有乘法和除法两种转换方式 。
1,BCD码转换为二进制数
D = dn-1× 10n-1+dn-2× 10n-2+…+d 1× 101+d0× 100
=((( dn-1× 10+dn-2 )× 10 +dn-3 )× 10 +… d 1) × 10+ d0
“整数十翻二”:从最高位开始,按二进制运算法则循环
“乘十加次低位”,B=B× 10+bi 。
R3←0 R4←0
10×
R3 R4
+ (R0)
R3 R4
R0←R0+1
2.二进制数转换为 BCD码
B = bn-1× 2n-1 + bn-2× 2n-2 + … + b 1× 21 + b0× 20
=((( bn-1× 2 + bn-2 )× 2 + bn-3 )× 2 + …b 1)+ b0
“整数二翻十”:从最高位开始,按十进制运算法则循环“乘二加次低位”,D=D× 2+di 。
除法转换式:
bn-1× 2n-1 + bn-2× 2n-2+ …+b0 = dm-1× 10m-1 + dm-2× 10m-2+ …+d0
两边同时除基数,两边的整数或小数应该分别相等 。
除基数,取出 1位余数,得到的商继续除基数取余数 。 循环
,除基取余,操作,得到转换进制的各位系数 。
编程习题要求
1.为程序标明必要注释。
2.上机调试通过。
3.给出程序执行前设定的数据,并记录程序执行后的结果数据。
4.要求写明数据的存储单元
4-1 汇编程序的约定
4-2 程序设计步骤
4-3 直线程序
4-4 分支程序
4-5 循环程序
4-6 子程序
4-1 汇编程序约定汇编语言程序:
用汇编语言编写的,完成特定功能的指令序列。
汇编程序:
能将汇编语言 源程序 转换成机器语言 目标 程序的系统软件 。
汇编语言程序到机器语言程序的转换过程称为汇编。
1.手工汇编,人工查指令表汇编。用于设计短小程序或调试程序的场合。
2.机器汇编,用汇编程序进行汇编 。
源程序使用机器汇编要考虑汇编程序的约定
1) 按指令格式和语法规则编写程序。
常数的表示:
十进制数,20
十六进制数,87H,0F0H
二进制数,01011001B
字符,‘ H’
字符串:,Hello” 。
2) 使用伪指令提供汇编信息 。
汇编的主要任务:
1) 确定程序中每条汇编语言指令的指令机器码 。
2) 确定每条指令在存储器中的存放地址 。
3) 提供错误信息 。
4) 提供目标执行文件 ( *.OBJ/*.HEX)和列表文件
( *.LST) 。
一,汇编语言指令类型
1.机器指令,
指令系统中的全部指令,每条指令有对应的机器代码 。
2,伪指令,
汇编控制指令,仅提供汇编信息,没有指令代码 。
一,汇编语言指令类型
3,宏指令,
宏汇编功能:将需要多次反复执行的程序段定义成一个宏指令名(宏定义),编程时,可在程序中使用宏指令名来替代一段程序(宏调用)。
宏定义过程,
宏指令名 MACRO 形式参数
… ;定义程序段
ENDM
宏调用过程:
…
宏指令名 实际参数
…
宏指令名 实际参数二,汇编控制指令 (伪指令 )
常用伪指令及其功能:
1,ORG—起始地址指令:指明程序和数据块起始地址。
指令地址 机器码 源程序
ORG 2000H
2000H 78 30 MAIN,MOV R0,#30H
2002H E6 MOV A,@R0
…
ORG 3000H
3000H 23 DB 23H,100,‘A’
3001H 64
3002H 41
2,DB — 定义字节型常数指令 。
例,DB 12H,100,‘A’
4,EQU —等值。为标号或标识符赋值。
X1 EQU 2000H
X2 EQU 0FH
…
MAIN:MOV DPTR,#X1
ADD A,#X2
5,END —结束汇编指令。
例,START,…
…
END START
3,DW —定义字型常数指令 。
例,DW 1234H,5678H
4-2 汇编语言程序设计步骤一,确定方案和计算方法二,了解应用系统的硬件配置,性能指标 。
三,建立系统数学模型,确定控制算法和操作步骤 。
四,画程序流程图表示程序结构和程序功能五,编制源程序
1.合理分配存储器单元和了解 I/O接口地址。
2.按功能设计程序,明确各程序之间的相互关系。
3.用注释行说明程序,便于阅读和修改调试和修改。
开始
1
Y
N
常用程序结构,
直线程序、分支程序、循环程序、子程序
4-3 直线程序
直线程序又称简单程序,程序走向只有一条路径。
双字节变补程序 (设数据在 R4R5中 ):
MOV A,R5 ; 取低字节
CPL A
ADD A,#1 ; 低字节变补
MOV R5,A
MOV A,R4 ; 取高字节
CPL A
ADDC A,#0 ; 高字节变补
MOV R4,A
例 4-3-4 压缩式 BCD码分解成为单字节 BCD码。
MOV R0,#40H ; 设指针
MOV A,@R0 ; 取一个字节
MOV R2,A ; 暂存
ANL A,#0FH ; 清 0高半字节
INC R0
MOV @R0,A ; 保存数据个位
MOV A,R2
SWAP A ; 十位换到低半字节
ANL A,#0FH
INC R0
MOV @R0,A ; 保存数据十位片内 R A M
42H 0 十
41H 0 个
40H 十 个
4-4 分支程序由条件转移指令构成程序判断框部分,形成程序分支结构。
4-4-2 单重分支程序一个判断决策框,程序有两条出路。
两种分支结构:
条件满足?
N
影响条件
Y
处理段条件满足?
N
影响条件
Y
处理 1 处理 2
例 求 R2中补码绝对值,正数不变,
负数变补。
MOV A,R2
JNB ACC.7,NEXT; 为正数?
CPL A ; 负数变补
INC A
MOV R2,A
NEXT,SJMP NEXT ; 结束行李计价,当 G≤5,M=G× 3;
当 G> 5,M=G× 3+(G-5)× (5-3)
FRT,MOV A,40H ; 取行李重量计价单位 G
MOV R3,A
MOV B,#03H ; M=G× 3
MUL AB
MOV R2,A ;暂存 3G
MOV A,R3 ;取回 G
CJNE A,#05H,L1; G≤5?
SJMP WETC
L1,JC WETC ;是,转至 WETC
SUBB A,#05H ;否则 M=3G+2(G-5)
RLC A
ADD A,R2
WETC,MOV 41H,A ;存结果 M
RET
4-4-3 多重分支程序一.多次使用条件转移指令,形成两个以上判断框。
例 求符号函数 Y=SGN(X)
+1 当 X>0
SGN(X)= 0 当 X=0
-1 当 X<0
X= 0?
Y
取 X
N
Y= 0
Y= + 1
开始
Y=- 1
X< 0?
NY
保存 Y
结束图 4-4-4求符号函数流程图
SYMB,MOV A,40H ; 取 X
JZ STOR ; X=0,Y=X
JB ACC7,MINUS; X< 0
MOV A,# 1 ; X> 0,Y=+1
SJMP STOR
MINUS,MOV A,#0FFH; X< 0,Y= -1
STOR,MOV 41H,A ; 保存 Y
RET
二.按分支号转移如:分支号 =0,程序转移到 ADDR0处;当分支号 =1,
程序转移到 ADDR1处; … 。
(1)用地址表法。设分支号已存入 A。
MTJS,MOV DPTR,#TAB ; 取表首地址
CLR C ; 分支号× 2
RLC A
MOV R2,A
MOVC A,@ A+DPTR; 取分支地址低位
PUSH ACC ; 入栈保存
MOV A,R2
INC A
MOVC A,@ A+DPTR; 取分支地址高位
PUSH ACC ; 入栈保存
RET ; 分支地址 → PC,转移
TAB,DW ADDR0 ; 分支地址表
DW ADDR1
…
ADDR0,… ; 程序段 0 …
A =?
0
处理一处理二处理…
1 n
(2)转移表法。 用分支转移指令 JMP @A+DPTR。 设 R7R6=分支号
MTJS,MOV DPTR,#TAB; 指向表首地址
MOV A,R7 ; 分支号高字节× 3
MOV B,#03H
MUL AB ; 乘积不超过 1字节
ADD A,DPH
MOV DPH,A
MOV A,R6 ; 分支号低字节× 3
MOV B,#03H
MUL AB
XCH A,B
ADD A,DPH ; DPH←DPH+((R7,R6)× 3)高字节
MOV DPH,A
XCH A,B ; A←((R7,R6)× 3)低字节
JMP @ A+DPTR ; 实现多分支转移
TAB,LJMP ADDR0 ; 转移表
LJMP ADDR1
…
LJMP ADDRN
ADDR0,… ; 程序段 0 …
A+DPTR←TAB+R7R6 × 3
DPTR←TAB
JMP @A+DPTR
LJMP ROUT0 LJMP ROUT1 LJMP ROUTn
R6R7
3×
DPLDPH
A
+
4-5 循环程序包含多次重复执行的程序段,循环结构使程序紧凑。
4-5-1 循环程序的构成循环控制?
循环工作循环结束循环初始化
Y
N
各个环节任务:
一.初始化部分循环准备工作。如:清结果单元、
设指针、设循环控制变量初值等。
二.循环体循环工作部分:
需多次重复处理的工作。
循环控制部分:
1.修改指针和循环控制变量。
2.检测循环条件:满足循环条件,继续循环,否则退出循环。
三,结束部分处理和保存循环结果。
允许 0次循环的循环结构:在循环工作之前检测循环条件。
4-5-2 单重循环简单循环结构:循环体中不套循环。
例:求 n个单字节数据的累加,设数据串已在 43H起始单元,
数据串长度在 42H单元,累加和不超过 2个字节。
片内 R A M
X n
43H X1
42H n
41H SUM H
40H SUM L
SUM,MOV R0,#42H; 设指针
MOV A,@R0
MOV R2,A ; 循环计数器 ← n
CLR A ; 结果单元清 0
MOV R3,A
ADD1,INC R0 ; 修改指针
ADD A,@R0 ; 累加
JNC NEXT ; 处理进位
INC R3 ; 有进位,高字节加 1
NEXT,DJNZ R2,ADD1 ; 循环控制:数据是否加完?
MOV 40H,A ; 循环结束,保存结果
MOV 41H,R3
RET
循环控制方法:计数控制、特征标志控制。
一,计数控制:
设循环计数器,控制循环次数 。 正计数和倒计数两种方式 。
例:为一串 7位 ASCII码数据的 D7位加上奇校验,设数据存放在片外 RAM的 2101H起始单元,数据长度在 2100H单元 。 片外 R A M
2 1 0 2 H 0 1 1 0 1 0 0 0
2 1 0 1 H 0 0 1 0 1 1 0 1
2 1 0 0 H n
MOV DPTR,#2100H
MOVX A,@DPTR
MOV R2,A
NEXT,INC DPTR
MOVX A,@DPTR
ORL A,#80H
JNB P,PASS
MOVX @DPTR,A
PASS,DJNZ R2,NEXT
DONE,SJMP DONE
二,特征控制:设定循环结束标志实现循环控制。
例:找正数表最小值。正数表存在片外 RAM中以 LIST为起始单元,用 -1作为结束标志。
START,MOV DPTR,#LIST ; 数表首地址
MOV B,#127 ; 预置最小值
NEXT,MOVX A,@DPTR ; 取数
INC DPTR ; 修改指针
CJNE A,#-1,NEXT1; 是否为数表结尾?
SJMP DONE ; 循环结束
NEXT1,CJNE A,B,NEXT2 ; 比较
NEXT2,JNC NEXT
MOV B,A ; 保存较小值
SJMP NEXT
DONE,SJMP DONE
习题 统计一班考试为 100分和不及格人数,成绩单在 41H起始单元。
4-5-3 多重循环循环体中套循环结构。以双重循环使用较多。
例 将内存一串单字节无符号数升序排序。
步骤,
每次取相邻单元的两个数比较,决定是否需要交换数据位置。
第一次循环,比较 N-1次,取到数据表中最大值。
第二次循环,比较 N-2次,取到次大值。
…
第 N-1次循环:比较一次,排序结束。
片内 R A M
M A X
5
2
4
1
T A B → 3
内循环控制?
循环工作循环结束外循环控制?
内循环初始化开始外循环初始化
SORT,MOV A,#N-1 ; N个数据排序
MOV R4,A ; 外循环次数
LOOP1,MOV A,R4
MOV R3,A ; 内循环次数
MOV R0,#TAB ; 设数据指针
LOOP2,MOV A,@R0 ; 取二数
MOV B,A
INC R0
MOV A,@R0
CJNE A,B,L1 ; 比较
L1,JNC UNEX ; A≥B,不交换
DEC R0 ; 否则交换数据
XCH A,@R0
INC R0
MOV @R0,A
UNEX,DJNZ R3,LOOP2 ; 内循环结束?
DJNZ R4,LOOP1 ; 外循环结束?
RET
R3←R3 —1=0?
B ← ( R0)
A← ( R0 + 1 )
循环结束外循环次数 → R4
R4←R4 —1=0?
内循环次数 → R3
表首 TAB→R0
开始
A ≥ B?
(R0)←→(R0+1)
R0 ← R0+1
Y
N
软件延时程序。
用循环程序将指令重复多次执行,实现软件延时。
试计算延时程序的执行时间。
源程序 指令周期 (M) 指令执行次数习题
DELAY,MOV R6,#100 1
D1,MOV R7,#10 1
D2,NOP 1
DJNZ R7,D2 2
DJNZ R6,D1 2
RET 2
计算延时程序的执行时间 (设时钟 f=6MHz,M=1μ s)。
DELAY,MOV R6,#64H 1
I1,MOV R7,#0FFH 1
I2,DJNZ R7,I2 2
DJNZ R6,I1 2
RET 2
延时时间计算:(设时钟 f=12MHz)
t=(1× 1+1× 100+2× 100× 255+2× 100+2× 1)× M=51.3 ms
1
100
100× 255
100
1
4-6 子程序子程序:能完成某项特定功能的独立程序段,可被反复调用。
4-6-1 子程序设计一,子程序入口用标号作为子程序名 。
二,调用子程序之前设置好堆栈 。
三,用返回指令 RET结束子程序,并保证堆栈栈顶为调用程序的返回地址 。
四,子程序嵌套须考虑堆栈容量 。
五,提供足够的调用信息,
如:子程序名,子程序功能,入口参数和出口参数,子程序占用的硬件资源,子程序中调用的其他子程序名 。
主程序
C AL L S
C AL L S
子程序 S
R E T
4-6-4 子程序的类型按子程序与主程序之间传递参数的方式分类。
入口参数:调用子程序之前,需要传给子程序的参数 。
出口参数:子程序送回调用程序的结果参数 。
选用不同的参数传递方式 。
1.寄存器传送参数
2.存储器传送参数
3.堆栈传送参数设计子程序应满足通用性的要求,不针对具体数据编程。
如,1.子程序功能为求单字节数的立方:
A?A3,入口参数和出口参数为 A。
2.子程序功能为求单字节数的 n次方:
(41H)(42H)?(40H)A,入口参数为 (40H)和 A,
出口参数为 (42H)(41H)。
例:将 R4R5R6中三个字节数据对半分解,变成 6个字节,
存入显示缓冲区 (DISMEM0~ DISMEM5)。
1)子程序 UFOR1的功能:将 A累加器中单字节数据,对半分解成两个字节,存入 R0所指向的相邻两个单元
UFOR1,MOV @R0,#0
XCHD A,@R0 ; 保存低半字节
INC R0 ; 修改指针
MOV @R0,#0
SWAP A
XCHD A,@R0 ; 保存高半字节
RET
2)调用子程序 UFOR1之前,将待分解的内容送 A,存放地址送 R0。
R A M
R 0 + 1 → 0 A H
R0 → 0 A L
LED 数码管
5 4 3 2 1 0
R AM 显示缓冲区地址 数据
DI S M E M 5 0 R6 H
DI S M E M 4 0 R6 L
DI S M E M 3 0 R5 H
DI S M E M 2 0 R5 L
DI S M E M 1 0 R4 H
DI S M E M 0 0 R4 L
例 比较两个数据串是否完全相等,若完全相等,A=0;
否则 A=FFH。
PMT,MOV R2,A ; 设数串长度
CHC,MOV A,@R0 ; 各取数串中的一个数
MOV 42H,@R1
CJNE A,42H,NOM ; 是否相等?不相等转移
INC R0 ; 相等,修改指针
INC R1
DJNZ R2,CHC ; 全部比较完?
MOV A,#0 ; 完全相等
SJMP PEND
NOM,MOV A,#0FFH ; 不完全相等
PEND,RET
例,查表求出数据的 ASCII码,再以字符形式输出。
1)子程序 HEXASC功能:取出堆栈中数据,查表将低半字节转换成 ASCII码送累加器 A。
2)分别将待转换数据入栈,然后调用子程序 HEXASC。
33H
32H
31H
30H ×
RAM
41H 23
40H 01
MOV SP,#30H
PUSH 40H ; 入口参数入栈
LCALL HEXASC
POP A…
HEXASC,DEC SP ; 跳过返回地址
DEC SP
POP A ; 取入口参数
… ;查表求 ASCII码
PUSH A ; 保存出口参数
INC SP ; 指向返回地址
INC SP
RET
DB ‘0’,‘1’,… ; ASCII码表
4-7 算术运算程序
4-7-1 多字节加减运算程序
1.多字节加法子程序,Z=X+Y。
ADDS,CLR C
LOOP,MOV A,@R0
ADDC A,@R1 ; 加一字节
MOV @R0,A ; 存和一字节
INC R0 ; 修改指针
INC R1
DJNZ R2,LOOP ; 全部字节加完?
RET
Y H
R1 → Y L
X H
R0 → X L
习题 1编写十进制多字节加法子程序,Z=X+Y。
习题 2编写多字节减法子程序,Z=X-Y。
思考题 修改程序使运算结果保存到其他存储单元。
4-7-2 多字节无符号数乘除运算相加计算多字节乘法程序,步骤:
1.部分积清零。
2.检测乘数各位,
为 1则部分积对位加被乘数,否则加 0。
3.对位方法:被乘数左移或部分积右移。
初值,0 0~ 0
Cy R4R5 右移 R6R7并检测 Cy
+ R2R3 当 Cy=1
Cy R4R5 得部分积并右移对位乘积最后右移一次
110
× 101
110
000
+ 110
11110
例,双字节相乘 R2R3× R6R7?R4R5R6R7
解,部分积清零,右移检测乘数,决定部分积是否加被乘数,部分积右移对位。
循环
16
次相减计算多字节除法程序,步骤:
1.对齐高位被除数试减除数。
2.若够减商上 1,不够减商上 0且恢复余数。
3.余数左移或除数右移对位。
4.循环重复前 3步,直至取够相应位数的商。
例 R2R3R4R5÷ R6R7?R4R5 (余数?R2R3)
解 1.判断 R2R3< R6R7? 使商不大于 16位。
2.被除数左移 1位,试减除数。
3.若够减,商加 1并保留余数。
10111
0101/ 011101100101
01000101
10010101
10010101
10000101
011
Cy←R2R3←R4R5←0
- R6R7 + 1 够减
R2R3 不够减恢复余数循环
16
次
4-7-3 代码转换程序
(一 )十六进制数转换为 ASCII码
(二 )ASCII码转换为十六进制数
0~ 9的 ASCII码,30~ 39H,A~ F的 ASCII码,41~ 46H。
HASC,CJNE A,#0AH,N AHEX,CLR C
N,JNC N1 SUBB A,#30H
ADD A,#30H CJNE A,#0AH,N
SJMP SE N,JC N1
N1,ADD A,#37H SJMP AE
SE,RET N1,SUBB A,#11H
CJNE A,#06H,N2
N2,JNC ERR
ADD A,#0AH
SJMP AE
ERR,MOV A,#0FFH
AE,RET
(三 )BCD码与二进制数之间的转换有乘法和除法两种转换方式 。
1,BCD码转换为二进制数
D = dn-1× 10n-1+dn-2× 10n-2+…+d 1× 101+d0× 100
=((( dn-1× 10+dn-2 )× 10 +dn-3 )× 10 +… d 1) × 10+ d0
“整数十翻二”:从最高位开始,按二进制运算法则循环
“乘十加次低位”,B=B× 10+bi 。
R3←0 R4←0
10×
R3 R4
+ (R0)
R3 R4
R0←R0+1
2.二进制数转换为 BCD码
B = bn-1× 2n-1 + bn-2× 2n-2 + … + b 1× 21 + b0× 20
=((( bn-1× 2 + bn-2 )× 2 + bn-3 )× 2 + …b 1)+ b0
“整数二翻十”:从最高位开始,按十进制运算法则循环“乘二加次低位”,D=D× 2+di 。
除法转换式:
bn-1× 2n-1 + bn-2× 2n-2+ …+b0 = dm-1× 10m-1 + dm-2× 10m-2+ …+d0
两边同时除基数,两边的整数或小数应该分别相等 。
除基数,取出 1位余数,得到的商继续除基数取余数 。 循环
,除基取余,操作,得到转换进制的各位系数 。
编程习题要求
1.为程序标明必要注释。
2.上机调试通过。
3.给出程序执行前设定的数据,并记录程序执行后的结果数据。
4.要求写明数据的存储单元