第4章汇编程序设计_第1页
第4章汇编程序设计_第2页
第4章汇编程序设计_第3页
第4章汇编程序设计_第4页
第4章汇编程序设计_第5页
已阅读5页,还剩95页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

第4章MCS-51汇编语言程序设计

汇编语言是面向机器硬件的语言,要求程序设计者对MCS-51单片机具有很好的“软、硬结合”的功底。

介绍程序设计的基本知识及如何使用汇编语言来进行基本的程序设计。4.1汇编语言程序设计概述

4.1.1机器语言、汇编语言和高级语言用于程序设计的语言基本上分为3种:机器语言、汇编语言和高级语言。

1.机器语言

二进制代码表示的指令、数字和符号简称为机器语言不易懂,难记忆,易出错。

2.汇编语言

英文助记符表示的指令称为符号语言或汇编语言将汇编语言程序转换成为二进制代码表示的机器语言程序称为汇编程序经汇编程序“汇编(翻译)”得到的机器语言程序称为目标程序,原来的汇编语言程序称为源程序。汇编语言特点:面向机器的语言,程序设计员须对MCS-51的硬件有相当深入的了解。助记符指令和机器指令一一对应,用汇编语言编写的程序效率高,占用存储空间小,运行速度快,用汇编语言能编写出最优化的程序。

能直接管理和控制硬件设备(功能部件),它能处理中断,也能直接访问存储器及I/O接口电路。汇编语言和机器语言都脱离不开具体机器的硬件,均是面向“机器”的语言,缺乏通用性。3.高级语言不受具体机器的限制,使用了许多数学公式和数学计算上的习惯用语,非常擅长于科学计算。常用的如BASIC、FORTRAN以及C语言等。高级语言优点:通用性强,直观、易懂、易学,可读性好。使用C语言(C51)、PL/M语言来进行MCS-51的应用程序设计。

对于程序的空间和时间要求很高的场合,汇编语言仍是必不可缺的。

C语言和汇编语言混合编程

在很多需要直接控制硬件的应用场合,则更是非用汇编语言不可使用汇编语言编程,是单片机程序设计的基本功之一4.1.2汇编语言语句的种类和格式两种基本类型:指令语句和伪指令语句(1)指令语句已在第3章介绍每一条指令语句在汇编时都产生一个指令代码——机器代码(2)伪指令语句

是为汇编服务的。在汇编时没有机器代码与之对应。

MCS-51的汇编语言的四分段格式如下:标号字段操作码字段操作数字段注释字段规则:(1)标号字段和操作字码段之间要有冒号“:”相隔;(2)操作码字段和操作数字段间的分界符是空格;(3)双操作数之间用逗号相隔;(4)操作数字段和注释字段之间的分界符用分号“;”相隔。操作码字段为必选项,其余各段为任选项。例4-1

下面是一段汇编语言程序的四分段书写格式

标号字段操作码字段操作数字段注释字段

START:MOVA,#00H;0→AMOVR1,#10;10→R1 MOVR2,#00000011B;3→R2 LOOP:ADDA,R2;(A)+(R2)→A DJNZR1,LOOP;R1内容减1不 为零,则循环

NOP HERE:SJMPHERE基本语法规则:1.标号字段是语句所在地址的标志符号

(1)标号后边必须跟以冒号“:”(2)由1~8个ASCII字符组成(3)同一标号在一个程序中只能定义一次(4)不能使用汇编语言已经定义的符号作为标号2.操作码字段

是汇编语言指令中唯一不能空缺的部分。汇编程序就是根据这一字段来生成机器代码的。3.操作数字段

通常有单操作数、双操作数和无操作数三种情况。如果是双操作数,则操作数之间,要以逗号隔开。(1)十六进制、二进制和十进制形式的操作数表示

采用十六进制形式来表示,某些特殊场合才采用二进制或十进制的表示形式。十六进制,后缀“H”

。二进制,后缀“B”

。十进制,后缀“D”,也可省略。若十六进制的操作数以字符A~F中的某个开头时,则需在它前面加一个“0”,以便在汇编时把它和字符A~F区别开来。(2)工作寄存器和特殊功能寄存器的表示采用工作寄存器和特殊功能寄存器的代号来表示,也可用其地址来表示。例如,累加器可用A(或Acc)表示。也可用0E0H来表示,0E0H为累加器A的地址。(3)美元符号$的使用用于表示该转移指令操作码所在的地址。例如,如下指令:

JNBF0,$与如下指令是等价的:

HERE:JNBF0,HERE

再如:

HERE:SJMPHERE可写为:

SJMP$4.注释字段

必须以分号“;”开头,换行书写,但必须注意也要以分号“;”开头。汇编时,注释字段不会产生机器代码。4.1.3伪指令在MCS-51汇编语言源程序中应有向汇编程序发出的指示信息,告诉它如何完成汇编工作,这是通过使用伪指令来实现的。也称为汇编程序控制命令。只有在汇编前的源程序中才有伪指令。经过汇编得到目标程序(机器代码)后,伪指令已无存在的必要,所以“伪”体现在汇编时,伪指令没有相应的机器代码产生。常用的伪指令:

1.ORG(ORiGin)汇编起始地址命令

在汇编语言源程序的开始,通常都用一条ORG伪指令来实现规定程序的起始地址。如不用ORG规定,则汇编得到的目标程序将从0000H开始。例如:

ORG2000HSTART: MOVA,#00H ┋规定标号START代表地址为2000H开始。在一个源程序中,可多次使用ORG指令,来规定不同的程序段的起始地址。但是,地址必须由小到大排列,地址不能交叉、重叠。例如:

ORG2000H ┇

ORG2500H ┇ ORG3000H ┇2.END(ENDofassembly)汇编终止命令汇编语言源程序的结束标志,用于终止源程序的汇编工作。在整个源程序中只能有一条END命令,且位于程序的最后。3.DB(DefineByte)定义字节命令在程序存储器的连续单元中定义字节数据。

ORG2000HDB30H,40H,24,“C”,“B”汇编后: (2000H)=30H

(2001H)=40H

(2002H)=18H(10进制数24) (2003H)=43H(字符“C”的ASCII码) (2004H)=42H(字符“B”的ASCII码)DB功能是从指定单元开始定义(存储)若干个字节,10进制数自然转换成16进制数,字母按ASCII码存储。4.DW(DefineWord)定义数据字命令从指定的地址开始,在程序存储器的连续单元中定义16位的数据字。例如:

ORG2000H DW1246H,7BH,10汇编后:(2000H)=12H ;第1个字(2001H)=46H(2002H)=00H ;第2个字(2003H)=7BH(2004H)=00H ;第3个字(2005H)=0AH(2005H)=0AH5.EQU(EQUate)赋值命令用于给标号赋值。赋值以后,其标号值在整个程序有效。例如:TESTEQU2000H

表示标号TEST=2000H,在汇编时,凡是遇到标号TEST时,均以2000H来代替。

4.1.4汇编语言程序设计步骤(1)分析问题,确定算法(2)根据算法,画出程序框图(3)分配内存工作区及有关端口地址----与硬件相关(4)编写程序养成在程序的适当位置上加上注释的好习惯。(5)上机调试编写完毕的程序,必须“汇编”成机器代码,才能调试和运行,调试与硬件有关程序还要借助于仿真开发工具并与硬件连接。4.2汇编语言源程序的汇编汇编语言源程序“翻译”成机器代码(指令代码)的过程称为“汇编”。汇编可分为手工汇编和机器汇编两类:4.2.1手工汇编人工查表翻译指令。但遇到的相对转移指令的偏移量的计算,要根据转移的目标地址计算偏移量,不但麻烦,且容易出错。4.2.2机器汇编用编辑软件进行源程序的编辑。编辑完成后,生成一个ASCII码文件,扩展名为“.ASM”。然后在微计算机上运行汇编程序,把汇编语言源程序翻译成机器代码。交叉汇编—汇编后的机器代码是在另一台计算机(这里是单片机)上运行。

MCS-51单片机的应用程序的完成,应经过三个步骤;(1)在微计算机上,运行编辑程序进行源程序的输入和编辑;(2)对源程序进行交叉汇编得到机器代码;(3)通过微计算机的串行口(或并行口)把机器代码传送到用户样机(或在线仿真器)进行程序的调试和运行。第(1)步,只需在微计算机上使用通用的编辑软件即可完成。第(2)步的交叉汇编所用的汇编程序可在购买单片机的仿真开发工具时,由厂商提供。第(3)步骤的实现要借助于单片机仿真开发工具进行。4.3.1程序结构设计的基本方法汇编语言程序设计基本要求:

高质量、可读性好、存储容量小和执行速度快汇编程序结构设计的基本方法:

1.简单程序的设计

2.分支程序设计3.循环程序设计4.子程序设计5.查表程序设计6.散转程序设计4.3汇编语言实用程序设计4.3.2简单和分支程序设计1简单程序设计[例4.1]

请用51汇编指令编写程序,将外部RAM单元中40H单元2位BCD数转换成ASCII码,送到内部RAM单元60H61H之中。简单程序:是指程序设计中没有使用转移类指令的程序段。也称顺序程序或直线程序。程序执行:按照指令存储位置的先后顺序依次执行,中间不会有任何分支程序、循环程序等。程序特点:结构简单,易于阅读理解,大量使用数据传送指令。解:根据ASCII字符表,十进制数09的ASCII码和它的BCD码之间仅相差30H,本题需要把一个字节的两位BCD数进行拆分,然后分别和30H相加,即得到相应的ASCII码。参考设计程序如下:

ORG1000HADDR1DATA0040HADDR2EQU60H

MOVDPTR,#ADDR1;源地址=>DPTRMOVR0,#ADDR2;目标地址=>R0

MOV@R0,#00H;目标地址单元清零MOVXA,@DPTR;源地址单元中BCD数送AMOVB,AANLA,#0FHORLA,#30H;完成低位BCD数转换MOV@R0,A;存入60HINCR0MOVA,BANLA,#0F0HSWAPA;高位BCD数送低4位ORLA,#30H;完成高位BCD数转换

MOV@R0,A;

存入61HSJMP$

END2分支程序设计

分支程序的特点是程序中含有转移指令。由于转移指令有无条件转移和条件转移之分,因此分支程序也可分为无条件分支程序和条件分支程序两类。无条件分支程序中含有无条件转移指令,因简单这里不作专门讨论;条件分支程序中含有条件转移指令,是我们讨论的重点。条件分支程序体现了计算机执行程序时的分析判断能力。若某种条件满足,则机器就转移到另一分支上执行程序;若条件不满足,则机器就按原程序继续执行。

MCS-51中,条件转移指令共有13条,分为累加器A判零条件转移、比较条件转移、减1条件转移和位控制条件转移等四类。[例4.2]

已知VAR单元内有一自变量X,请按如下条件编出求函数值Y并将它存入FUNC单元的程序。Y=

解:这是一个三分支归一的条件转移问题,程序实现通常可分为“先分支后赋值”和“先赋值后分支”两种求解办法。现分述如下:1.先分支后赋值。题意告诉我们,自变量X是个带符号数,可采用累加器判零条件转移和位控制条件转移指令来实现,程序流程如图4-1(a)所示。相应程序为:

ORG1000HVAR DATA30HFUNCDATA31HMOVA,VAR ;X送A JZDONE ;若X=0,则转DONEJNBACC.7,POSI ;若X>0,则转POSIMOVA,#0FFH ;若X<0,则-1送ASJMPDONE

;转DONEPOSI: MOVA,#01H ;1送ADONE:MOVFUNC,A

;存Y值

SJMP$

END

A←XA=0?A>0?

A

1

存结果A

1(a)先分支后赋值

YN

N

Y

图4-1[例4.2]流程图

2.先赋值后分支。

先把X调入累加器A,并判断它是否为零?

若X=0,则A中内容送FUNC单元;

若X≠0,则先给R0赋值(如-1),然后判断A<0?

若A<0,则R0送FUNC单元;

若A>0,则把R0修改成1后送FUNC单元,

程序流程如图4-1(b)所示。

(b)先赋值后分支

A←X,R0←0

R0←1

存结果

R0←–1A=0?

A>0?YN

YN

图4-1[例4.2]流程图

相应程序为:

ORG1000HVARDATA30HFUNCDATA31HMOVR0,#00HMOVA,

VAR;X送AJZDONE;若X=0,则转DONEMOVR0,#0FFH;若X0,则-1送R0JBACC.7,DONE;若X<0,则转DONEMOVR0,#01H;若X>0,则1送R0DONE:MOVFUNC,R0;存Y值

SJMP$

END

[例4.3]

某系有200名学生参加外语统考,若成绩已存放在MCS-51外部RAM始地址为ENGLISH的连续存储单元,现决定给成绩在95分~100分之间学生颁发A级合格证书和成绩在90分~94分之间学生颁发B级合格证书。试编制一个程序,可以统计A级和B级证书的学生人数,并把统计结果存入内部RAM的GRADA和GRADB单元。

解:这是一个循环和分支相结合程序,

程序流程图如图4-2所示。

A≥95?

A≥90?完成否?GRADB单元内容加1修改DPTR指针

结束GRADA单元内容加1GRADA和GRADB单元清零、DPTR置初值ENGLISH、循环计数器R2置初值200取某学生外语成绩图4-2[例4.3]程序流程图

相应程序为:

ORG1000HENGLISHDATA2000HGRADADATA20HGRADBDATA21HMOVGRADA,#00H

;GRADA单元清零

MOVGRADB,#00H

;GRADB单元清零

MOVR2,#0C8H

;参考总人数送R2

MOVDPTR,#ENGLISH;学生成绩始地址送DPTRLOOP:

MOVXA,@DPTR

;取某学生成绩到A

CJNEA,#5FH,LOOP1;和95作比较,形成CyLOOP1:JNCNEXT1

;若A95,则NEXT1CJNEA,#5AH,LOOP2;和90作比较LOOP2:JCNEXT

;A<90,NEXTINCGRADB

;为B级,则GRADB单元内容加1SJMPNEXTNEXT1:

INCGRADA

;A95,则GRADA单元内容加1NEXT:

INCDPTR

;修改学生成绩指针

DJNZR2,LOOP

;未完,则LOOPSJMP$

;结束

END3散转程序设计在利用MCS-51单片机指令设计汇编程序时,有时会遇到一类多分支程序的设计。分支转移的目标地址不是汇编或编程时确定的,而是在程序运行时动态决定的。

MCS-51单片机提供了间接转移指令JMP@A+DPTR,恰好可以实现这一类转移。其中,DPTR装入多分支转移程序的首地址,用累加器A的内容来动态选择其中的某一个分支予以转移。这样一条指令可实现以DPTR内容为起始地址的256个字节范围的选择转移。[例4.4]

已知通过调用键盘控制程序KEYREAD可将按下的按键键值0~15之一读到累加器A,要求编写程序对读入的不同键值,分别转入对应的键控程序段KEY0~KEY15执行。

即要求:当(A)=0时,转键控处理程序KEY0;

当(A)=1时,转键控处理程序KEY1;

…………………

当(A)=15时,转键控处理程序KEY15。

解:

对于上述要求的问题,编写程序如下:ORG

1000HACALLKEYREAD;读键值程序

RL

A

;调整

MOV

DPTR,#TABLE;表首址送DPTRJMP

@A+DPTR

;以A中内容为偏移量跳转

……………TABLE:AJMPK0

;读入键为第1个键,转K0执行

AJMPK1

;读入键为第2个键,转K1执行

……………AJMPK15

;读入键为第16个键,转K15执行

……………K0:[第1键处理程序段]K1:[第2键处理程序段]………

K15:[第16键处理程序段]4.4循环和查表程序设计4.4.1循环程序设计

循环程序的特点是程序中含有可以重复执行的程序段,该程序段通常称为循环体。例如,求100个数的累加和是没有必要连续安排100条加法指令的,可以只用一条加法指令并使之循环执行100次。循环程序的组成(四部分):1.循环初始化循环初始化程序段位于循环程序开头,用于完成循环前的准备工作,例如:循环体中循环计数器和各工作寄存器设置初值,其中循环计数器用于控制循环次数。

循环程序设计不仅可以大大缩短所编程序长度和使程序所占存储单元数最少,也能使程序结构紧凑和可读性变好。

应注意循环程序设计并不能缩短完成任务的程序执行时间。2.循环处理这部分程序位于循环体内,是循环程序的工作程序,需要重复执行。要求编写得尽可能简练,提高程序执行速度。3.循环控制循环控制程序也在循环体内,常常由修改循环计数器内容的语句和条件转移语句等组成,用于控制循环执行次数。4.循环结束这部分程序用于存放执行循环程序所得结果以及恢复各工作单元循环前的初值。循环程序通常有两种编制方法:一种是先循环处理后循环控制(即先处理后判断),如图4-3(a)所示;另一种是先循环控制后循环处理(即先判断后处理),如图4-3(b)所示。初始化循环处理循环控制循环结束

完成?初始化循环处理循环控制完成?循环结束

(a)先处理后判断

(b)

先判断后处理

图4-3循环程序结构类型解:为了使大家对两种循环结构有一个全面了解,以便进行分析比较,现给出两种设计方案。

1.先判断后处理(见图4-4(a))[例4.5]

已知内部RAM的BLOCK单元开始有一无符号数据块,块长在LEN单元。请编出求数据块中各数累加和、并存入SUM单元的程序。A←0R2←块长+1R1←BLOCK

完成?A←A+(R1)R1←R1+1SUM←和A←A+(R1)R1←(R1)+1SUM←和完成?A←0R2←块长R1←BLOCK

(a)先判断后处理

(b)先处理后判断

图4-4[例4.5]程序流程图求累加和参考程序:

ORG1000HLENDATA20HSUMDATA21HBLOCKDATA22HCLRA;A清零

MOVR2,LEN;块长送R2MOVR1,#BLOCK;块始地址送R1INCR2;块长+1

SJMPCHECKLOOP:ADDA,@R1

;A+(R1)送A

INCR1

;修改数据块指针R1CHECK:DJNZR2,LOOP

;若未完,则转LOOPMOVSUM,A

;存累加和

SJMP$

END先判断后处理2.先处理后判断(见图4-4(b))

参考程序为:

ORG1000HLENDATA20HSUMDATA21HBLOCKDATA22HCLRA;A清零

MOVR2,LEN;块长送R2MOVR1,#BLOCK;数据始地址送R1

NEXT:ADDA,@R1

;A+(R1)送A

INCR1

;修改数据块指针R1

DJNZR2,NEXT

;若未完,则转NEXTMOVSUM,A;存累加和

SJMP$

END先处理后判断应当注意:上述两个程序是有区别的。若块长≠0,则两个程序的执行结果相同;若块长=0,则先处理后判断程序的执行结果是错误的。或者说,先处理后判断程序至少执行一次循环体内程序。[例4.6]

设单片机MCS-51内部RAM起始地址为30H的数据块中有64个无符号数。试编制一个程序能使它们按从小到大数据排列。解:设有64个无符号数,在数据块中序号为:e1,e2,…,e63,e64,使它们按从小到大顺序排列的方法颇多。现以气泡分类法为例加以介绍。

气泡分类法又称两两比较法。它先使e63和e64比较,若e64>e63,则两个存贮单元中内容交换,反之就不交换;然后使e62和e63相比,按同样原则决定是否交换;一直比较下去;最后完成e1和e2比较及交换,经过N-1=63次比较(常用内循环63次来实现)后,e1位置上必然得到数组中的最大值,犹如一个气泡从水底冒到了水顶,如图4-5所示。第二次冒泡过程和第一次冒泡过程完全相同,比较次数也可以是63次(其实只需62次),冒泡后可以在e2位置上得到次最大值,如图4-5所示。

冒泡循环次数计算:(以

64个数的排序为例)大循环(外循环)共63次;内循环:共63×63次。完成64个数的排序需要外循环63次、内循环3969次。第一次冒泡排序(比较5次)

N=6时

比较1

比较2

比较3

比较4

比较5

e144444256e211112564e300025611e44242256000e53625642424242e62563636363636第二次冒泡排序(比较4次)

N=6时

比较1

比较2

比较3

比较4e1256256256256256256e244444242e31114244e40042111e542420000e6363636363636第三次冒泡排序(比较3次)

N=6时

比较1

比较2

比较3e1256256256256256256e2424242424242e3444363636e41136444e50361111e63600000第四次冒泡排序(比较2次)

N=6时

比较1

比较2e1256256256256256256e2424242424242e3363636363636e4444444e5111111e6000000第五次冒泡排序(比较1次)

N=6时

比较1e1256256256256256256e2424242424242e3363636363636e4444444e5111111e6000000其实,64个无符号数的数组排序需要冒泡63次的机会是很少的,每次冒泡所需的数据比较次数,也是从63逐次减少(每冒一次泡减少一次比较)。为了禁止那些不必要的冒泡次数,人们常常设置一个“交换标志位”。“交换标志位”在循环初始化时清零,在数据交换时置位成1(表示冒泡中进行过数据交换)。“交换标志位”用来控制是否再需要冒泡:若“交换标志位”为1,则表明刚刚进行的冒泡中发生过数据交换(即排序尚未完成),应继续进行冒泡;若“交换标志位”为0,则表明刚进行完的冒泡中未发生过数据交换(即排序已完成),冒泡应该禁止。例如,对于一个已经排好序的数组:1,2,3,…,63,64,排序程序只要进行一次冒泡便可根据“交换标志位”状态而结束排序程序的再执行,这自然可以节省63-1=62次的冒泡时间。冒泡程序流程如图4-6所示。开始数据块始址送R0块长-1送R2“交换标志位”7FH清零

eN送20H和A修改数据指针eN-1送21H

eN≥eN-1?“交换标志”7FH=1?e和e在数据块中位置交换“交换标志”7FH置”1”结束

R2-1=0?图4-6冒泡程序流程图

参考程序为:

ORG1000HBUBBLE:MOVR0,#30H;置数据块指针R0MOVR2,#64;块长送R2CLR7FH

;交换标志2FH.7清零

DECR2

;块长-1为比较次数

BULOOP:

MOV20H,@R0;e送20HMOVA,@R0

;e送AINCR0MOV21H,@R0

;e送21HCJNEA,21H,LOOP;(20H)和(21H)比较

LOOP:JCBUNEXT

;若(20H)<(21H),则BUNEXTMOV@R0,20H

;若(20H)≥(21H),则两者交换

DECR0MOV@R0,21HINCR0

;恢复数块指针

SETB7FH

;置“1”交换标志位

BUNEXT:DJNZR2,BULOOP

;若一次冒泡未完,则BULOOP… ;R2=0?JB7FH,BUBBLE

;若交换标志位为1,则BUBBLESJMP$

;结束

END在以上循环程序的实例中,单循环程序结构比较简单,程序每循环一次,其循环体就被执行一次。双循环(或多循环)程序就不同了,外循环一次内循环执行一圈。因此,在双重循环和多重循环程序设计中,内层循环体前应注意安排循环初始化,内外循环间也不应相互交叉。4.4.2查表程序设计

查表是根据存放在ROM中数据表格的项数来查找和它对应的表中值。方法简便,可缩短程序长度和提高程序执行效率。

例如:查Y=X2(设X为0~9)的平方表时,可以预先计算出X为0~9时的Y值作为数据表格的内容,存放在起始地址为DTAB的ROM存储器中,并使X的值和数据表格的项数(所查数据的实际地址对DTAB的偏移量)一一对应。这样,就可以根据DTAB+X来找到X对应的Y值。采用MCS-51汇编语言进行查表尤为方便,它有两条专门的查表指令:MOVCA,@A+DPTR

MOVCA,@A+PC

第一条查表指令采用DPTR存放数据表格起始地址,其查表过程比较简单。查表前要把数据表格起始地址存入DPTR,然后把要求查表的项数折算成相对数据表始地址的偏移量,送入累加器A,最后使用MOVCA,@A+DPTR完成查表。采用MOVCA,@A+PC指令查表,其步骤分为如下三步。

(1)使用传送指令把所查数据表格的项数送入累加器A.(2)使用ADDA,#data指令对累加器A进行修正。data值由下式确定。PC+data=数据表起始地址DTAB其中,PC是查表指令MOVCA,@A+PC的下一条指令码的起始地址。data值实际等于查表指令和数据表存放初始地址之间的字节数。(3)采用查表指令MOVCA,@A+PC完成查表。查表程序主要用于线性化处理、代码转换、代码显示、实时值的查表计算和按命令号实现转移等。

注意:MOVCA,@A+DPTR指令可以实现64K地址范围内的数据查寻,而MOVCA,@A+PC指令只能实现256字节范围内的数据查寻。

[例4.7]

已知BLOCK1为起始地址的数据块(数据块长度在LEN单元),数块中每个存储单元中的高、低4位分别为两个十六进制数,请编程把它们转换为相应ASCII码,并存放在BLOCK2开始的连续存储单元(低4位ASCII码在前,高4位ASCII码在后)。解:由于每个存储单元中放有两个十六进制数,因此每个存储单元中十六进制数应分别转换成ASCII码。这就需要两次使用查表指令MOVCA,@A+PC,这两条查表指令在程序中位置是不相同的,故两次对PC调整的值也不相同。在编程时,可以先把整个程序编完,然后再计算两条加法指令中的data修正值并填入相应位置。相应参考程序为:

ORG1000HLENDATA30HBLOCK1DATA31HBLOCK2DATA51HMOVR0,#BLOCK1;BLOCK1送R0MOVR1,#BLOCK2;BLOCK2送R1LOOP:MOVA,@R0;取源数据块中数

ANLA,#0FH;取出低4位

ADDA,#20

;第一次地址调整

MOVCA,@A+PC;第一次查表

MOV@R1,A;存第一次转换结果2

MOVA,@R0;重新取出被转换数2

SWAPA

;高4位调入低4位1

ANLA,#0FH

;取出低4位2

ADDA,#09

;第二次地址调整2

MOVCA,@A+PC

;第二次查表2

INCR1

;修改目的数据块指针1

MOV@R1,A

;存第二次转换结果2

INCR0

;修改源数据块指针1

INCR1

;修改目的数据块指针1

DJNZLEN,LOOP

;若未转换完,则转LOOP2SJMP$1ASCTAB:DB‘0’,’1’,’2’,’3’,’4’DB‘5’,’6’,’7’,’8’,’9’DB‘A’,’B’,’C’,’D’,’E’,’F’

END例:设有一巡回检测报警装置,需对16路输入量进行测量控制,每路有一个最大允许值。控制时根据测量的路数,找出该路的最大允许值。测量的路数保存在R2中,最大值结果保存在R3R4中。解:利用查表程序完成。LTB: MOV A,R2 ADD A,R2 MOV R3,A ADD A,#6 MOVC A,@A+PC XCH A,R3 ADD A,#3 MOVC A,@A+PC MOV R4,A RETMAX: DW 1520,3721,445,7850 DW 3483,32657,883,9943 DW 1101,40511,6756,331 DW 4468,5871,13224,9981解:利用查表程序完成。LTB: MOV A,R2 ADD A,R2 MOV R3,A MOV DPTR,#MAX MOVC A,@A+DPTR XCH A,R3 INC A MOVC A,@A+DPTR MOV R4,A RETMAX: DW 1520,3721,445,7850 DW 3483,32657,883,9943 DW 1101,40511,6756,331 DW 4468,5871,13224,99814.5子程序和运算程序设计

子程序和运算程序是实用程序的两大支柱程序,在汇编语言程序设计中占有极其重要的地位。4.5.1子程序设计

子程序是指完成确定任务并能为其他程序反复调用的程序段。

调用子程序的程序叫做主程序或称调用程序。

例如:代码转换、通用算术及函数计算、外部设备的输入/输出驱动程序等等,都可以编成子程序。

只要在主程序中安排程序的主要线索,在需要调用某个子程序时采用LCALL或ACALL调用指令,便可从主程序转入相应子程序执行,CPU执行到子程序末尾的RET返回指令,即可从子程序返回主程序断点处执行。在工程上,几乎所有实用程序都是由许多子程序构成的。子程序可以构成子程序库,集中存放在某一存储空间,任凭主程序随时调用。采用子程序设计能使整个程序结构简单,缩短程序设计时间,减少对存储空间的占用。例如:如果某一实用程序需要10次调用某一子程序,那么只要在主程序的相应地安排10条调用指令就可以避免把同一子程序编写10遍,内存空间几乎可以减少9倍子程序的长度。主程序和子程序是相对的,没有主程序也不会有子程序。同一程序既可以作为另一程序的子程序,也可以有自己的子程序。即子程序是允许嵌套的,嵌套深度和堆栈区的大小有关。总之,子程序是一种能完成某一专用任务的程序段,其资源需要为所有调用程序共享,因此,子程序在结构上应具有通用性和独立性,在编写子程序时应注意以下问题。使用注意事项:

1)子程序的第一条指令地址称为子程序的始地址或入口地址。该指令前必须有标号,标号应以子程序任务定名,以便一看就一目了然。例如:延时程序常以DELAY作为标号。

2)主程序调用子程序是通过安排在主程序中的调用指令实现的,子程序返回主程序一般执行安排在子程序末尾的一条RET返回指令。

3)主程序调用子程序和从子程序返回主程序,计算机能自动保护和恢复主程序的断点地址。但对于各工作寄存器、特殊功能寄存器和内存单元中内容,如果需要保护和恢复,就必须在子程序开头和末尾(RET指令前)安排一些能够保护和恢复它们的指令。

4)为使所编子程序可以放在64KB内存的任何区域并能为主程序调用,子程序内部一般使用相对转移指令而不使用其他转移指令,以便汇编时生成浮动代码。5)子程序参数可以分为入口和出口参数两类:入口参数是指子程序需要的原始数,由调用它的主程序通过约定的工作寄存器R0~R7、特殊功能寄存器SFR、内存单元或堆栈等预先传送给子程序使用:出口参数是由子程序根据入口参数执行程序后获得的结果参数,应由子程序通过约定的R0~R7、SFR、内存单元或堆栈等传递给主程序使用。

传送子程序参数的方法通常有以下几种:

1)利用寄存器或片内RAM传送子程序参数对于某些简单子程序、入口参数和出口参数通常较少。常可采用本传送参数的方式。例如:CPU可以预先在主程序中把乘数和被乘数送入R0~R7,转入乘法子程序执行后得到的乘积也可通过R0~R7传送给主程序。

2)利用寄存器传送子程序参数的地址如果上述方法不太方便,CPU也可在主程序中把子程序入口参数地址通过R0~R7传送给子程序,子程序根据R0~R7中入口参数地址便可找到入口参数并对它们进行相应的操作,操作得到的出口参数也可把它们的地址通过寄存器R0~R7传送给主程序。3)利用堆栈传送子程序参数任何符合先进后出或后进先出原则的片内RAM区都可称为堆栈。堆栈中数据的存取是由堆栈指针SP指示的。因此,堆栈也可用来传送子程序参数。例如:CPU可以通过主程序中的PUSH指令把入口参数压入堆栈传送给子程序,子程序的出口参数也可通过堆栈传送给主程序。4)利用位地址传送子程序参数如果子程序的入口参数是字节中的某些位,那么利用本方法传送入口和出口参数也有方便之处,传送参数过程和上述诸方法类似。子程序参数的上述传递方法也适用于中断服务程序的编制。[例4.8]设MDA和MDB内有两个数据a和b,请编制出求c=a2+b2并把c送入MDC的程序,设a和b皆为小于10的整数。解:本程序由两部分组成:主程序和子程序。主程序通过累加器A传送子程序的入口参数a或b,子程序也通过累加器A传送出口参数a或b给主程序,子程序为求一个数的平方的通用子程序。相应程序如下:

ORG1000HMDADATA20HMDBDATA21HMDCDATA22HMOVA,MDA;入口参数a送AACALLSQR

;求a2

MOVR1,A

;a2送R1MOVA,MDB

;入口参数b送AACALLSQR

;求b2

ADDA,R1

;a2

+b2送AMOVMDC,A;存入MDC

SJMP$

;结束

SQR:ADDA,#01H

;地址调整

MOVCA,@A+PC;查平方表

RET

;返回

SQRTAB:DB0,1,4,9,16DB25,36,49,64,81

END

上述程序采用了查表法求一个数的平方,并且通过子程序调用实现了两个数的平方求和,值得注意的是,上述程序仅适应两个数比较小,两个数的平方和不大于用一个字节的数据表示。

[例4.9]

已知片内RAM中有一个五位BCD码(高位在前,低位在后),最大不超过65535,始地址在R0中,BCD码位数减1(04H)已在R2中,请编出把BCD码转换为二进制整数并存入R4R3中(R4中内容为高8位)中的程序。解:本题只编出子程序,主程序从略。①算法

开始保护现场R4R3R4R3×10,R0R0+1R4R3R4R3+(R0)R2-1=0?恢复现场结束

R4清零,R3万位BCD码图4-7例4-7程序流程

②参考程序入口参数:BCD字节地址指针R0,指数幂R2中。出口参数:AY值应存于R4R3中(R4中为高字节)。

ORG1000HBCDB:PUSHPSW;保护现场

PUSHACCPUSHBMOVR4,#00H;R4清令

MOVA,@R0MOVR3,A

;万位BCD码送R3LOOP:MOVA,R3

;R3送AMOVB,#10MULAB

;A×10送BAMOVR3,A ;R3×10低位送R3MOVA,#10XCHA,B XCHA,R4 ;R3×10高位送R4 MUL AB ;R4×10ADDA,R4

XCH A,R3 INC R0 ADD A,@R0 XCH A,R3 ADDCA,#00H MOV

R4,A;完成R4R3R4R3+(R0)

DJNZR2,LOOP

;若未完,则转LOOP执行。

POPB

;恢复现场

POPACCPOPPSWRET

;返回程序中,R2中初值为位数n减1,对于五位BCD码,R2中初值位4。4.5.2运算程序设计运算程序可分为浮点数运算程序和定点数运算程序两大类。浮点数就是小数点不固定的数,其运算通常比较麻烦,常由阶码运算和数值运算两部分组成;定点数就是小数点固定的数,通常包括整数、小数和混合小数等,其运算比较简单,但在数位相同时定点数的表示范围比浮点数的小。以下只介绍定点数运算程序设计,若无特别说明,则所有

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论