|
第4章 MCS-51汇编语言程序设计
本章重点
汇编语言与机器语言、高级语言的区别
汇编语言程序语句格式
两次扫描汇编过程
Intel HEX文件格式
汇编语言程序的流程控制结构
4.1、汇编语言的概述
1、机器语言:计算机能够直接识别和执行的只有二进制编码的指令,这种编码形式就是机器语言
例如:74H 34H 24H 45H F5H 09H 74H 12H 34H 23H F5H 08H
2、汇编语言:使用助记符、符号地址、标号等符号来编写程序的系统称为汇编语言
例如:RES_LOW DATA 09H
RES_HIGH DATA 08H
MOV A,#34H
ADD A.#45H
………..
3、高级语言:面向过程和问题并能独立于机器的通用程序设计语言,是一种接近人类自然语言和常用数学表达式的计算机语言
例如:int a,b,c
a=0x1234;
b=0x1235;
c=a+b;
在科学计算、信息处理等方面采用高级语言比较合适,而在实时控制中,通常使用汇编语言
4.2汇编语言格式
4.2.1程序语句格式:汇编语言中的语句包括指令语句、汇编语句伪指令语句、汇编控制语句和注释语句
指令语句就是可执行的指令助记符,伪指令语句是汇编器的指令,汇编控制语句用来设置汇编器模式和工作流程,注释语句用来说明以上语句的目的,提高程序可读性
汇编语句一般 [标号:] 助记符 [操作数列表] [;注释]
[标号或符号:] 伪指令 [操作数] [;注释]
4.2.2表达式:位于操作数字段的数据有三种表示方法:显示记法(如0FFH),使用预定义的符号(如ACC),也可以使用表达式,如2-3,表达示求值都按16位运算进行
A、数制:可以在常数结尾处加符号标注来表示数值的进制,通常B表示二进制,O或Q表示八进制,H表示十六进制,D或者不加表示十进制
B、字符和字符串:字符串以一个或两个单引号引起来的字符构成,可用在操作数字段的表达式中,汇编器将其ASCII码转换为等价的二进制形式,如MOV A,#’0’
C、算术运算:包括加(+),减(-),乘(*),除(/),求模(MOD)
D、逻辑运算:或(OR),与(AND),异或(XOR),非(NOT)
E、特殊运算:右移(SHR),左移(SHL),取高字节(HIGH),取低字节(LOW),优先求值(())
F、关系运算:相等(EQ、=),不相等(NE、<>),小于(LT、<),小于或等于(LE、<=),大于(GT、>),大于或等于(GE、>=)
运算优先级从高到低如下
()
HIGH LOW
* /
+ -
EQ(=) NE(<>) LT(<) LE(<=) GT(>) GE(>=)
NOT
AND
OR XOR
同级别的结合性为从左到右
4.2.3伪指令语句:只是指定汇编器在对源程序汇编期间需要执行的一些操作
A、ORG:设置汇编计数器的值,指定其后语句的起始地址
B、END:是源程序的最后一条语句,用以通知汇编程序汇编过程应在此结束
C、EQU和SET:EQU symbol EQU expression ,为常数符号symbol指定一个数值,即表达式expression的结果,SET类似于EQU,二者区别在于EQU定义的符号不允许重新定义,而使用SET定义的符号可以重新定义
D、DATA、IDATA、XDATA、BIT、CODE:用来给相应的段(存储区域)内地址赋一个符号分别对应内部RAM、间接寻址的内部RAM、外部RAM、位寻址区、程序存储器区域
E、DS:以字节单位保留存储空间 [lable:] DS expression 汇编时地址计数器的值将会更新为当前值与expression结果的和
F、DBIT以位为单位保留存储空间 [lable:] DBIT expression
G、DB以字节为单位初始化程序存储器空间 [lable:] DB expression[,expression][……….]
H、DW以双字节为单位初始化程序存储器空间,格式同上
I、PUBLIC和EXTRN:模块间通信的伪指令,连接各个子程序等等
PUBLIC symbol[,sybol][………]
J、绝对地址选择伪指令
CSEG [AT address] 程序存储器指定绝对地址
CSEG [AT address] 内部数据….
CSEG [AT address] 间接寻址的内部数据……
CSEG [AT address] 位寻址区和外部数据…….
CSEG [AT address] 和外部数据…….
4.2.5条件汇编:允许将一个软件的多个版本保存在同一组源程序文件中,使用IF、ELSEIF、ELSE、ENDIF一般格式为
IF expression
(语句组1)
ELSE
(语句组2)
ENDIF
或者
IF expression1
(语句组1)
ELSEIF expression2
(语句组2)
[ELSEIF expressionX
(语句组X)]
ELSE
(语句组X+1)
ENDIF
4.2.6程序结构:程序员经验的总结,通常的顺序是:版本号定义部分,常数符号定义部分,存储区符号定义部分,指令代码部分
4.3汇编程序的工作过程
4.3.1手工汇编过程:通常手工汇编要两次完成
第一次扫描时应该先确定源程序在内存的起始地址,然后在指令码表中依次找出每条指令的操作码,从程序的起始地址开始,逐一将它们写出。
第二次扫描是第一次的继续,其任务是确定第一次扫描过程序中未确定的标号或地址位移量的值
例题:MCS-51单片机内部RAM的30H和31H单元存放着两个8位无符号数,求出其中最大者存放到32H单元中,使用CJNE指令完成无符号数的比较,程序如下
NUM1 DATA 30H
NUM2 DATA 31H
NUM3 DATA 32H
ORG 0000H
MAIN:
MOV A,NUM1
CJNE A,NUM2 NUM_NEQ
MOV NUM3,NUM1
SJMP OVER
MUN_NEQ:
JC LATTER
MOV NUM3,NUM1
SJMP OVER
LATTER:
MOV NUM3,NUM2
OVER:
SJMP $
END
这里包含一个ORG和END伪指令语句的完整程序,第一扫描时要查指令表,并写下每条指令的机器码及其起始地址,对于无法确定的位移量、目标地址等,应该照原样写在操作数的相应位置上,如表4-1所示
地址 |
机器码 |
标号 |
指令助记符 |
0000H |
02 MAIN |
|
LJMP MAIN |
0030H |
E5 30 |
MAIN |
MOV A,NUM1 |
0032H |
B5 31 NUM_NEQ |
|
CJNE A,NUM2,NUM_NEQ |
0035H |
85 30 32 |
|
MOV NUM3,NUM1 |
0038H |
80 OVER |
|
SJMP VOER |
003AH |
40 LATTER |
NUM_NEQ |
JC LATTER |
003CH |
85 30 32 |
|
MOV NUM3,NUM1 |
003FH |
80 OVER |
|
SJMP VOER |
0041H |
85 31 32 |
TATTER |
MOV NUM3,NUM2 |
0044H |
80 $ |
OVER |
SJMP $ |
第二次扫描要确定机器码中的标号或地址位移量,就是计算出表4-1中的MAIN、NUM_NEQ、OVER、LATTER、$等所对应的实际值,其中MAIN的值为0030H,OVER的值为0044H,LATTER的值为0041H,除了MAIN可以直接填写外,其他都涉及相对寻址,所以要计算出位移量
0034H单元的NUM_NEQ=003AH-0035H=05H,0039H单元的OVER=0044H-003AH=0AH,003BH单元的LATTER=0041H-003CH=05H,0040H单元的OVER=0044H-0041H=03H,0045H单元的$=0044H-0046H=-2=FEH,将计算结果填入表中得到表4-2如下
地址 |
机器码 |
标号 |
指令助记符 |
0000H |
02 00 30 |
|
LJMP MAIN |
0030H |
E5 30 |
MAIN |
MOV A,NUM1 |
0032H |
B5 31 05 |
|
CJNE A,NUM2,NUM_NEQ |
0035H |
85 30 32 |
|
MOV NUM3,NUM1 |
0038H |
80 0A |
|
SJMP VOER |
003AH |
40 05 |
NUM_NEQ |
JC LATTER |
003CH |
85 30 32 |
|
MOV NUM3,NUM1 |
003FH |
80 03 |
|
SJMP VOER |
0041H |
85 31 32 |
TATTER |
MOV NUM3,NUM2 |
0044H |
80 FE |
OVER |
SJMP $ |
4.3.2机器汇编过程:手工汇编简单易行,但效率低容易出错,特别是在源程序较长,复杂时,实际应用中都采用机器汇编来完成,机器汇编通常也是两次扫描汇编,为完成两次扫描需要以下基本数据:
各个段的址计数器LC,用以跟踪和确定符号和指令的地址。
指令机器码表MOT,用以确定指令的长度和把助记符转换为机器码
符号表SYMBOL,在第一扫描时,把各个标号、符号的值列入表中,以便第二次扫描时代入相应的符号地址中
伪指令操作表POT,汇编过程序中遇到伪指令时执行相应的操作
输入汇编源程序
实现两次扫描汇编程序的算法可描述如下
读源程序
查找MOT或POT
分析源程序行的语法(检查语法有没有错误)
跟踪地址计数器LC
建立符号表
计算地址
写出目标程序
4.3.3 inter HEX文件
HEX文件是一种把二进制机器码保存为ASCII字符文件的标准。若存储在磁盘上,由于一个字节数据需要两个十六进制符号表示,HEX文件所占空间比二进制格式要大一倍,例如对上例题的对应的HEX文件内容如下
:03000000020030CB
:10003000E530B53105853032800A400585303280A3
:060040000385313280FE51
:00000001FE
HEX文件一般有多行,每行以冒号开始,格式为
:CCAAAATTDDDDDDDDDDDDDDDDDDDDSS
数据全部使用十六进制表示,其中,CC是计算字节,指示该行有多少个机器码字节,CC的范围是00-10,即从0-16,AAAA为加载地址,指出该行第一个机器码字节在程序存储器中的单元地址,是用4位十六进制数表示的16位地址,TT为类型,01表示该行为文件未行,00表示非未行,DD……DD是实际机器码(包括程序中的常数表格),这部分最多有16个字节的数据,对程序存储器编程时,这部分内容输入到程序存储器的连续单元中,SS为校验字节,即校验和的形式,将该行包括SS在内的所有字节相加,丢弃进位后结果应该为0。
例如解释以下HEX文件信息,并检查是否有存储错误
:060040000385313280FE51
:00000001FE
第一行有6个字节机器码,从程序存储器0040H单元开始存放,非最后一行,机器码分别为03H、85H、13H、80H、FEH,:06H+00H+40H+00H+03H+85H+31H+32H+80H+FEH=0,无校验错
第二行有0个字节机器码,是文件的最后一行,00H+00H+00H+01H+FFH=0,无校验错
4.4汇编语言设计
汇编语言程序设计一般过程是:分析任务,确定算法或解题思路,按功能划分模块,确定各模块之间的相互关系及参数传递;若问题较复杂,应根据算法和钥匙思路画出程序流程图;合理分配寄存器和存储器,编写汇编语言源程序,并附以必要的注释;进行汇编和连接;软件或硬件仿真调试、修改,直到满足任务要求;将调好目标文件(二进制或HEX格式)写入程序存储器内,上电运行,
根据结构化程序设计特点,程序有三种基本结构:顺序结构、分支结构和循环结构,为实现模块化,也经常使用子程序
如图1所示。
4.4.1顺序结构
例1、设在外RAM的60H单元存有1个字节代码,要求将其分解成两个4位字段,高4位存入原单元的低4位,其低4位存入61H单元的低4位,且要求这两个单元的高4位均为0,试编制完整程序。
解: 字节分解:
核心指令 |
ANL ORL 1000H MODE:MOV R0,#60H MOVX A,@R0 MOV B,A ANL A,#0F0H SWAP A MOVX @R0,A ANL B,#0FH MOV A,B INC R0 MOVX @R0,A END |
4.4.2分支结构与分支程序设计
结构:根据不同的条件,进行相应的处理。
通常用条件转移指令形成简单分支结构。
如: 判(A) = Z 或 NZ ,转移
判(CY)= 1 或 0 ,转移
判(bit)=1 或 0 ,转移
CJNE 比较不相等转移
例3、设a存放在累加器A中,b存放在寄存器B中,要求按下式计算Y值,并将结果Y存于累加器A 中,试编写程序。
解:本题关键是判a是正数,还是负数;由ACC7便知。
|
ORG 1000H JB ACC7,MINUS CLR C SUBB A,B SJMP DONE ADD A,B SJMP $ END |
例4、设有两个16位无符号数NA,NB分别存放在8031单片机内部RAM的40H、41H及50H、51H单元中,当NA > NB时,将内部RAM的42H单元清0;否则,将该单元置成全1,试编程。
解法I:因为无16位数的比较指令,所以,只能用8位数的比较指令。
(画出流程框图)
|
ORG 2000H MOV A,50H CJNE A,40H,CMP1 MOV A,51H CJNE A,41H,CMP1 SJMP NHIGHE JC HIGHE NHIGHE:MOV 42H,#0FFH SJMP DONE MOV 42H,#00H SJMP $ END |
上述程序中多次用到SJMP语句,该语句为无条件转移语句。无条件语句应尽量少用,这样可使程序结构紧凑而易读,易理解。
解法II:先假设NA > NB,再来判断是否NA ≤ NB
CMP2: CMP3: NHIGHE: HIGHE: |
ORG 3000H
|
4.4.3循环结构
循环结构不但使程序简练,而且大大节省存储空间。
循环程序包含四部分:
初始化部分
循环处理部分(主体)
循环控制部分(修改地址指针、修改变量、检测循环结束条件)
循环结束部分(对结果分析、处理,存放结果)
循环有:单循环、多重循环。
循环次数已知,可用计数器控制循环次数;
循环次数未知,按问题条件控制循环是否结束。
一、单循环程序
1、循环次数是已知的程序
例1、已知片外RAM的10H单元存放8位二进制数,要求将其转移成相应的ASCII码,并以高位在前,低位在后的顺序,依次存放到片外RAM以11H为首地址的连续单元中,试编程。
解:先将中间单元置成30H,然后判欲转换位是否为1,
若是,则将中间单元内容加1;否则,中间单元内容保持不变。
通过左移指令实现由高到低的顺序进行转换。
ORG 1000H | ||
START: |
MOV R2,#08H | ;循环计数初值(循环次数已知) |
MOV R0,#10H | ;地址指针初值 | |
MOVX A,@R0 | ;取数 | |
MOV B,A | ;暂存B中 | |
LOOP: |
MOV A,#30H | ;将中间单元(A)置成30H |
JNB B.7,NA | ;判断转换的二进制位为0否? | |
;若是转NA | ||
INC A | ;1的ASCII码“31H” | |
NA: |
INC R0 | ;修改地址指针 |
MOVX @R0,A | ;存放转换的结果 | |
MOV A,B | ||
RL A,B | ;作好准备,判断下一位 | |
MOV B,A | ;暂存 | |
DJNZ R2,LOOP | ;判断转换结束否?未完继续 | |
SJMP $ | ||
END |
2)循环次数未知的程序
例2、设用户用键盘输入长度不超过100字节的字符串放在8031单片机外部RAM以20H为首地址的连续单元,该字符串用回车符CR(‘CR’= 0DH)作为结束标志,要求统计此字符串的长度并存入内部RAM的1FH单元中。
解:从首单元开始取数,每取一数判断其是否为‘CR’,是则结束。
STADA SLANG CMCR2: CRLOP: |
ORG 1000H DATA 20H DATA 1FH MOV R0,#STADA-1 MOV B,#0FFH INC R0 INC B MOVX A,@R0 CJNE A,#0DH,CRLOP MOV SLANG,B SJMP $ END |
2、多重循环设计
循环体中还包含着一个或多个循环结构,即双重或多重循环。
例3、设8031使用12MHz晶振,试设计延迟100ms的延时程序。
解:延时程序的延迟时间就是该程序的执行时间,通常采用MOV和DJNZ二指令。
T = 12 / fosc = 12 / (12×106)= 1us
内循环延时:
(1 + 2 × CTR)T = 500us(假设)
则CTR = 250
实际延时:[1 + 2 × 250] × 1us = 501us
外循环延时:T +(501 + 2T)× CTS = 100ms = 100 000us
所以 , CTS = 198.8 取 199
实际延时:[1 + (501 + 2)×199] = 1000.98ms
例4、设在8031内部RAM中存一无符号数的数组,其长度为100,起始地址是30H,要求将它们从大到小排序,排序后仍存放在原区域中,试编者按程。
这就是所畏的“冒泡法”。
实际上大多情况,用不到99次循环,排序就结束。为了提高排序速度,程序中可设一交换标志位,如10H位,
每次循环中:若有交换则 SETB 10H
若无交换则 CLR 10H
每次循环结束时,测10H位,判断排序是否结束。
|
ORG 1000H MOV R0,#30H MOV B,#64H CLR 10H DEC B MOV A,@R0 MOV 20H,A INC R0 MOV 21H,@R0 CJNE A,21H,BUEU JNC BUNEXT MOV A,@R0 MOV @R0,20H DEC R0 MOV @R0,A INC R0 SETB 10H DJNZ B,LOOP JB 10H,BUBBLE END |
;长度计数 ;暂存,为交换作准备 ;若(20H)≠(21H)转移 ;(20H)≥(21H)转移 ;若(20H)< (21H)则交换 ;使R0退格指向小地址 ;恢复R0指向大地址 ;置交换标志 ;判断标志位为1否?若为1,则继续 |