指令系统是熟悉单片机功能、合理应用单片机的基础。掌握单片机指令的关键在于多看 多练,多上机练习,然后在现有程序的基础上进行模仿性编程。
汇编语言程序有 4 种结构形式,即顺序结构、分支结构、循环结构和子程序结构。下面 举例说明这 4 种程序结构及编程方法。
3.8.1 顺序结构程序设计
把 8000H 地址上的内容拆开,高位送 8001H 地址的低位,低位送 8002H 地址的低位,
8001H、8002H 地址的高位清零。本程序通常在把数据送显示缓冲区时使用。
程序流程图如图 3-1 所示,程序清单如下:
图 3-1 程序流程图
ORG 0000H
MOV DPTR,#8000H ;指定的字节 MOVX A,@DPTR
MOV B,A ;暂存
SWAP A ;交换
ANL A,#0FH ;屏敝高位 INC DPTR
MOVX @DPTR,A INC DPTR
MOV A,B
ANL A,#0FH ;指定字节的内容屏敝高位 MOVX @DPTR,A
LOOP: SJMP LOOP END 案例 5 拼字程序
把 8000H、8001H 两个字节的低位分别送入 8002H 的高位和低位。本程序一般用于把显 示缓冲区中的数据取出拼装成一个字节。
程序流程图如图 3-2 所示,程序清单如下:
ORG 0000H MOV DPTR,#8000H MOVX A,@DPTR
ANL A,#0FH ;屏敝高位 SWAP A
MOV B,A ;保存 INC DPTR
MOVX A,@DPTR ANL A,#0FH
ORL A,B ;合并
INC DPTR
MOVX @DPTR,A ;送 8002H 存放 LOOP: SJMP LOOP
END
图 3-2 程序流程图 案例 6 查表程序
求 R1 中的数(0~15 之间)平方,结果仍放回到 R1 中。
查表是计算机解决复杂问题所采取的一种简单而有效的方法。它根据变量 x 的值,在表 格中查找 y,使 y=f(x)。由于查表程序结构简单,执行速度快,因而广泛应用于数值计算、转 换、补偿、显示、打印等功能程序中。
设计查表程序的关键是善于组织表格,使其具有一定的规律性,便于编程查找。程序清 单(采用 DPTR 当基址寄存器)如下:
ORG 0100H
TAB2: PUSH DPH ;保存 DPTR 的原值 PUSH DPL
MOV DPTR, #TAB ;取平方表首地址 MOV A, R1
MOVC A, @A+DPTR ;查平方表 MOV R1, A
POP DPL ;恢复 DPTR 的原值 POP DPH
TAB: DB 0,1,4,9,16,25,39 ;平方表 DB 49,64,81,100,121 ;续表 DB 144,169,196,225 ;续表
为了保护调用程序中 DPTR 的值,在子程序中可以用堆栈进行保护,子程序返回之前应 正确恢复。
3.8.2 分支结构程序设计
程序分支是通过条件转移指令实现的,即根据条件对程序的执行进行判断,满足条件则 进行程序转移,不满足条件则顺序执行程序。
案例 7 无符号数的比较(单分支结构)
比较外部 RAM 的 Data1 和 Data2 单元的两个无符号数,并将大数存入 Data3 单元(Data1、
Data2、Data3 为 3 个连续的单元)。
解:该问题属于单分支结构,程序流程图如图 3-3 所示,程序清单如下:
图 3-3 无符号数的比较
ORG 1000H
COM1: MOV DPTR,#DATA1 ;设置外部数据存储器指针 MOV A,@DPTR ;取第一个数
MOV B,A ;暂存第一个数到 B
INC DPTR ;修改指针,指向第二个数所在的单元 MOVX A,@DPTR ;取第二个数到 A
CJNE A,B,L1 ;两数比较,产生 Cy 标志
L1: JC BIG1 ;若第二个数小于第一个数,则转向 BIG1;修改
;指针,指向 Data3 单元 BIG: INC DPTR
MOVX @DPTR,A ;存大数 RET
BIG1: XCH A,B ;将大数转移到 A SJMP BIG
END
案例 8 码制转换(双分支结构程序)
将 R2 中的一位十六进制数转换为 ASCII 码,结果仍放在 R2 中。
解:查 ASCII 码表可知数字 0~9 的 ASCII 码分别是 30H~39H;英文大写字母 A~F 的 ASCII 码分别是 41H~46H。可见该十六进制数若<10,要转换为 ASCII 码应加 30H;若≥10,
则加 37H。
该问题属于双分支结构,程序流程图如图 3-4 所示,程序清单如下:
图 3-4 十六进制数转换为 ASCII 码
ORG 0000H
HEXASC: MOV A, R2 ;将该十六进制数暂存于 A 中 CJNE A, #0AH, L1
L1: JNC ADD_37 ;判断是否小于 0AH ADD_30: ADD A, #30H ;小于 0AH,则加 30H
MOV R2, A ;保存结果
RET ;子程序返回
ADD_37: ADD A, #37H ;大于或等于 0AH,则加 37H MOV R2, A ;保存结果
RET
该程序使用了两个子程序返回指令,这也是双分支程序的一个特点。
案例 9 带符号数的比较(多分支结构程序)
比较内部 RAM 的 Data1 和 Data2 单元内以补码形式表示的两个带符号数,并将大数存入
BIG 单元,小数存入 SMALL 单元;若两数相等,则建立起标志位 F0。
解:要比较两个带符号数,不能依据 Cy 标志位判定其大小,其判定方法为:
(1)若 X、Y 两数符号相同,且(X-Y)为正,表明 X>Y。
(2)若 X、Y 两数符号不同,则根据符号判定大小。
程序流程图如图 3-5 所示,程序清单如下:
图 3-5 比较两个带符号数
DATA1 EQU 40H DATA2 EQU 41H BIG EQU 30H SMALL EQU 31H ORG 0000H COM2: MOV A, 40H
XRL A, 41H
JNZ STEP1 ;两数不等,转 STEP1 SETB F0 ;两数相等,F0 置位 RET
STEP1: JB ACC.7, TEST ;两数异号,转 TEST XRL A, 41H ;恢复 40H
SUBB A, 41H ;比较
JB ACC.7, STEP3 ;40H 小,转 STEP3 STEP2: MOV BIG, 40H
MOV SMALL, 41H RET
TEST: XRL A, 41H
JNB ACC.7, STEP2 ;40H 为正,转 STEP2 STEP3: MOV SMALL, 40H
MOV BIG, 41H
NEXT: INC R0 ;指向下一个数据单元 MOV A, @R0 ;取当前数据
CJNE A, Data2, COMP ;比较当前数与当前最大数
COMP: JC CON ;若当前数小于当前最大数,则继续 MOV Data2, A ;否则,把当前数当作最大数 CON: DJNZ Data1, NEXT ;判断数据是否比较完毕
RET ;比较结束 该程序属于“先执行后判断”结构的单循环程序。
3.8.4 子程序设计
对于一般的单片机应用系统,通常采用模块化程序设计方法来设计应用程序。所谓模块 化程序设计,就是把一个复杂的程序分成多个功能上相对独立的程序模块(即子程序),分别 编制、调试,然后连接在一起形成一个完整的程序。为此,对那些具有独立功能的或通用的或 需要多次重复使用的程序段,常编写成子程序,需要执行这段程序时,就用 ACALL 或 LCALL 指令调用该子程序,子程序执行完毕再由返回指令 RET 返回到调用程序继续执行。子程序调 用与返回过程如图 3-6 所示。
图 3-6 子程序的调用与返回
案例 12 一位数码管显示
P1 接七段数码管段数据口,P3.4 接七段数码管位数据口,编写程序,使一位数码管 0~9 循环点亮。数码管为共阴极数码管。
程序流程图如图 3-7 所示,程序清单如下:
ORG 0000H START: CLR P3.4
MOV P1,#3FH ;显示“0”
图 3-7
LCALL DELAY
MOV P1,#06H ;显示“1”
LCALL DELAY
MOV P1,#5BH ;显示“2”
LCALL DELAY
MOV P1,#4FH ;显示“3”
LCALL DELAY
MOV P1,#66H ;显示“4”
LCALL DELAY
MOV P1,#6DH ;显示“5”
LCALL DELAY
MOV P1,#7DH ;显示“6”
LCALL DELAY
MOV P1,#07H ;显示“7”
LCALL DELAY
MOV P1,#7FH ;显示“8”
LCALL DELAY
MOV P1,#67H ;显示“9”
LCALL DELAY LJMP START
DELAY: ;延时子程序
MOV R4,#10 D1: MOV R5,#200 D2: MOV R6,#126 D3: DJNZ R6,D3
DJNZ R5,D2 DJNZ R4,D1 RET
END
1.常用的程序结构有哪几种?特点如何?
2.什么是伪指令?常用的伪指令功能如何?
1.求 8 个无符号数的平均值,这 8 个无符号数存放在内部 RAM 以 20H 开始的 8 个单元 中,结果保存在 30H 中。
2.设内部 RAM 从 21H 单元开始存有一组带符号数,数据长度存于 20H 单元,要求把该 组数据中的正数、负数分别求和,并存放在寄存器 R6 和 R7 中。
3.设内部 RAM 从 LIST 单元开始存有一组无符号数据,数据个数为 30,编程找出其中 的最大数,并存入 BIG 单元中。
4.设内部 RAM 从 20H 单元开始存有 40H 个无符号数,试编制程序将它们按从大到小的 顺序排列,结果仍存放在原存储区域内。
5.试编写程序,将内部 RAM 的 20H、21H 单元的两个无符号数相乘,结果存放在 R2、
R3 中,R2 中存放高 8 位,R3 中存放低 8 位。
6.已知自变量 X 存放在 4000H 单元中,函数值 Y 存放在 4001H 单元中,编写程序计算 分支函数的值。
5X ;X 10H Y 4X 50H ;X 10H 3X 30H ;X 10H
7.编写排序程序,将地址为 30H~3FH 的片内数据存储器中的数据降序排序。
8.设被加数存放在内部 RAM 的 20H、21H 单元,加数存放在 22H、23H 单元,若要求 和存放在 24H、25H 中,试编写出 16 位数相加的程序。
指令系统功能的强弱决定了计算机性能的高低。80C51 单片机的指令系统共 111 条指令,
其指令的执行时间短、字节少,位操作指令极为丰富。
指令由操作码和操作数组成。寻址方式是寻找存放操作数的地址并将其提取出来的方法。
80C51 单片机有 7 种基本的寻址方式。
本模块以举例方式,对于初学者经常用到的各类指令和简单的程序类型进行了较详细的 注释。数据传送类程序的编写是初学者首先应掌握的,而数据传送空间是内部 RAM、寄存器 及外部数据空间及程序空间。因此,内部硬件结构及存储器结构应是初学者首先应该掌握的。
只有软件指令功能和硬件映像相结合,才能更好地掌握汇编源程序的编写。初学者可以结合本 模块中的例题和习题进行程序编写的练习。