目录

前言:

一、变量存储空间详解

二、内部FLASH区域

三、内部SRAM区域

四、如果这篇文章能帮助到你,请点个赞鼓励一下吧ξ( ✿>◡❛)~


前言:

        本例程以STM32G070CBT6单片机为例,讲解内存和嵌入式系统中变量的存储空间,这块片子具有128KB的内部FLASH,36KB的内部SRAM存储空间。

一、变量存储空间详解

        这段带有注释的代码示例,说明了定义在不同区域、使用不用修饰符声明的变量的存储区域:

// 常量 var_Flash 存储在 FLASH 中的只读数据段(.rodata)
const int var_Flash = 1;  

// 字符串Hello是常量,存储在内部FLASH中的只读数据段(.rodata),指针p_const是全局变量,存储在SRAM的静态存储区(.data 或 .bss)
const char* p_const = "Hello"; 

//var_Global在函数外定义,是全局变量,存储在SRAM的静态存储区的 .data 段(已初始化)
int var_Global = 5;		
		
void TestCode()    //示例函数
{
    //var_Static是static声明的静态变量,在程序运行期间只初始化一次,存储在SRAM的静态存储区
	Static int var_Static = 5;
    
    //初始化的static变量,存储在SRAM中静态存储区的.data段,程序启动时,初始值50从内部FLASH中加载
	static int value_one = 50;
	
    //未初始化的static变量,存储在SRAM中静态存储区的.bss段,程序启动时,该区域变量自动赋零值
	static int value_two;
	
    //new申请的地址位于SRAM的堆中,大小为10*sizeof(int),但p是一个指针类型的局部变量,存储在SRAM的栈中,它指向new分配的地址
	int* p = new int[10];

    //new和delete要配对使用,在嵌入式系统中慎用new和malloc来进行内存分配,会导致内存碎片化
	delete[] p;	
	
	if( var_Global == 5 )
	{
        //局部变量 var_Local 存储在SRAM的栈空间中,生命周期和if语句一致
		int var_Local = 5;
	}
	
}	

二、内部FLASH区域

        Keil示例图中的IROM指的就是单片机内部的FLASH区域,这部分区域严格读取,是非易失性存储器(NVM),用来存储中断向量表、程序代码、Const声明的常量等。FLASH的起始地址为0x08000000,总共0x00020000Byte大小的空间,转换为10进制就是131072Bytes,对应128KB (128 * 1024Byte) ,资源相当有限了。

        如果想要长久保存一些个人定义的程序运行标志位,可以在程序运行中对FLASH进行写操作,写操作需要对FLASH进行——FLASH解锁,擦除,写入,上锁操作,将标志位写入固定的FLASH扇区内存地址中。

        FLASH存储区域示例如下图所示:

        图中的BootLoader区域是可选配置,用来为单片机提供在线升级,如果代码没有设置BootLoader功能的话(BootLoader小型项目一般用不到),这部分内存区域可以直接存放主程序。

三、内部SRAM区域

        Keil图片中的IRAM指的就是单片机的SRAM区域,等价于我们手机电脑中的“运行内存”,这部分区域依赖系统的内存分配策略进行空间分配,存储的是程序运行过程中使用的变量,包括三个存储区域:栈,堆和静态存储区。这三个存储区域是相互独立的,用来存储不同声明类型的变量。

        SRAM存储区域示例如下图所示:

        栈:存储局部变量和函数形参,地址增加方向是反的,由高向低,先进先出。起始地址位于SRAM地址空间尾部,空间上和堆相邻。

例如:

int main()
{
     char temp1 = 0; //temp1变量存储在SRAM的栈中,地址为0x20008FFF
     char temp2 = 0; //temp2变量存储在SRAM的栈中,地址为0x20008FFE
}

        堆:存储new和malloc申请的变量,地址由低向高增加,位于SRAM内存区域的中间位置,以堆地址为基准,地址减小的方向是静态存储区的位置,地址增加的方向是栈区域的位置。

例如:

int main()
{
     char* p1 = new char[10]; //new申请的地址位于SRAM的堆中,数组首地址为0x20003000
     char* p2 = new char[10]; //new申请的地址位于SRAM的堆中,数组首地址为0x2000300A

     /*new和delete要配对使用,在嵌入式系统中慎用new和malloc来进行内存分配
       ,会导致内存碎片化*/
     delete[] p1;  
     delete[] p2;
}

        静态存储区:存储全局变量,Static声明的静态变量,地址位于SRAM地址起始位置,由0x20000000起,和堆相邻,详见第一部分的代码,就不单独举例了。

        开发者可以通过编译后生成的.map地址映射文件来查看项目中的实际内存分配,这是嵌入式开发的黄金标准。

四、如果这篇文章能帮助到你,请点个赞鼓励一下吧ξ( ✿>◡❛)~

Logo

openvela 操作系统专为 AIoT 领域量身定制,以轻量化、标准兼容、安全性和高度可扩展性为核心特点。openvela 以其卓越的技术优势,已成为众多物联网设备和 AI 硬件的技术首选,涵盖了智能手表、运动手环、智能音箱、耳机、智能家居设备以及机器人等多个领域。

更多推荐