详解STM32堆栈

发布时间:2024-01-25  

学习STM32单片机的时候,总是能遇到“堆栈”这个概念。分享本文,希望对你理解堆栈有帮助。


对于了解一点汇编编程的人,就可以知道,堆栈是内存中一段连续的存储区域,用来保存一些临时数据。堆栈操作由PUSH、POP两条指令来完成。而程序内存可以分为几个区:


栈区(stack)

堆区(Heap)

全局区(static)

文字常亮区程序代码区

程序编译之后,全局变量,静态变量已经分配好内存空间,在函数运行时,程序需要为局部变量分配栈空间,当中断来时,也需要将函数指针入栈,保护现场,以便于中断处理完之后再回到之前执行的函数。
栈是从高到低分配,堆是从低到高分配。
普通单片机与STM32单片机中堆栈的区别
普通单片机启动时,不需要用bootloader将代码从ROM搬移到RAM。

但是STM32单片机需要。

这里我们可以先看看单片机程序执行的过程,单片机执行分三个步骤:

取指令

分析指令

执行指令

根据PC的值从程序存储器读出指令,送到指令寄存器。然后分析执行执行。这样单片机就从内部程序存储器去代码指令,从RAM存取相关数据。

RAM取数的速度是远高于ROM的,但是普通单片机因为本身运行频率不高,所以从ROM取指令慢并不影响。

而STM32的CPU运行的频率高,远大于从ROM读写的速度。所以需要用bootloader将代码从ROM搬移到RAM。

使用栈就象我们去饭馆里吃饭,只管点菜(发出申请)、付钱、和吃(使用),吃饱了就走,不必理会切菜、洗菜等准备工作和洗碗、刷锅等扫尾工作,他的好处是快捷,但是自由度小。使用堆就象是自己动手做喜欢吃的菜肴,比较麻烦,但是比较符合自己的口味,而且自由度大。

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

如果非要给他加几个特点的话那就是:

这些存储单元中的内容都是程序执行过程中被中断打断时,事故现场的一些相关参数。如果不保存这些参数,单片机执行完中断函数后就无法回到主程序继续执行了。

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

结合STM32的开发讲述堆栈

从上面的描述可以看得出来,在代码中是如何占用堆和栈的。可能很多人还是无法理解,这里再结合STM32的开发过程中与堆栈相关的内容来进行讲述。

如何设置STM32的堆栈大小?

在基于MDK的启动文件开始,有一段汇编代码是分配堆栈大小的。

d6e99b46-59c0-11ec-b2e9-dac502259ad0.png

这里重点知道堆栈数值大小就行。还有一段AREA(区域),表示分配一段堆栈数据段。数值大小可以自己修改,也可以使用STM32CubeMX数值大小配置,如下图所示。

d710eb4c-59c0-11ec-b2e9-dac502259ad0.png

STM32F1默认设置值0x400,也就是1K大小。


Stack_Size EQU 0x400


函数体内局部变量:


void Fun(void){ char i; int Tmp[256]; //...}


局部变量总共占用了256*4 + 1字节的栈空间。所以,在函数内有较多局部变量时,就需要注意是否超过我们配置的堆栈大小。

函数参数:


voidHAL_GPIO_Init(GPIO_TypeDef*GPIOx,GPIO_InitTypeDef *GPIO_Init)


这里要强调一点:传递指针只占4字节,如果传递的是结构体,就会占用结构大小空间。提示:在函数嵌套,递归时,系统仍会占用栈空间。

堆(Heap)的默认设置0x200(512)字节。


Heap_Size EQU 0x200


大部分人应该很少使用malloc来分配堆空间。虽然堆上的数据只要程序员不释放空间就可以一直访问,但是,如果忘记了释放堆内存,那么将会造成内存泄漏,甚至致命的潜在错误。

MDK中RAM占用大小分析

经常在线调试的人,可能会分析一些底层的内容。这里结合MDK-ARM来分析一下RAM占用大小的问题。在MDK编译之后,会有一段RAM大小信息:

d736d352-59c0-11ec-b2e9-dac502259ad0.png

这里4+6=1640,转换成16进制就是0x668,在进行在调试时,会出现:

d74b3360-59c0-11ec-b2e9-dac502259ad0.png

这个MSP就是主堆栈指针,一般我们复位之后指向的位置,复位指向的其实是栈顶:

d75dbd46-59c0-11ec-b2e9-dac502259ad0.png

而MSP指向地址0x20000668是0x20000000偏移0x668而得来。具体哪些地方占用了RAM,可以参看map文件中【Image Symbol Table】处的内容:

d76af862-59c0-11ec-b2e9-dac502259ad0.png


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

相关文章

    竞争格局的关键时刻,因为NVIDIA计划将这种产品纳入即将推出的AI 加速器中。 Blackwell Ultra将采用8个36GB HBM3E 12堆栈模......
    A, @R0; A-((R0))   (3)位地址空间操作,如:   SETB 00H; 20H的D0位置1   (4)工作寄存器的选择操作,如:   MOV PSW, #18H; RS1、RS0置成......
    超低功耗无线 MCU:玩转睡眠模式;支持蓝牙低功耗 (LE) 的设计可让设备长时间处于非工作状态,因此,您可能需要选用具有超低功耗睡眠模式的高能效无线微控制器 (MCU),这对......
    空间的设置是为中断处理和程序跳转时服务的。当系统响应中断或程序跳转时,需要将当前处理器的状态和部分重要参数保存在一段存储空间中,所以对每个模式都要进行堆栈初始化工作,给每个模式的SP定义一个堆栈基地址和堆栈......
    作中使用到的是8位的HT48R006,在开发过程中,需要注意一下几点: 1、在HT-3000中有相关的配置,包括时钟的选择,管脚的功能配置,看门狗的使能,看门狗的喂狗指令方式。 2、寄存......
    由于P89V51RD2可以扩展RAM空间,使这一问题得以解决。我们为它扩展了一片32KB的RAM来构成移植μC/OS-II的硬件平台。这样P89V51RD2就满足了移植μC/OS-II的所有要求。 编译器的选择......
    ) IDATALEN:IDATA存储区的大小<0-256>,可以根据自己的选择修改 IDATA绝对的起始地址总是0 IDATA区涵盖DATA和BIT区(DATA区(直接寻址区)以及 BIT区......
    令来初始化内存(RAM单元) IDATALEN:IDATA存储区的大小《0-256》,可以根据自己的选择修改 IDATA绝对的起始地址总是0 IDATA区涵盖DATA和BIT区(DATA区(直接......
    ) IDATALEN:IDATA存储区的大小<0-256>,可以根据自己的选择修改 IDATA绝对的起始地址总是0 IDATA区涵盖DATA和BIT区(DATA区(直接寻址区)以及 BIT区 (位寻......
    ) IDATALEN:IDATA存储区的大小<0-256>,可以根据自己的选择修改 IDATA绝对的起始地址总是0 IDATA区涵盖DATA和BIT区(DATA区(直接寻址区)以及 BIT区 (位寻......

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

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

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

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

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

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

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