电子工程师技术服务社区
公告
登录
|
注册
首页
技术问答
厂商活动
正点原子
板卡试用
资源库
下载
文章
社区
论坛
单片机专区
鸡仔单片机成长记----------------浅谈51堆栈操作
鸡仔单片机成长记----------------浅谈51堆栈操作
单片机
辰__逸
LV3工程师
| 2016-09-08 20:29:43
浏览量 765
回复:2
发表新帖
本帖最后由 辰__逸 于 2016-9-8 20:43 编辑
今天来谈一下51的堆栈操作,堆栈是什么?堆栈是单片机在片内数据存储器中用与存储临时数据的区域,以SP来确定位置,8位寄存器,复位的时候值位07H。可以用MOV SP,#data来改变值。
用GCC来编译C语言中堆栈的操作与用KEIL中C程序对堆栈的操作不一样,下面先来说一下GCC编译中堆栈的操作:
--------------------------------------- GCC中函数调用过程----------------------------------------------
1>保存断点地址,即PC的值入栈,并且将PC的值赋值为要执行函数的地址,实际上是用LCALL实现的。
2>实际参数入栈。
3>为被调用函数分配存储空间。
4>被调函数从栈中取得参数,并开始执行函数体。(通过计算SP的值来计算出参数的地址)
5>被调函数执行结束前(return前),先将返回值入栈,函数执行结束,空间收回。
6>主调函数从栈中获得返回值。
7>主调函数从栈中获得断点地址。并从断点处继续运行(在这里读一下SP的值,栈空间的大小也就能估算了)
注意:每种编译器的处理方式都有些许差别,但是总的流程大体一致。
有些CPU的编译器在参数少的时候且参数类型简单时,会用CPU的寄存器来传递参数,
但碰到参数比较多或者类型复杂的状况时,一定是用stack来传参数。
----------------------------------------Cx51编译器中函数调用--------------------------------------------
1>Cx51为每个参数分配一个特殊的地址
2>函数被调用时,调用者在传递控制权之前必须拷贝参数到分配好的存储区,函数就可以
在从固定的存储区提取参数,在这个过程中,只有返回地址保存在堆栈中,中断函数要更多的空间,因为要保存一些
寄存器的值
3>函数调用之后,出栈PC。调用者继续运行。
注意:在缺省条件下,Cx51最多可以用寄存器传递3个参数,若无寄存器可用,则用固定地址存放。
CPU寄存器经常用来返回函数的返回值。把局部变量分配到固定的内存位置或者寄存器中,而不是堆栈中。
还可能把不同函数的局部变量分到同一位置,这些都是以节约RAM为目的的。
------------------------------------------------实例分析-------------------------------------------------------
#include
void delay(bit b,unsigned char a)
//void delay(unsigned char a,bit b)
{
}
void main()
{
while(1)
{
delay(1,50);
// delay(50,1);
}
}
将上面的程序在KEIL中调试,并观察汇编代码,如下图:
这里的函数先传递参数是位类型的,放在位可寻址区里,第二个参数放在了固定地址里。也没有
用寄存器传递参数啊!!!!!!这是什么鬼,让我们在看一张图:
这里我们可以清晰的看到了,第一个参数放在R7中了,而第二个还是在位可寻址区里面。
别着急,让我们在看一张图:
别急,在来一张:
聪明的人从图中就能看出端倪来了,让我来依次说明下:
1>从第一和第二张图我们可以看到,如果有参数是bit型的,则传递的时候最好是放在最后面,
因为如果第一个参数是bit型的,Cx51就不会把剩下的参数用寄存器去传递,而是放在RAM的特定地址中。
2>Cx51最多只能用3个寄存器来传递参数,如果参数个数大于3个,剩下的就只能放在RAM的特定地址中了。
接下来看一下中断的处理:
从图上可以看出来:在进入中断有PUSH操作,在退出中断的时候有POP操作,这就是所谓的保护现场,而且SP的值也变了,这就是入栈和出栈的过程了。从图中我们还可以看到,堆栈是从高地址向低地址生长的。
今天就到这里了。我这里有关于KEIL的编译文档,现在不在身边,等有时间我传上来吧。
本帖最后由 辰__逸 于 2016-9-8 20:43 编辑
今天来谈一下51的堆栈操作,堆栈是什么?堆栈是单片机在片内数据存储器中用与存储临时数据的区域,以SP来确定位置,8位寄存器,复位的时候值位07H。可以用MOV SP,#data来改变值。
用GCC来编译C语言中堆栈的操作与用KEIL中C程序对堆栈的操作不一样,下面先来说一下GCC编译中堆栈的操作:
--------------------------------------- GCC中函数调用过程----------------------------------------------
1>保存断点地址,即PC的值入栈,并且将PC的值赋值为要执行函数的地址,实际上是用LCALL实现的。
2>实际参数入栈。
3>为被调用函数分配存储空间。
4>被调函数从栈中取得参数,并开始执行函数体。(通过计算SP的值来计算出参数的地址)
5>被调函数执行结束前(return前),先将返回值入栈,函数执行结束,空间收回。
6>主调函数从栈中获得返回值。
7>主调函数从栈中获得断点地址。并从断点处继续运行(在这里读一下SP的值,栈空间的大小也就能估算了)
注意:每种编译器的处理方式都有些许差别,但是总的流程大体一致。
有些CPU的编译器在参数少的时候且参数类型简单时,会用CPU的寄存器来传递参数,
但碰到参数比较多或者类型复杂的状况时,一定是用stack来传参数。
----------------------------------------Cx51编译器中函数调用--------------------------------------------
1>Cx51为每个参数分配一个特殊的地址
2>函数被调用时,调用者在传递控制权之前必须拷贝参数到分配好的存储区,函数就可以
在从固定的存储区提取参数,在这个过程中,只有返回地址保存在堆栈中,中断函数要更多的空间,因为要保存一些
寄存器的值
3>函数调用之后,出栈PC。调用者继续运行。
注意:在缺省条件下,Cx51最多可以用寄存器传递3个参数,若无寄存器可用,则用固定地址存放。
CPU寄存器经常用来返回函数的返回值。把局部变量分配到固定的内存位置或者寄存器中,而不是堆栈中。
还可能把不同函数的局部变量分到同一位置,这些都是以节约RAM为目的的。
------------------------------------------------实例分析-------------------------------------------------------
#include
void delay(bit b,unsigned char a)
//void delay(unsigned char a,bit b)
{
}
void main()
{
while(1)
{
delay(1,50);
// delay(50,1);
}
}
将上面的程序在KEIL中调试,并观察汇编代码,如下图:
这里的函数先传递参数是位类型的,放在位可寻址区里,第二个参数放在了固定地址里。也没有
用寄存器传递参数啊!!!!!!这是什么鬼,让我们在看一张图:
这里我们可以清晰的看到了,第一个参数放在R7中了,而第二个还是在位可寻址区里面。
别着急,让我们在看一张图:
别急,在来一张:
聪明的人从图中就能看出端倪来了,让我来依次说明下:
1>从第一和第二张图我们可以看到,如果有参数是bit型的,则传递的时候最好是放在最后面,
因为如果第一个参数是bit型的,Cx51就不会把剩下的参数用寄存器去传递,而是放在RAM的特定地址中。
2>Cx51最多只能用3个寄存器来传递参数,如果参数个数大于3个,剩下的就只能放在RAM的特定地址中了。
接下来看一下中断的处理:
从图上可以看出来:在进入中断有PUSH操作,在退出中断的时候有POP操作,这就是所谓的保护现场,而且SP的值也变了,这就是入栈和出栈的过程了。从图中我们还可以看到,堆栈是从高地址向低地址生长的。
今天就到这里了。我这里有关于KEIL的编译文档,现在不在身边,等有时间我传上来吧。
0
收藏
举报
分享
×
微信分享
扫描二维码分享
qq分享
QQ空间分享
微博分享
我来回复
登录后可评论,请
登录
或
注册
所有回答
数量:
2
灵澈
2016-09-09
分析的很到位
0
回复
举报
发布
kk118a
2016-09-08
楼主分析的不错,学习了
0
回复
举报
发布
×
举报
举报人:
被举报人:辰__逸
*
类型:
请选择类型
问题质量差
垃圾广告信息
偏离社区主题
违规内容
不友善内容
与社区已有问题重复
以上选项都不是
*
详细原因:
取消
提交
x
收藏成功!点击
我的收藏
查看收藏的全部帖子