加深初学者对单片机堆栈的理解--分析

发布时间:2022-12-19  

  看关于单片机方面的书籍的时候,总是能看到别人说的一些堆栈啊什么的操作,之前看到这个术语就直接跳过,没想到去探究单片机内部的原理。但是最近课程学习微机原理这门课,需要我们写汇编程序,汇编里面经常遇到堆栈这个东西,所以就找了个时间把堆栈给彻底的搞一下。


  如果了解一点汇编编程话,就可以知道,堆栈是内存中一段连续的存储区域,用来保存一些临时数据。通常用来保存CALL指令调用子程序时的返回地址,RET指令从堆栈中获取返回地址。中断指令INT调用中断程序时,将标志寄存器值、代码段寄存器CS值、指令指针寄存器IP值保存在堆栈中。


  堆栈也可以用来保存其他数据。

  堆栈操作由PUSH,POP两条指令来完成;

  堆栈操作的操作数均为子类型(两个字节)进行操作。

  程序内存可以分为几个区,栈区(stack),堆区(Heap),全局区(static),文字常亮区,程序代码区。


  程序编译之后,全局变量,静态变量已经分配好内存空间,在函数运行时,程序需要为局部变量分配栈空间,当中断来时,也需要将函数指针入栈,保护现场,以便于中断处理完之后再回到之前执行的函数。


  栈是从高到低分配,堆是从低到高分配。

  我们一般说的堆栈指的栈。堆栈又分硬堆栈和软堆栈,硬堆栈即SP,从片内RAM的顶部向下生长。软堆栈在硬堆栈跟全局变量区之间的空间,C51函数调用通过R0-R7和栈来实现。


  为什么单片机启动时,不需要用bootloader将代码从ROM搬移到RAM,而ARM则需要。这里我们可以先看看单片机程序执行的过程,单片机执行分三个步骤,取执行---分析指令----执行指令。取指令的任务是:根据PC的值从程序存储器读出指令,送到指令寄存器。然后分析执行执行。这样单片机就从内部程序存储器去代码指令,从RAM存取相关数据。要知道RAM取数的速度是远高于ROM的,但是单片机因为本身运行频率不高,所以从ROM取指令慢并不影响。而ARM不同,cpu运行的频率高,远大于从ROM读写的速度,所以一般有操作系统,都需要将代码部分拷贝到RAM中再执行。


  再来看一个网上很流行的经典例子:

  main.cpp

  int a = 0; 全局初始化区

  char *p1; 全局未初始化区

  main()

  {

  int b; 栈

  char s[] = "abc"; 栈

  char *p2; 栈

  char *p3 = "123456"; 123456/0在常量区,p3在栈上。

  static int c =0; 全局(静态)初始化区

  p1 = (char *)malloc(10); 堆

  p2 = (char *)malloc(20); 堆

  }

  不知道你是否有点明白了,堆和栈的第一个区别就是申请方式不同:栈(英文名称是stack)是系统自动分配空间的,例如我们定义一个 char a;系统会自动在栈上为其开辟空间。而堆(英文名称是heap)则是程序员根据需要自己申请的空间,例如malloc(10);开辟十个字节的空间。由于栈上的空间是自动分配自动回收的,所以栈上的数据的生存周期只是在函数的运行过程中,运行后就释放掉,不可以再访问。而堆上的数据只要程序员不释放空间,就一直可以访问到,不过缺点是一旦忘记释放会造成内存泄露。


  网上一个很好的比喻,摘抄下来,以便理解:

  使用栈就象我们去饭馆里吃饭,只管点菜(发出申请)、付钱、和吃(使用),吃饱了就走,不必理会切菜、洗菜等准备工作和洗碗、刷锅等扫尾工作,他的好处是快捷,但是自由度小。


  使用堆就象是自己动手做喜欢吃的菜肴,比较麻烦,但是比较符合自己的口味,而且自由度大。


  总结:

  其实堆栈就是单片机中的一些存储单元,这些存储单元被指定保存一些特殊信息,比如地址(保护断点)和数据(保护现场)。


  如果非要给他加几个特点的话那就是:1、这些存储单元中的内容都是程序执行过程中被中断打断时,事故现场的一些相关参数。如果不保存这些参数,单片机执行完中断函数后就无法回到主程序继续执行了。


  2、这些存储单元的地址被记在了一个叫做堆栈指针(SP)的地方。

  好了,以上就是这些。



文章来源于:电子工程世界    原文链接
本站所有转载文章系出于传递更多信息之目的,且明确注明来源,不希望被转载的媒体或个人可与我们联系,我们将立即进行删除处理。

相关文章

    不加载该startup_M051.s文件,编译的代码可能会使单片机不能正常工作。 那么什么是堆栈呢?在计算机领域,堆栈是一个不容忽视的概念,但是很多人甚至是计算机专业的人也没有明确堆栈这两种数据结构。堆栈......
    arm 堆栈操作(2024-08-05)
    ) 空堆栈递减 4.EA (empty ascending ) 空堆堆栈的递增 我们很熟悉的X86 堆栈操作,一般是堆栈先指向最后一个有效的数据的低地址 比如 mov esp ,4096,那么......
    调用库占用的一些数据(不太清楚是什么数据),然后再将剩余的空间分配给Heap和Stack。由于内存空间是启动时实现分配好的,所以当动态分配内存的需求过多的时候,就会产生堆栈空间不足的问题。 查阅......
    ) __initial_sp0x20000748Data0startup_stm32f10x_hd.o(STACK) 上面节选中,HEAP是堆的基地址,__initial_sp是栈指针。示意图如下 堆栈地址的设置 在上述图和map中,我么......
    要你了解了它的原理,就能轻易地将它扩展得非常强大,想知道要如何做吗?   一。什么是操作系统?   人脑比较容易接受“类比”这种表达方式,我就用“公交系统”来类比“操作系统”吧。   当我......
    空。OSTaskStkInit()是堆栈初始化函数,用在建立任务的函数OSTaskCreate()中,初始化任务的栈,在arm920t中需要在栈中保存的寄存器和数据为 $task;           LR......
    STM32F0单片机快速入门三: MCU启动过程;1.MCU 代码如何启动 首先我们需要澄清一个问题,什么是 Startup Code,什么是 Bootloader?因为......
    是主程序,而且主程序起始地址为0x8000000时单独运行良好,但是改成0x8007000用bootloader跳转过去就卡死,也是卡死在OS的初始化中。因为单独运行良好,所以排查起来困难些。最终定位是堆栈......
    再设置CPU的堆栈,最后跳转到main()函数。 第三个代码段就是main()函数,在keil c51编译器里main()的段地址名就是?C_START。 还有一个IDATA数据段?STACK就是堆栈......
    单片机的程序结束后都干嘛去了?;对于嵌入式系统,如果没有运行RTOS,那么程序开发中的主函数main()需要通过某种机制使其永远愉快的运行下去,它没有终点。如果想从main函数中退出,具体干什么是......

我们与500+贴片厂合作,完美满足客户的定制需求。为品牌提供定制化的推广方案、专属产品特色页,多渠道推广,SEM/SEO精准营销以及与公众号的联合推广...详细>>

利用葫芦芯平台的卓越技术服务和新产品推广能力,原厂代理能轻松打入消费物联网(IOT)、信息与通信(ICT)、汽车及新能源汽车、工业自动化及工业物联网、装备及功率电子...详细>>

充分利用其强大的电子元器件采购流量,创新性地为这些物料提供了一个全新的窗口。我们的高效数字营销技术,不仅可以助你轻松识别与连接到需求方,更能够极大地提高“闲置物料”的处理能力,通过葫芦芯平台...详细>>

我们的目标很明确:构建一个全方位的半导体产业生态系统。成为一家全球领先的半导体互联网生态公司。目前,我们已成功打造了智能汽车、智能家居、大健康医疗、机器人和材料等五大生态领域。更为重要的是...详细>>

我们深知加工与定制类服务商的价值和重要性,因此,我们倾力为您提供最顶尖的营销资源。在我们的平台上,您可以直接接触到100万的研发工程师和采购工程师,以及10万的活跃客户群体...详细>>

凭借我们强大的专业流量和尖端的互联网数字营销技术,我们承诺为原厂提供免费的产品资料推广服务。无论是最新的资讯、技术动态还是创新产品,都可以通过我们的平台迅速传达给目标客户...详细>>

我们不止于将线索转化为潜在客户。葫芦芯平台致力于形成业务闭环,从引流、宣传到最终销售,全程跟进,确保每一个potential lead都得到妥善处理,从而大幅提高转化率。不仅如此...详细>>