单片机的堆栈
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
堆栈是一种数据结构。一直以为堆栈是一个寄存器,惭愧!教科书定义:所谓堆栈,就是只允许在其一端进行数据插入和数据删除的线性表。51单片机的单片机的堆栈是在内部RAM中开辟的。这句话表明了堆栈的位置。
那么堆栈到底有什么作用?
堆栈主要是为子程序调用和中断操作而设立的,因此对应有两项功能:保护断点和保护现场。
单片机的程序归根结底是个死循环,反复在执行Main函数(主程序),你可以只写一个函数Main,那么你这个函数随着功能的增多而变得异常大,而且非常不具备可读,这个时候就需要子函数(子程序)了。主函数在调用完子函数后会返回到主函数中,这样就可以调用其它函数并且继续这个死循环。在计算机去执行子函数或者中断服务函数,如何确保程序能够正确地返回到主函数中并且继续正确执行后面的内容?因为在执行子函数或者中断服务函数时,很有可能会破坏寄存器单元的内容,但这些寄存器单元在子函数必须要用到?这个问题看起来比较难解决了。这个时候就要用到断点保护和现场保护了。
保护断点:在调用子程序和堆栈时,将返回地址(执行完子程序或者中断后要执行的下一个指令的的地址(PC 寄存器值)) 送入堆栈,程序返回时,这个值自动弹回PC。这种方式是自动使用堆栈的,程序中一般无需理会。在这个过程中,地址送入堆栈时,堆栈指针SP+2,因为51的寻址范围是64KB,再查看RAM中堆栈单元就可以发现这个时候已经变成了PC的值,在返回的时候SP-2,但是堆栈中的内容在下一次堆栈操作之前不会发生变化。来看下面的仿真图:
程序初始化将SP设置为0x07,这个时候RAM中全部被清零。单步运行。
这个时候SP的值已经变为0x30,但是内容依旧没有改变。
运行到断点。
运行到断点PC的值没什么变化,在执行完Lcall之后,发现RAM中30单元起了变化,0013,PC也+2,而0013就是sjmp st1的地址。
以上是用Protues仿真的结果。在用KEIL做软仿的时候发现SP会变化,但是对应的内容却没有变化,这个是不是KEIL的一个BUG呢?
保护断点是比较简单的,编程者一般不用理会。现场保护就和编程扯上关系了。现场保护:在转中断服务程序或者子程序之前,要把单片机中个有关单元的内容保存起来,这就是所谓的现场保护。有保护当然就有恢复。现场恢复:返回主程序之后恢复寄存器的内容到调用之前的状态。
这里就首先要牵涉一个using的用法了。
写过中断服务函数的人都知道,中断服务函数一般都是这种形式的
教单片机的老师当时说你搞不清using 的含义,写中断服务程序不用用它就万事大吉了。这个说法不能说是没有道理的。很长一段时间我写中断服务程序也是不管这个,直到有一次中断RAM溢出,才感到这个using用好了还是有点用处的。“8051是一个基于累加器的单片机,具有8个通用寄存器,每个寄存器都是一个单字节的寄存器。这8个寄存器通用寄存器可以认为是一组寄存器或者一个通用寄存器组。8051提供四组可用的寄存器组。当使用中断时,多组寄存器切换将带来许多方便。典型8051 C程序不需要选择或者切换寄存器组,默认使用寄存器组0。寄存器组1·2·3在中断服务程序中使用。”引自北航版《单片机的C语言应用程序设计》
来看具体的程序。
使用using 1
从上面的代码可以看出,中断对目标代码的影响如下:
1.当调用中断时,SFR中的ACC,B,DPH,DPL,和PSW入栈;
2.如果不使用寄存器组切换,就是不用using,默认的寄存器组(寄存器组0)需要入栈;
3.退出函数前,所有寄存器内容出栈;
4.函数由8051的指令RETI终止。