打印
[应用相关]

STM32 内存五区及堆栈空间大小设置

[复制链接]
251|0
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
晓伍|  楼主 | 2025-3-10 21:36 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
一、引言
在使用 STM32 微控制器进行嵌入式开发时,了解其内存结构是非常重要的。STM32 的内存可以大致分为五个区域,分别是代码区、常量区、全局(静态)数据区、堆区和栈区。合理设置堆栈空间的大小对于程序的稳定性和性能有着关键的影响。本文将详细介绍 STM32 的内存五区以及堆栈空间大小的设置方法,并给出相应的代码示例。

二、STM32 内存五区
2.1 代码区(Code Area)
代码区也称为文本段(Text Segment),用于存放程序的机器码。这部分内存是只读的,在程序运行期间不会被修改。代码区通常位于 Flash 存储器中,因为 Flash 具有非易失性,适合存储程序代码。例如,我们编写的 C 或 C++ 代码经过编译和链接后生成的机器指令就存放在这里。

2.2 常量区(Constant Area)
常量区用于存放程序中的常量数据,如字符串常量、数值常量等。这些常量在程序运行期间不会改变,同样也是只读的。常量区一般也位于 Flash 存储器中,与代码区相邻。例如,const int a = 10; 这样的常量定义就会存储在常量区。

2.3 全局(静态)数据区(Global and Static Data Area)
全局(静态)数据区用于存放全局变量和静态变量。全局变量是在函数外部定义的变量,而静态变量是使用 static 关键字定义的变量。这个区域又可以分为已初始化数据段(Data Segment)和未初始化数据段(BSS Segment)。

已初始化数据段:存放已经初始化的全局变量和静态变量。例如,int globalVar = 20; 这样的变量就存储在已初始化数据段中。
未初始化数据段:存放未初始化的全局变量和静态变量。这些变量在程序启动时会被自动初始化为 0。例如,int uninitVar; 就存储在未初始化数据段中。
2.4 堆区(Heap Area)
堆区是用于动态内存分配的区域。程序在运行时可以通过 malloc()、calloc()、realloc() 等函数从堆区申请内存空间,使用完后再通过 free() 函数释放。堆区的内存分配是由程序员手动管理的,这意味着如果使用不当,可能会导致内存泄漏等问题。堆区通常位于内存的较高地址部分。

2.5 栈区(Stack Area)
栈区用于存储函数调用时的局部变量、函数参数、返回地址等信息。栈是一种后进先出(LIFO)的数据结构,函数调用时会在栈上分配空间,函数返回时会释放这些空间。栈区的内存管理是由编译器自动完成的,程序员不需要手动干预。栈区通常位于内存的较低地址部分。

三、堆栈空间大小设置
3.1 栈空间大小设置
栈空间的大小在链接脚本(Linker Script)中进行设置。不同的开发环境和工具链,链接脚本的位置和格式可能会有所不同。以 Keil MDK 为例,链接脚本文件通常是 .sct 文件。以下是一个简单的链接脚本示例,用于设置栈空间的大小:

; 链接脚本示例
LR_IROM1 0x08000000 0x00100000  {    ; 定义代码区的起始地址和大小
  ER_IROM1 0x08000000 0x00100000  {  ; 代码区
   *.o (RESET, +First)
   *(InRoot$$Sections)
   .ANY (+RO)
  }
  RW_IRAM1 0x20000000 0x00020000  {  ; 数据区
   .ANY (+RW +ZI)
  }
  ; 设置栈空间大小为 0x1000 字节
  __initial_sp = 0x20000000 + 0x00020000;
  __stack_size = 0x1000;
}




在上述示例中,__stack_size 被设置为 0x1000 字节,即 4096 字节。这个值可以根据程序的实际需求进行调整。

3.2 堆空间大小设置
堆空间的大小同样可以在链接脚本中进行设置。以下是在上述链接脚本的基础上添加堆空间设置的示例:

; 链接脚本示例,包含堆空间设置
LR_IROM1 0x08000000 0x00100000  {    ; 定义代码区的起始地址和大小
  ER_IROM1 0x08000000 0x00100000  {  ; 代码区
   *.o (RESET, +First)
   *(InRoot$$Sections)
   .ANY (+RO)
  }
  RW_IRAM1 0x20000000 0x00020000  {  ; 数据区
   .ANY (+RW +ZI)
  }
  ; 设置栈空间大小为 0x1000 字节
  __initial_sp = 0x20000000 + 0x00020000;
  __stack_size = 0x1000;
  ; 设置堆空间大小为 0x800 字节
  __heap_base = __initial_sp - __stack_size;
  __heap_limit = __heap_base + 0x800;
}



在这个示例中,堆空间的大小被设置为 0x800 字节,即 2048 字节。__heap_base 表示堆区的起始地址,__heap_limit 表示堆区的结束地址。

四、代码示例
以下是一个简单的 STM32 代码示例,演示了全局变量、局部变量、堆内存分配的使用:

#include "stm32f10x.h"

// 全局变量,存储在全局(静态)数据区
int globalVar = 10;

// 函数,演示栈和堆的使用
void testFunction() {
    // 局部变量,存储在栈区
    int localVar = 20;

    // 动态分配内存,从堆区申请空间
    int *heapVar = (int *)malloc(sizeof(int));
    if (heapVar != NULL) {
        *heapVar = 30;
        // 使用完后释放堆内存
        free(heapVar);
    }
}

int main(void) {
    // 调用函数
    testFunction();

    while (1) {
        // 主循环
    }
}



在这个示例中,globalVar 是全局变量,存储在全局(静态)数据区;localVar 是局部变量,存储在栈区;heapVar 是通过 malloc() 函数从堆区申请的内存空间。

五、总结
了解 STM32 的内存五区结构以及合理设置堆栈空间的大小对于嵌入式开发至关重要。通过正确设置堆栈空间,可以避免栈溢出、内存泄漏等问题,提高程序的稳定性和性能。在实际开发中,需要根据程序的具体需求和内存使用情况,灵活调整堆栈空间的大小。同时,要注意内存的合理使用,避免不必要的内存浪费。
————————————————

                            版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。

原文链接:https://blog.csdn.net/duierrorshuobu/article/details/146002282

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

80

主题

4243

帖子

1

粉丝