子程序嵌套是指在子程序执行过程中,还可以调用另一个子程序。堆栈在子程序调用中是必不可少的,因为断点地址均是自动存入堆栈区的。使用子程序进行程序设计会给用户带来很多方便,在实际程序中,特别是监控程序中,经常把一些常用的运算如数码转换、延时、拆字、多字节运算等操作编成子程序,供用户调用,以节省编程时间。
下面通过具体例子说明子程序的设计和调用。
【例4-15】 用程序实现C=a2+b2,设a、b均小于10的整数,a存在31H单元,b存在32 H单元,把C存入33 H单元。
解 因本题两次用到平方值,所以在程序设计中采用把求平方部分编写为子程序的法。
子程序名称:SQR
功能:求X2(通过查平方表来获得)。
入口参数:某个数在A中,出口参数:某个数的平方在A中。
主程序是通过两次调用子程序来得到a2和b2,并在主程序中完成相加。依题意编写主程序和子程序如下:
主程序:
子程序:
求平方的子程序在此采用的是查表法,也可以采用计算法。用伪指令DB将0~9的平方值以表格的形式定义到ROM中。A之所以要加1,是因为RET指令占用了一个字节。
子程序入口和出口参数都是A,不需要进行现场保护。
下面说明一下堆栈内容在程序执行过程中的变化。当程序执行第一条LCALL SQR指令时,断点地址为2208 H,此时08H压入40H单元,22H压入41H单元,2400 H装入PC。当在子程序中执行RET指令时,2208 H弹入PC,主程序接着从此地址执行。当执行第二条LCALL SQR指令时,断点地址为220EH,此时0EH压入40H单元,22H压入41H单元、2400 H装入PC。当在子程序执行RET指令时,220EH弹入PC,主程序接着从此地址运行。
【例4-16】 求两个无符号数据块中的最大值。数据块的首地址分别为60H和70H,每个数据块的第一个字节都存放数据块的长度,结果存入5FH单元。
解 本例可采用分别求出两个数据块的最大值,然后比较其大小的方法,求最大值的过程可采用子程序。
子程序名称:QMAX
子程序入口条件:R1中存有数据块首地址。
出口条件:最大值在A中。
下面分别编写主程序和子程序。(www.daowen.com)
主程序:
【例4-17】 在50 H单元存有两位十六进制数。编程将它们分别转换成ASCII码,并存入到51H、52H单元。
解法1 十六进制数转换成ASCII码的过程可以采用子程序。
子程序名称:HASC
功能:把低4位十六进制数转换成ASCII码(采用查表法)。
入口条件:A中存有待转换的十六进制数。
出口条件:转换后的ASCII码在A中。
由于一个字节单元中有两位十六进制数,而子程序的功能是一次只转换一位十六进制数,所以50 H单元中的两位十六进制数要拆开、转换两次,因此,主程序需两次调用于程序,才能完成一个字节的十六进制数向ASCII码的转换。编写主程序和子程序如下。
主程序:
子程序:
子程序在此采用的是查表法,查表法只需把转换结果按序编成表连续存放在ROM中,用查表指令即可以实现转换,查表法编程方便且程序代码少。
十六进制数转换成ASCII码,也可以采用计算法,但计算法需要判断十六进制数是0~9、还是A~F,以确定转换时是+30 H、还是+37 H,读者可自行编程。
如果要求转换的不是某个单元的两位十六进制数,而是一组数据,数据块的长度在R2中,数据块首地址在R0中,转换结果存放的首地址在R1中,则子程序不变,只修改主程序即可。由于数据块长度已知,源操作数首地址、目的操作数首地址已知,主程序可编成循环程序,故对上述主程序修改如下:
解法2 十六进制数转换成ASCII码的过程仍采用子程序。子程序名称和功能同解法1,与解法1不同的是采用堆栈来传递参数。对应的主程序和子程序如下。
主程序:
子程序:
本例中堆栈的操作示意图见图4-10。当主程序第一次执行PUSH 50 H时,即把50H中的内容压入40 H单元内。执行从ACALL HASC指令后,则主程序的断点地址高低位(PCH、PCL)分别压入41 H、42 H单元。进入子程序后,执行二次DEC SP,则把堆栈指针修正到40 H。此时执行POP A则把40 H中的数据(即50 H单元内容)弹入到A中。当查完表以后,执行PUSH A,则已转换的ASCII码值压入堆栈的40 H单元,再二次执行INC SP,则SP变为42 H,此时执行RET指令,则恰好把原断点内容又送回PC,SP又指向40 H,所以返回主程序后执行POP 51 H,正好把40 H的内容弹出到51 H。第二次调用过程类似,不再赘述。
图4-10 堆栈操作示意图
免责声明:以上内容源自网络,版权归原作者所有,如有侵犯您的原创版权请告知,我们将尽快删除相关内容。