单片机的堆栈的.docVIP

  1. 1、原创力文档(book118)网站文档一经付费(服务费),不意味着购买了该文档的版权,仅供个人/单位学习、研究之用,不得用于商业用途,未经授权,严禁复制、发行、汇编、翻译或者网络传播等,侵权必究。。
  2. 2、本站所有内容均由合作方或网友上传,本站不对文档的完整性、权威性及其观点立场正确性做任何保证或承诺!文档内容仅供研究参考,付费前请自行鉴别。如您付费,意味着您自己接受本站规则且自行承担风险,本站不退款、不进行额外附加服务;查看《如何避免下载的几个坑》。如果您已付费下载过本站文档,您可以点击 这里二次下载
  3. 3、如文档侵犯商业秘密、侵犯著作权、侵犯人身权等,请点击“版权申诉”(推荐),也可以打举报电话:400-050-0827(电话支持时间:9:00-18:30)。
  4. 4、该文档为VIP文档,如果想要下载,成为VIP会员后,下载免费。
  5. 5、成为VIP后,下载本文档将扣除1次下载权益。下载后,不支持退款、换文档。如有疑问请联系我们
  6. 6、成为VIP后,您将拥有八大权益,权益包括:VIP文档下载权益、阅读免打扰、文档格式转换、高级专利检索、专属身份标志、高级客服、多端互通、版权登记。
  7. 7、VIP文档为合作方或网友上传,每下载1次, 网站将根据用户上传文档的质量评分、类型等,对文档贡献者给予高额补贴、流量扶持。如果你也想贡献VIP文档。上传文档
查看更多
单片机的堆栈的

堆栈是一种数据结构。一直以为堆栈是一个寄存器,惭愧!教科书定义:所谓堆栈,就是只允许在其一端进行数据插入和数据删除的线性表。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的用法了。 写过中断服务函数的人都知道,中断服务函数一般都是 这种形式的 void isr(void) interrupt x (using x) //using x是可选的 { } 教单片机的老师当时说你搞不清using 的含义,写中断服务程序不用用它就万事大吉了。这个说法不能说是没有道理的。很长一段时间我写中断服务程序也是不管这个,直到有一次中断RAM溢出,才感到这个using用好了还是有点用处的。 “8051是一个基于累加器的单片机,具有8个通用寄存器,每个寄存器都是一个单字节的寄存器。这8个寄存器通用寄存器可以认为是一组寄存器或者一个通用寄存器组。8051提供四组可用的寄存器组。当使用中断时,多组寄存器切换将带来许多方便。典型8051 C程序不需要选择或者切换寄存器组,默认使用寄存器组0。寄存器组1·2·3在中断服务程序中使用。”引自北航版《单片机的C语言应用程序设计》 来看具体的程序。 不实用using,默认使用寄存器组0 void Timer0(void) interrupt 1 { TH0 = TH0_VAL; TL0 = TL0_VAL; time_1ms_counter++; if(0==(time_1ms_counter%10)) { ScanCardFlag=1; LCMDisplayAndScanKey();//显示时间 } if(64==time_1ms_counter) { time_1ms_counter=1; } } 对应的汇编语言程序 Timer0: C:0x9D70 C0E0 PUSH ACC(0xE0) C:0x9D72 C0F0 PUSH B(0xF0) C:0x9D74 C083 PUSH DPH(0x83) C:0x9D76 C082 PUSH DPL(0x82) C:0x9D78 C0D0 PUSH PSW(0xD0) C:0x9D7A 75D000 MOV PSW(0xD0),#os_buf(0x00) ;选择寄存器组0 C:0x9D7D C000 PUSH

文档评论(0)

ayangjiayu4 + 关注
实名认证
文档贡献者

该用户很懒,什么也没介绍

1亿VIP精品文档

相关文档