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

下载本文档

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

文档简介

第四章汇编语言程序设计回忆:MCS-51单片机系统硬件资源MCS-51单片机指令系统单片机系统应用程序设计:熟悉单片机的硬件原理掌握单片机的汇编指令二者有机的组合,形成系统应用程序提高单片机控制系统的特性和效率:熟悉控制系统本身的硬件结构熟悉编程思路、技巧,掌握编程方法、步骤

4.1汇编语言程序设计方法

4.2简单和分支程序设计

4.3循环和查表程序设计

4.4子程序和运算程序设计4.1汇编语言程序设计方法

4.1.1程序设计步骤1、汇编语言程序设计:根据设计任务要求,采用汇编语言编制程序的过程。2、应用程序设计步骤:1.拟定任务书2.建立数学模型3.建立算法4.绘制程序流程图5.编制汇编语言源程序6.上机调试

注意:汇编调试需要屡次试验4.1.2程序结构设计的根本方法汇编语言程序设计根本要求:高质量、可读性好、存储容量小和执行速度快汇编程序结构设计的根本方法:1.简单程序的设计

2.分支程序设计3.循环程序设计4.子程序设计5.查表程序设计6.散转程序设计4.2简单和分支程序设计4.2.1简单程序设计[例4.1]

请用51汇编指令编写程序,将外部RAM单元中40H、41H单元4位BCD数转换成ASCII码,送到内部RAM单元80H

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

ORG1000HADDR1DATA0040HADDR2EQU80H

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

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

MOV@R0,A;存入81H

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

MOV@R0,A;存入83HSJMP$

END4.2.2分支程序设计

分支程序的特点是程序中含有转移指令。由于转移指令有无条件转移和条件转移之分,因此分支程序也可分为无条件分支程序和条件分支程序两类。无条件分支程序中含有无条件转移指令,因简单这里不作专门讨论;条件分支程序中含有条件转移指令,是我们讨论的重点。条件分支程序表达了计算机执行程序时的分析判断能力。假设某种条件满足,那么机器就转移到另一分支上执行程序;假设条件不满足,那么机器就按原程序继续执行。MCS-51中,条件转移指令共有13条,分为累加器A判零条件转移、比较条件转移、减1条件转移和位控制条件转移等四类。[例4.2]VAR单元内有一自变量X,请按如下条件编出求函数值Y并将它存入FUNC单元的程序。Y=

解:这是一个三分支归一的条件转移问题,程序实现通常可分为“先分支后赋值〞和“先赋值后分支〞两种求解方法。现分述如下:1.先分支后赋值。题意告诉我们,自变量X是个带符号数,可采用累加器判零条件转移和位控制条件转移指令来实现,程序流程如图4-1(a)所示。相应程序为:ORG1000HVARDATA30HFUNCDATA31HMOVA,VAR;X送AJZDONE;假设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;假设X≠0,那么-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所示。

图4-2[例4.3]程序流程图

A≥95?

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

结束GRADA单元内容加1GRADA和GRADB单元清零、DPTR置初值ENGLISH、循环计数器R2置初值200取某学生外语成绩YYNNYN相应程序为:ORG1000HENGLISHDATA2000HGRADADATA20HGRADBDATA21HMOVGRADA,#00H;GRADA单元清零MOVGRADB,#00H;GRADB单元清零MOVR2,#0C8H;参考总人数送R2MOVDPTR,#ENGLISH;学生成绩始地址送DPTRLOOP:MOVXA,@DPTR;取某学生成绩到ACJNEA,#5FH,LOOP1;和95作比较,形成CyLOOP1:JNCNEXT1;假设A≥95,那么NEXT1CJNEA,#5AH,LOOP2;和90作比较LOOP2:JCNEXT;A<90,NEXTINCGRADB;为B级,那么GRADB单元内容加1SJMPNEXTNEXT1:INCGRADA;A≥95,那么GRADA单元内容加1NEXT:INCDPTR;修改学生成绩指针DJNZR2,LOOP;未完,那么LOOPSJMP$;结束END4.2.3散转程序设计在利用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。解:对于上述要求的问题,编写程序如下:ORG1000HACALLKEYREAD;读键值程序RLA;调整MOVDPTR,#TABLE;表首址送DPTRJMP@A+DPTR;以A中内容为偏移量跳转……………TABLE:AJMPK0;读入键为第1个键,转K0执行AJMPK1;读入键为第2个键,转K1执行……………AJMPK15;读入键为第16个键,转K15执行……………K0:[第1键处理程序段]K1:[第2键处理程序段]………

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

循环程序的特点是程序中含有可以重复执行的程序段,该程序段通常称为循环体。例如,求100个数的累加和是没有必要连续安排100条加法指令的,可以只用一条加法指令并使之循环执行100次。循环程序的组成〔四局部〕:1.循环初始化循环初始化程序段位于循环程序开头,用于完成循环前的准备工作,例如:循环体中循环计数器和各工作存放器设置初值,其中循环计数器用于控制循环次数。循环程序设计不仅可以大大缩短所编程序长度和使程序所占存储单元数最少,也能使程序结构紧凑和可读性变好。

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

完成?初始化循环处理循环控制完成?循环结束(a)先处理后判断〔b〕先判断后处理图4-3循环程序结构类型[例4.5]内部RAM的BLOCK单元开始有一无符号数据块,块长在LEN单元。请编出求数据块中各数累加和、并存入SUM单元的程序。

(a)先判断后处理

(b)先处理后判断

图4-4[例4.5]程序流程图解:为了使读者对两种循环结构有一个全面了解,以便进行分析比较,现给出两种设计方案。1.先判断后处理〔见图4-4(a)〕A←0R2←块长+1R1←BLOCK

完成?A←(A)+((R1))R1←(R1)+1SUM←和NYA←A+(R1)R1←(R1)+1SUM←和完成?A←0R2←块长R1←BLOCKYN求累加和参考程序:ORG1000HLENDATA20HSUMDATA21HBLOCKDATA22HCLRA;A清零MOVR2,LEN;块长送R2MOVR1,#BLOCK;块始地址送R1INCR2;块长+1SJMPCHECKLOOP:ADDA,@R1;A+(R1)送AINCR1;修改数据块指针R1CHECK:DJNZR2,LOOP;假设未完,那么转LOOPMOVSUM,A;存累加和SJMP$END2.先处理后判断〔见图4-4(b)〕参考程序为:ORG1000HLENDATA20HSUMDATA21HBLOCKDATA22HCLRA;A清零MOVR2,LEN;块长送R2MOVR1,#BLOCK;数据始地址送R1NEXT:ADDA,@R1;A+(R1)送AINCR1;修改数据块指针R1DJNZR2,NEXT;假设未完,那么转NEXTMOVSUM,A;存累加和SJMP$END应当注意:上述两个程序是有区别的。假设块长≠0,那么两个程序的执行结果相同;假设块长=0,那么先处理后判断程序的执行结果是错误的。或者说,先处理后判断程序至少执行一次循环体内程序。[例4.6]设单片机MCS-51内部RAM起始地址为30H的数据块中有64个无符号数。试编制一个程序能使它们按从小到大数据排列。解:设有64个无符号数,在数据块中序号为:e64,e63,…,e2,e1,使它们按从小到大顺序排列的方法颇多。现以气泡分类法为例加以介绍。气泡分类法又称两两比较法。它先使e64和e63比较,假设e64>e63,那么两个存贮单元中内容交换,反之就不交换;然后使e63和e62相比,按同样原那么决定是否交换;一直比较下去;最后完成e2和e1比较及交换,经过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比较5e144444256e211112564e300025611e44242256000e53625642424242e62563636363636第二次冒泡排序〔比较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所示。图4-6冒泡程序流程图

Y开始数据块始址送R0块长-1送R2“交换标志位”7FH清零eN送20H和A修改数据指针eN-1送21HeN≥eN-1?“交换标志”7FH=1?eN和eN-1在数据块中位置交换“交换标志”7FH置”1”结束R2-1=0?NNYYN参考程序为:ORG1000HBUBBLE:MOVR0,#30H;置数据块指针R0MOVR2,#64;块长送R2CLR7FH;交换标志2FH.7清零DECR2;块长-1为比较次数BULOOP:MOV20H,@R0;eN送20HMOVA,@R0;eN送AINCR0MOV21H,@R0;eN-1送21HCJNEA,21H,LOOP;(20H)和(21H)比较LOOP:JCBUNEXT;假设(20H)<(21H),那么BUNEXTMOV@R0,20H;假设(20H)≥(21H),那么两者交换DECR0MOV@R0,21HINCR0;恢复数据块指针SETB7FH;置“1〞交换标志位BUNEXT:DJNZR2,BULOOP;假设一次冒泡未完,那么BULOOPJB7FH,BUBBLE;假设交换标志位为1,那么BUBBLESJMP$;结束END在以上循环程序的实例中,单循环程序结构比较简单,程序每循环一次,其循环体就被执行一次。双循环(或多循环)程序就不同了,外循环一次内循环执行一圈。因此,在双重循环和多重循环程序设计中,内层循环体前应注意安排循环初始化,内外循环间也不应相互交叉。查表程序设计

查表是根据存放在ROM中数据表格的项数来查找和它对应的表中值。方法简便,可缩短程序长度和提高程序执行效率。例如:查Y=X2(设X为0~9)的平方表时,可以预先计算出X为0~9时的Y值作为数据表格的内容,存放在起始地址为DTAB的ROM存储器中,并使X的值和数据表格的项数〔所查数据的实际地址对DTAB的偏移量〕一一对应。这样,就可以根据DTAB+X来找到X对应的Y值。采用MCS-51汇编语言进行查表尤为方便,它有两条专门的查表指令:MOVCA,@A+DPTRMOVCA,@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,#17;第一次地址调整指令字节数MOVCA,@A+PC;第一次查表1MOV@R1,A;存第一次转换结果1MOVA,@R0;重新取出被转换数1SWAPA;高4位调入低4位2ANLA,#0FH;取出低4位2ADDA,#09;第二次地址调整1MOVCA,@A+PC;第二次查表1INCR1;修改目的数据块指针1MOV@R1,A;存第二次转换结果1INCR0;修改源数据块指针1INCR1;修改目的数据块指针3DJNZLEN,LOOP;假设未转换完,那么转LOOP2SJMP$;结束ASCTAB:DB‘0’,’1’,’2’,’3’,’4’DB‘5’,’6’,’7’,’8’,’9’DB‘A’,’B’,’C’,’D’,’E’,’F’END4.4子程序和运算程序设计子程序和运算程序是实用程序的两大支柱程序,在汇编语言程序设计中占有极其重要的地位。4.4.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传送出口参数a2或b2给主程序,子程序为求一个数的平方的通用子程序。相应程序如下:ORG1000HMDADATA20HMDBDATA21HMDCDATA22HMOVA,MDA;入口参数a送AACALLSQR;求a2MOVR1,A;a2送R1MOVA,MDB;入口参数b送AACALLSQR;求b2ADDA,R1;a2+b2送AMOVMDC,A;存入MDCSJMP$;结束SQR:ADDA,#01H;地址调整MOVCA,@A+PC;查平方表RET;返回SQRTAB:DB0,1,4,9,16DB25,36,49,64,81END上述程序采用了查表法求一个数的平方,并且通过子程序调用实现了两个数的平方求和,值得注意的是,上述程序仅适应两个数比较小,两个数的平方和不大于用一个字节的数据表示。[例4.9]片内RAM中有一个五位BCD码〔高位在前,低位在后〕,最大不超过65535,始地址在R0中,BCD码位数减1〔04H〕已在R2中,请编出把BCD码转换为二进制整数并存入R4R3中〔R4中内容为高8位〕中的程序。解:此题只编出子程序,主程序从略。①算法设:五位BCD码,y为相应的十六位二进制数,那么以下算式成立:

式中,括号内的数可用加法循环来做,循环次数为指数的幂〔即:BCD位数减1〕,相应的程序流程图如图4-7所示。开始保护现场R4R3R4R3╳10,R0R0+1R4R3R4R3+(R0)R2-1=0?恢复现场结束R4清零,R3万位BCD码图4-7例4-9程序流程

R4R3+((R0))R3R4(R4R3)╳10+((R0))计算过程图示(R4R3)╳10=(R3×10)H+(R4×10)L(R3×10)L(R3×10)H+(R4×10)L+Cy(R3×10)L+((R0))②参考程序入口参数:BCD字节地址指针R0,BCD位数减1在R2中。出口参数:Y值应存于R4R3中〔R4中为高字节〕。ORG1000HBCDB:PUSHPSW;保护现场PUSHACCPUSHBMOVR4,#00H;R4清零MOVA,@R0MOVR3,A;万位BCD码送R3LOOP:MOVA,R3;R3送AMOVB,#10MULAB;(R3)╳10送BAMOVR3,A;MOVA,#10XCHA,B;(B)=10XCHA,R4;(R3)X10高字节存R4MULAB;(R4)X10送BA

ADDA,R4;{(R4)X10低字节}+{(R3)X10高字节}XCHA,R3;A=(R3)X10低字节INCR0;ADDA,@R0;A={(R3)X10低字节}+((R0))XCHA,R3;R3={(R3)X10低字节}+((R0))ADDCA,#00HMOVR4,A;完成R4R3R4R3+〔R0〕DJNZR2,LOOP;假设未完,那么转LOOP执行。POPB;恢复现场POPACCPOPPSWRET;返回程序中,R2中初值为位数n减1,对于五位BCD码,R2中初值为4。4.4.2运算程序设计运算程序可分为浮点数运算程序和定点数运算程序两大类。浮点数就是小数点不固定的数,其运算通常比较麻烦,常由阶码运算和数值运算两局部组成;定点数就是小数点固定的数,通常包括整数、小数和混合小数等,其运算比较简单,但在数位相同时定点数的表示范围比浮点数的小。以下只介绍定点数运算程序设计,假设无特别说明,那么所有程序均指定点数运算程序。1.加减运算程序设计多字节加、减运算是应用程序设计中经常要进行的一种运算,加、减运算程序可以分为无符号多字节数加减运算和带符号多字节数加减运算程序两种。无符号多字节加减运算程序(1)无符号多字节加法运算程序的编制已在前面作过介绍,现以多字节减法程序为例加以介绍。[例4.10]BLOCK1和BLOCK2为起始地址的存储区中分别有5字节无符号被减数和减数〔低位在前,高位在后〕。请编制一个减法子程序,令它们相减,并把差值放入BLOCK1为起始地址的存储单元。解:用减法指令从低字节开始相减。相应程序为:ORG1000HSBYTESUB:MOVR0,#BLOCK1;被减数始址送R0MOVR1,#BLOCK2;减数始址送R1MOVR2,#05H;字长送R2CLRC;Cy清零LOOP:MOVA,@R0;被减数送ASUBBA,@R1;相减,形成CyMOV@R0,A;存差INCR0;修改被减数地址指针INCR1;修改减数地址指针DJNZR2,LOOP;假设未完,那么LOOPRETEND带符号单字节加减运算程序带符号单字节加减运算程序和无符号加减运算程序类似,只是符号位处理上有所差异。[例4.11]设在BLOCK和BLOCK+1单元中有两个补码形式的带符号数。请编出求两数之和,并把它放在SUM和SUM+1单元〔低8位在SUM单元〕的子程序。解:在两个8位二进制带符号数相加时,其和很可能会超过8位数能表示的范围而需要采用16位数形式来表示,因此,在进行加法时,可以预先把这两个加数扩张成16位二进制补码形式,然后对它完成双字节相加。例如:加数和被加数皆为-98〔补码为9EH〕时,扩张成16位二进制形式后相加的算式为:-981111111110011110B+)-981111111110011110B-1961111111100111100B

1最高进位位丧失不计,换算成真值显然也是-196,结果是正确的。因此,一个8位二进制正数扩张成16位时只要把它的高8位变成全“0〞,一个8位二进制负数扩张成16位时需要把它的高8位变成全“1〞。据此,我们在编程时应在加减运算前先对加数和被加数进行扩张,然后完成求和。设R2和R3分别用来存放被加数和加数高8位,那么相应程序为:ORG1000HSBADD:PUSHACCPUSHPSWMOVPSW,#08H;保护现场MOVR0,#BLOCK;R0指向一个加数MOVR1,#SUM;R1指向和单元MOVR2,#00H;高位先令其为零MOVR3,#00HMOVA,@R0;一个加数JNBACC.7,POS1;假设为正数,那么转POS1MOVR2,#0FFH;假设为负数,那么全“1〞送R2POS1:INCR0;R0指向下一个加数MOVB,@R0;取第二加数到BJNBB.7,POS2;假设是正数,那么转POS2MOVR3,#0FFH;假设是负数,那么全“1〞送R3POS2:ADDA,B;低8位相加MOV@R1,A;存8位和INCR1;R1指向SUM+1单元MOVA,R2ADDCA,R3;完成高8位求和MOV@R1,A;存高8位和POPPSW;恢复现场POPACCRETEND在上述程序中,入口:被加数存放在BLOCK,加数存放在BLOCK+1;出口:和的低字节存放在SUM,和的高字节存放在SUM+1。参数传递是利用BLOCK、BLOCK+1、SUM和SUM+1单元实现的。根据本程序,读者编出带符号8位数减法子程序并不困难。〔3〕多字节十进制数BCD码减法由于MCS-51指令系统中只有十进制加法调整指令DAA,也即该指令只有在加法指令〔ADD、ADDC〕后,才能得到正确的结果。为了用十进制加法调整指令对十进制减法进行调整,必须采用补码相加的方法,用9AH减去减数即得到以十为模的减数的补码。[例4.12]多字节十进制BCD码减法子程序如下:入口:被减数低字节地址在R1,减数低字节地址在R0,字节数在R2。出口:差〔补码〕的低字节地址在R0,字节数在R3。07H为符号位,“0〞为正,“1〞为负。原程序为:ORG1000HSBCD:MOVR3,#00H;差字节数置0CLR07H;符号位清0CLRC;借位位清0SBCD1:MOVA,#9AH;减数对100求补码SUBBA,@R0ADDA,@R1;补码相加DAA;十进制相加调整MOV@R0,A;存结果INCR0;地址值增加1INCR1INCR3;差字节增加1CPLC;进位位求反,以形成正确的借位DJNZR2,SBCD1;未减完,转SBCD1,继续JNCSBCD2;无借位,转SBCD2SETB07H;有借位,置“1〞符号位SBCD2:RET;返回主程序程序中,减数求补后与被减数相加,方可利用DAA指令进行调整,假设二者相加调整后结果无进位C=0,实际上表示二者相减有借位;假设二者相加调整后结果有进位C=1,实际上表示二者相减无借位。为了正确反映其借位情况,必须对其进位标志位C进行求反操作,举例说明如下:求BCD码8943H-7649H=?先对低位字节运算:1

温馨提示

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

评论

0/150

提交评论