MCS-5l系列单片机指令系统,只提供了单字节和无符号数的加、减、乘、除指令,而在实际程序设计中经常要用到有符号数及多字节数的加、减、乘、除运算,这里,只列举几个典型例子,来说明组织这类程序的设计方法。为了使编写的程序具有通用性、实用性,下述运算程序均以子程序形式编写。
【例4-18】 两个8位有符号数加法,并设加法的和超过8位。
解 编程说明:在计算机中,有符号数一律用补码表示,两个有符号数的加法,实际上是两个数补码相加,由于和超过8位,因此,和就是一个16位符号数,其符号位在16位数的最高位。在进行这样的加法运算时,应先将8位数符号扩展成16位,然后再相加。
符号扩展的原则:若是8位正数,则高8位扩展为00 H;若是8位负数,则高8位扩展为FFH。经过符号扩展之后,再按双字节相加,则可以得到正确的结果。
编程时,寄存器R2和R3做两个加数的高8位,并先令其为全零,即先假定两个加数为正数,然后判别符号位,根据符号位再决定是否将其高8位改为FFH。
子程序入口;(R0)=存放加数的首地址(两个加数连续存放),(R1)=存放和的首地址。
工作寄存器:R2作加数的高8位,R3作另一个加数的高8位。
程序清单如下:
在调用该子程序时,只需把加数及和的地址置入R0和R1,就可以调用这个子程序。
【例4-19】 两个8位有符号数的乘法程序。
编程说明:MCS-51的乘法指令是对两个无符号数求积,若是有符号相乘,应做如下处理:
1)保存被乘数和乘数的符号,并由此决定乘积的符号。决定积的符号时可使用位运算指令进行异或操作——通过位的与、或运算来完成。
2)被乘数或乘数均取绝对值相乘,最后,再根据积的符号,冠以正号或者负号,正数的绝对值是其原码本身,负数的绝对值是通过求补码来实现的。
3)若积为负数,还应把整个乘积求补,变成负数的补码。
子程序入口:(R0)=被乘数,(R1)=乘数。
出口:(R3)=积的高8位,(R2)=积的低8位。
程序流程图如图4-11所示。
图4-11 8位有符号数乘法程序流程图
程序清单如下:
以上对符号数相乘的处理方法,也可以用于多字节带符号数的乘法运算及除法运算。
【例4-20】 两个8位有符号数的除法程序。
编程说明:同单字节有符号数的乘法处理方法类似。也是将被除数、除数取绝对值进行相除,根据被除数和除数的符号确定商的符号,若商为负数,还应把商求补,变成负数的补码。与乘法不同的是,除法还要处理余数,余数的符号应与被除数相同,当余数为负时,应对余数求补。
上例是通过位运算指令进行异或操作来确定积的符号,这里介绍另一种方法,即通过字节的与运算、异或运算来确定商的符号。
子程序入口:(R2)=被除数,(R3)=除数。
出口:(R2)=商,(R3)=余数。
工作奇存器:R4用于暂存被除数符号,R5用于暂存除数的符号或商的符号。
程序流程图如图4-12所示。
图4-12 8位有符号数除法程序流程图
程序清单如下:
【例4-21】 两个16位无符号数乘法程序。
编程说明:由于MCS-5l指令系统中只有单字节乘法指令,因此,双字节相乘只能分解为4次单字节相乘。设被乘数为ab,乘数为cd,其中a、b、c、d都是8位数。它们的乘积运算式可列写如下:
其中,bd H、bd L等为相应的两个8位数的乘积,占16位。以H为后缀的是积的高8位,以L为后缀的是积的低8位。很显然,两个16位数相乘要产生8个字节的部分积,需由8个单元来存放,然后再相加,其和即为所求之积。但这样做占用工作单元太多,一般是另用单字节乘法和加法指令,按上面所列竖式,采用边相乘边相加的方法来进行。
本程序的编程思路即上面算式的运算过程。32位乘积存放在以R0内容为首地址的连续个单元内。
子程序入口:(R7R6)=被乘数(ab),(R5R4)=乘数(cd)(R0)=存放乘积的起始地址。
出口:(R0)=乘积的高位字节地址指针。
工作寄存器:R2R3暂存部分积(R2存高8位),Rl用于暂存中间结果的进位。(www.daowen.com)
程序流程图如图4-13所示。
图4-13 16位无符号数乘法程序流程图
程序清单如下:
本程序用到的算法很容易推广到更多字节的乘法运算中。
【例4-22】 两个16位无符号数除法程序。
解 编程说明:MCS-51系列单片机只有单字节无符号数除法指令,对于多字节除法,在单片机中一般都采用“移位相减”法。
移位相减法:设一个与被除数等长的余数单元(先清零),设一个计数器存放被除数的位数。将被除数与余数单元一起左移一位,然后将余数单元与除数相减,够减,商取1,并将所得差作为余数送入余数单元;不够减,商取零;被除数与余数再一起左移一位,再一次将余数单元与除数相减……,重复到被除数各位均移入余数单元为止。
被除数每左移一位,低位就空出一位,放可用来存放商。因此,实际上是余数、被除数、商三者一起进行移位。
图4-14 16位无符号数除法程序流程图
相除之后,对余数进行四舍五入处理。若余数的最高位为1,则余数一定大于除数的一半,应该使商加1。若余数最高位不为1,对于是否需要进1,可这样来判断;使余数乘以2,再与除数相比,若大于除数,说明余数大于除数的一半,则商应该进1;反之,则不必进加1。余数四舍五入处理后,不再保留。
另外,在进行除法运算之前,可先对除数和被除数进行判别,若除数为零,则商溢出若除数不为零,而被除数为零,则商为零。
子程序的入口:(R7R6)=被除数,(R5R4)=除数。
出口:(R7R6)=商,PSW.5=除数为0标志。
工作寄存器:R3R2作为余数寄存器,R1作为移位计数器,R0作为低8位的差值暂存寄存器。
程序流程图如图4-14所示。
程序如下:
【例4-23】 16位有符号数乘法程序。
解 编程说明:16位有符号数相乘与8位有符号数相乘的算法基本相同。
1)根据被乘数和乘数的符号计算乘积的符号;
2)被乘数、乘数均取绝对值;
3)根据16位无符号数乘法子程序的入口条件设置入口参数,然后调用16位无符号数乘法子程序;
4)当积为负数时,应把整个乘积求补,变成负数的补码。
子程序入口:(R7R6)=被乘数(带符号数),(R5R4)=乘数(带符号数),(R0)=存放乘积的起始地址。
出口:(R0)=32位乘积的高位字节地址指针。
工作寄存器:R2R3用于暂存部分积,R1用于暂存中间结果的进位,内部RAM 2FH单元暂存积的符号。
【例4-24】 16位有符号数除法程序。
编程说明:16位有符号数除法与16位有符号数乘法的算法类似。
1)根据被除数和除数的符号计算商的符号;
2)被除数、除数均取绝对值;
3)根据16位无符号数除法子程序的入口条件设置入口参数,然后调用16位无符号数除法子程序;
4)当商为负数时,应把商求补,变成负数的补码。
子程序入口:(R7R6)=被除数(带符号数),(R5R4)=除数(带符号数)。
出口:(R7R6)=商,PSW.5=除数为零标志。
工作寄存器:R3R2作为余数寄存器,R1作为移位计数器,R0作为差值暂存寄存器,内部RAM 2FH单元暂存商的符号。
通过上述编程实例,介绍了汇编语言程序设计的各种情况。从中可以看出,程序设计主要涉及两个方面的问题:一是算法,或者说程序的流程图;二是工作单元的安排。在以上例子中,8个工作寄存器是够用的。由于间接寻址的寄存器只有R0和Rl,如果不够用,可通过设置RS1、RS0,以选择不同的工作寄存器组,这一点在使用上应加以注意。
免责声明:以上内容源自网络,版权归原作者所有,如有侵犯您的原创版权请告知,我们将尽快删除相关内容。