在一个单片机系统的程序中,往往有许多地方需要执行同样的运算或操作。例如,各种函数的加减乘除运算、代码转换以及延时程序等。通常将这些经常需要重复使用的、能完成某种基本功能的程序段单独编制成子程序,以供不同程序或同一程序反复调用。在程序中需要执行这种操作的地方执行一条调用指令,转到子程序中完成规定操作,再返回原来程序中继续执行下去,这就是所谓的子程序结构。采用子程序结构,可使程序简化,便于调试、交流和共享资源。
1.子程序调用与返回
子程序第一条指令所在的地址称为入口地址,该指令前必须有标号,最好以子程序所能完成的功能名作为标号。例如:求平方子程序以SQR作为标号,延时子程序以DELAY作为标号。
调用子程序指令ACALL或LCALL应放在主程序中,这两条调用指令不仅具有寻址子程序入口地址的功能,而且在转入子程序之前能自动使主程序断点地址入栈,具有保护主程序断点地址的功能。返回指令RET放在子程序的末尾,它具有恢复主程序断点地址的功能,执行返回指令时将断点地址出栈送PC,以便从子程序返回到主程序继续执行。
子程序执行过程中还可以调用其他子程序,这种调用方式称为子程序嵌套或多重转子。
2.参数的现场保护
在转入子程序时,特别是进入中断服务子程序时,要特别注意现场保护问题。即主程序使用的内部RAM的内容、各工作寄存器的内容、累加器A的内容、DPTR以及PSW等特殊功能寄存器的内容都不应该因为转向子程序运行而改变。如果子程序使用的寄存器与主程序使用的寄存器有冲突,则应在转入子程序后首先采取措施保护现场。方法是将要保护的单元的内容压入堆栈保存起来,在返回主程序之前将压入的数据再弹出到原工作单元,恢复主程序原来的状态,即恢复现场。
3.主程序与子程序的参数传递
子程序调用时,要特别注意主程序与子程序之间的信息交换。在调用一个子程序时,主程序应先把与调用相关的参数(入口参数)放到某些特定的位置,子程序在运行时,可以从约定的位置得到相关参数。同样在子程序结束前,也应把子程序运行后的处理结果(出口参数)送到约定位置。当子程序返回后,主程序可从这些位置得到需要的结果,这就是参数传递。参数传递大致可分为以下三种方法。
(1)利用工作寄存器R0~R7或者累加器A实现参数传递
在调用子程序之前把数据送入寄存器或者累加器。调用以后就使用这些寄存器或者累加器中的数据进行操作。子程序执行后,结果仍由这些寄存器或累加器送回。这是一种最常用的方法,其优点是程序简单、速度快,缺点是传递的参数不能太多。
例4-11 用程序实现c=a2+b2。设a、b均小于10,a存于21H单元,b存于22H单元,结果c存于20H单元。
编程思路:本程序中两次用到求平方的运算,因此,把求平方运算设计成子程序以供主程序重复使用。
参考程序如下:
(2)利用指针寄存器传送(www.xing528.com)
数据一般存放在数据存储器中,可用指针来指示数据的位置,这样可大大节省传送数据的工作量,并可实现变长度运算。若数据在内部RAM中,可用R0与R1作为指针,数据在外部RAM或程序存储器中,可用DPTR作为指针。参数传递时只通过R0、R1和DPTR传送数据所存放的地址,调用结束后,传送回来的也只是存放数据的指针寄存器所指的数据地址。
例4-12 设内部RAM中存有3 B BCD码的被减数和减数,它们的首址分别为30H和40H,由低位到高位存放。求它们的差值并存入被减数单元中。
编程思路:由于MCS-51指令系统中无十进制减法指令和十进制减法调整指令,所以在进行十进制减法运算时只能先求减数的十进制补码,将减法变为加法,再用十进制调整指令来调整运算结果,该结果为十进制补码。若CY=1,表示够减无借位,值为正。若CY=0,表示不够减,值为负。两位BCD码减数对100求补,只要将100减去此数即可。因9AH经十进制调整后其值就是100,则减数的求补只需用9AH减原数即可。
例如:求67-35=?,可用9AH-35H+67H=65H+67H=CCH,经十进制调整后结果为132,对应两位十进制数即是32。CY=1表示两数相减的值为正。
参考程序如下:
主程序中通过指针寄存器R0、R1将被减数与减数送入子程序中进行处理,结果在子程序中直接保存,所以无须再传回主程序。
(3)利用堆栈传送
在主程序调用子程序前,可将子程序所需要的参数通过“PUSH”指令压入堆栈。在执行子程序时可用寄存器间接寻址方式访问堆栈,从中取出所需要的参数并在返回主程序之前将其结果送到堆栈中。当返回主程序后,可用“POP”指令从堆栈中取出子程序提供的处理结果。由于使用了堆栈区,应特别注意SP所指示的单元。在调用子程序时,断点处的地址也要压入堆栈,占用两个单元。在返回主程序时,要把堆栈指针指向断点地址,以便能正确地返回。在通常情况下,“PUSH”指令与“POP”指令总是成对使用的,否则会影响子程序的返回。
例4-13 在20H单元存放两位十六进制数,编程将它们分别转换成ASCII码并存入21H、22H单元。
编程思路:由于要进行两次ASCII码转换,故采用子程序来完成,参数传递通过堆栈来完成。
参考程序如下:
主程序通过堆栈将要转换的十六进制数送入子程序,子程序转换的结果再通过堆栈送回到主程序。用这种方式,只要在调用前将入口参数压入堆栈,在调用后把返回参数弹出堆栈即可。子程序开始的两条“DEC”指令和结束前的两条“INC”指令是为了将SP的位置调整到合适的位置,以保证子程序正确返回。
本节对常用的各种编程方法作了比较详细的介绍,并进行了举例说明。但要想真正掌握汇编语言程序设计的方法和技巧,必须经过大量的练习和实践,这样才能提高软件应用能力。
免责声明:以上内容源自网络,版权归原作者所有,如有侵犯您的原创版权请告知,我们将尽快删除相关内容。