基于MCS-51内核的汇编-子程序设计

子程序是什么?
实际编程过程中,为减轻程序代码的量,将一些经常用到的指令集称之为子程序;这里可以类比一下C语言中的延时函数delay()等等;
功能:
为了解决同一组程序代码被反复使用的麻烦操作,每次要用到的时候调用一下就好了;
子程序被调执行特点:
1. 被其他程序调用;
2. 执行完后又需要把执行流程返回到该子程序的主程序;
~一条华丽的分割线~~~
以上说的内容过于简单,相信学过一点其他语言的同志都可以深刻理解了,这里我们主要是针对汇编语言进行的讲解;来阐述我们经常用高级语言却习惯性忽视的细节(细节也即是高级语言直接优化,而不被看到的功能)
重点来了!
子程序调用时要注意的两点:
1. 现场的保护和恢复;
2. 主程序与子程序参数的传递

现场的保护和恢复
来想一个场景:
在调用子程序之前,单片机的某个通用单元里(累加器A)储存了一个等子程序执行完毕后继续用的有价值的数据;但是由于这个通用单元在执行子程序的时候被用了;出子程序后发现那个值已经不复存在了;GG了;
好吧,给予这种情况下,我们有了保护恢复的说法;
通用单元有:R0~R7,累加器A,数据指针DPTR,标志和状态等;

参数传递

  1. 利用累加器传送参数
    这种方式可以直接 “将计就计”,反正值已经在累加器A中了,在子函数中直接用就好了,子程序返回值得时候也是直接返回值给累加器A就好;

    举个栗子:

/*假设内存地址30H,31H,32H,33H,分别用来存放a,b,c,d的数值,现在要求除d=a平方+b平方+c平方*/
			ORG 0000H			 ;设置程序起始存储地址
START:		MOV A,30H			 ;将地址30H中的数据取出来送给累加器A
				ACALL SQR			 ;调用查平方表 (平方表就是DB定义的数组)
				MOV R1,A			 ;a平方暂放在R1中
				MOV A,31H			 ;将地址30H中的b的值取出来送给累加器A
				ACALL SQR			 ;调用子程序`这里写代码片`
				ADD A,R1			 ;A=a方+b方
				MOV R1,A			 ;R1 = A
				MOV A,32H
				ACALL SQR
				ADDC A,R1
				MOV 33H,A
				SJMP $
				;子程序
SQR:			MOV DPTR,#TAB				   ;将平方表的首元素地址给DPTR数据指针
				MOVC A,@A+DPTR					;将TAB平方表中的相应数据值赋予给累加器A
				RET 							;子程序返回指令,执行后,栈顶的两个内容弹出送到PC中,SP(栈顶指针)减2;然后将16位地址放入PC中;
TAB:			DB 0,1,4,9,6,25,36,49,64,81	  ;DB为定义字节指令,后面的每个数据都占一个字节;
				END
  1. 利用堆栈传送参数
    这里补充一个堆栈概念:
    堆栈是什么:储存区域;内存RAM中开辟的一块储存区域;
    堆栈作用:专门用来暂时存放数据或存放返回地址;

    堆栈传送参数是什么:
    利用堆栈传递参数常用于子程序嵌套中长采用的一种方法;
    怎样传递参数:
    在调用子程序之前,用PUSH指令将子程序中所需数据压入堆栈,
    执行子程序时,再用POP指令从堆栈中弹出数据;

    举个栗子:

/*问题:
	编写0!+1!+2!+3!+4!的子程序。
	20H单元存放要进行阶乘的数,30H单元存放每次调用子程序计算后的阶乘
	遇到的问题在程序的第30行和第31行
*/
		ORG 0000H

		MOV SP,#60H		;初始化SP=60H;注意,这里的60H是地址而不是整数;
		MOV 20H,#0H		;存放要进行阶乘的数;
		MOV R2,#04H		;循环次数
		MOV A,#0H

START:	PUSH 20H		;SP=SP+1,将整数20H给地址为61H的堆栈区寄存器
		PUSH ACC	  	;SP=SP+1,这里将ACC内储存的整数值赋予到地址为62H的寄存器单元,这里不应该是A而是ACC
		ACALL MU		;调用MU处的子程序,SP=SP+2,将此处PC的地址送给SP
		POP ACC
		POP 30H
		ADD A,30H
		INC 20H						
		DJNZ R2,START				 
		SJMP $

MU:		MOV R1,SP	;借用R1为堆栈指针
		DEC R1		;程序时要保护现场
		DEC R1 		;程序时要保护现场
		DEC R1 
		DEC R1		;R1指向要进行阶乘的数
		
		MOV A,@R1	;取出要进行阶乘的数
		ADD A,#02H	;				   ?为什么A要加2?是不是和第31行的程序有关?
		MOVC A,@A+PC	;查表		   ?CP怎样从自上而下执行程序的状态转变成查表状态的
		XCH	A,@R1		 ;整字节交换
		RET				 ;返回主程序的地址
TAB:	DB 0,1,2,6,24,120
		END		
	
	知识补充:
	在以上程序代码的时候出现过这么一个问题:
	PUSH A
	POP  A
	报错:表达式不匹配
	PUSH ACC
	POP ACC
	不报错;
	错误原因:
	虽然A和ACC是一个东西;但是……PUSH和POP指令后面一定是直接地址,然而A被编译成累加器A(非地址),编译器编译时A被认为是寄存器,ACC被认为是特殊功能寄存器(地址);所以报错;
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值