二、分支程序设计
在一个实际的应用程序中,程序不可能始终是直线执行的。这就要求计算机能够作出一些判断并根据判断结果作出不同的处理,以产生一个或多个分支,决定程序的流向。
(一)简单分支程序
【例4-6】二进制码与ASCII码的转换。
解:由二进制数和ASCII码之间的关系可知,对于小于等于9的4位二进制数加30H得到相应的ASCII代码,对于大于9的4位二进制数加37H得到相应的ASCII代码。
入口参数:4位二进制数存放于A中。
出口参数:ASCII代码存放于R2中。
程序清单如下:
【例4-7】比较两个8位无符号二进制数的大小,将较大的数存入低地址中(设两数分别存于30 H和31H中)。
解:这是一个简单的分支程序,可以让两数相减,若CY=1,则被减数小于减数。用JNC指令进行判断,程序流程如图4-6所示。
图4-6 [例4-7]流程图
程序清单如下:
【例4-8】16位数据乘法。程序流程如图4-7所示。
图4-7 [例4-8]流程图
解:两个双字节无符号数分别放在R7、R6和R5、R4中。由于MCS-51单片机指令中只有8位数的乘法指令MUL,用它来实现双字节数乘法时,可把乘数分解为
(R7)(R6)=(R7)28+(R6)
(R5)(R4)=(R5)28+(R4)
则这两个数的乘积可表示为
显然,将(R6)·(R4)放入(X02)(X01)中,将(R7)·(R4)和(R6)·(R5)累加到(X03)(X02)中,再将(R7)·(R5)累加到(X04)·(X03)中即可得到乘积结果。
入口:(R7 R6)=被乘数,(R5 R4)=乘数,(R0)=乘积的低位字节地址指针。
出口:(R0)=乘积的高位字节地址指针,指向32位积的高8位。
工作寄存器:R3、R2暂时存放部分积,R1存放进位位。
程序清单如下:
(二)多重分支程序
程序仅判断一个分支条件有时是无法解决问题的,这时需要判断两个或两个以上的条件,通常也称为复合条件。
【例4-9】设变量x存入36 H单元中,求得函数y的值存入37 H中。编程按下式要求给y赋值:
解:要根据x的大小来决定y的值,在判断x>5和x>10时,采用CJNE和JC指令进行判断。程序流程如图4-8所示。
图4-8 [例4-9]程序流程图
程序清单如下:
【例4-10】将ASCII码转换成十六进制数。如果不是十六进制数的ASCII码,用户标志位置“1”。
解:由ASCII码表可知,30H~39H为0~9的ASCII码,41H~46H为A~F的ASCII码。在这些范围内的ASCII码减30 H或37H就可获得对应的十六进制数。
设ASCII码存放于A中,转换结果再放回A中。程序流程如图4-9所示。
图4-9 [例4-10]流程图
程序清单如下:
【例4-11】双字节无符号数除法子程序(16位/8位)。
解:将被除数放在R6R5中,除数放在R4中。执行完毕,R5中为商,R6中为余数。程序框图如图4-10所示。
图4-10 [例4-11]流程图
(三)散转程序
N路分支程序是根据前面运行的结果,可以有N种选择,并且可以转向其中任一处理程序。对于这种结构,首先把分支程序按序号排列,然后按照序号值进行转移如图4-11所示。
图4-11 分支程序结构
【例4-12】根据R7的内容,转向各自对应的操作程序(R7=0,转入OPR0;R7=1,转入OPR1,…,R7=n,转入OPRn),见图4-12。程序清单如下:
图4-12 [例4-12]流程图
【例4-13】256路分支程序。
程序功能:根据R4的值转移到256个目的地址。程序框图如图4-13所示。
入口条件:(R4)=转移目的地址代号(00 H~0FFH)。
出口条件:转移到相应的分支处理程序入口。
程序清单如下:
图4-13 [例4-13]流程图
该程序可以产生256路分支程序,分支程序可以分布在64KB程序存储器的任何位置。该程序根据R4中分支地址代码00 H~0FFH,转到相应的处理程序入口地址FEZI00~FEZIFF,由于入口地址是双字节的,查表前应先把R4的内容乘2。当地址代码为00 H~7FH时(前128路分支)乘2时不产生进位;当地址代码为80 H~0FFH时,乘2会产生进位,当有进位时,使基址高8位DPH的内容加1。
该程序采用“堆栈技术”,巧妙地将查表所得的分支入口地址低8位和高8位分别压入堆栈,然后执行RET指令把栈顶内容(分支程序入口地址)弹入PC实现转移。执行完这段程序后,堆栈指针SP不受影响,仍恢复为原来值。