STM32内存分配解析及变量的存储位置

目录

 

内存映射

Flash

RAM

堆栈溢出

总结


内存映射

在一些桌面程序中,整个内存映射是通过虚拟内存来进行管理的,使用一种称之为内存管理单元(MMU)的硬件结构来将程序的内存映射到物理RAM。在对于RAM紧缺的嵌入式系统中,是缺少MMU内存管理单元的。因此在一些嵌入式系统中,比如常用的STM32来讲,内存映射被划分为闪存段(也被称为Flash,用于存储代码和只读数据)和RAM段,用于存储读写数据。

STM32的Flash和RAM地址范围

标题中所说的内存是指STM32的Flash和RAM,下图是ARM Cortex M3的地址映射

从图中我们可以看出,RAM地址是从0x2000 0000开始的,Flash地址是从0x8000 0000开始的。

Flash

代码和数据是存放在Flash中的,下面是将Flash内部进行细分之后的一张图,图中表明了代码段,数据段以及常量在Flash中的位置。

如上图所示,Flash又可以分为这么几个部分。分别是文本段(Text) ,其中文本段中又包含可执行代码(Executable Code)和常量(Literal Value),在文本段之后就是只读数据区域(Read Only Data),当然并不是所有架构的单片机都满足这样一个排布规律,这里只针对于ARM Cortex M3系列的,只读数据段后面接着的就是数据复制段(Copy of Data Section),第一次遇见这个概念的朋友看到数据复制可能会有疑惑,其实这个段充当的作用是存放程序中初始化为非0值得全局变量的初始值,之所以要将初始值存放到这里,是因为全局变量是存放在RAM上的,RAM上的值掉电便丢失,每次上电之后这些变量是要重新赋值的,而重新赋值的值就存放在这里。那为什么不存放初始化为0的全局变量的初始值呢,原因也很简单,既然是初始化为0,那么在上电之后统一对存放初始化为0的全局变量的那块区域清0就好。

下面举一个例子,分析各个变量在上述中的存储位置:

#include <stdio.h>

const int read_only_variable = 2000;

int data = 500;

void my_function(void)
{
    int x=200;
    
    char *str = 'string';

}

在上述代码中,read_only_variable是一个用const修饰的全局变量,它是只读的,存放在flash中的只读数据区域,编译器会给read_only_variable分配一个地址,并将2000这个数据存放到这个位置。data这个变量将存放到RAM中的RW区域中(后面将会详细讲解),但是data后面的初始值500 将会被存放到数据复制区域中,也就是上图中的从下往上的第三个区域,在my_function中的变量x将会被存放到RAM中的堆栈中,将x赋值为200,200将被存储到Flash的Text的常量区中,str是一个char型的指针变量,它指向的是字符串第一个字符存放的位置,然而对于字符串string来讲,它是存放在Text常量区的,所以指针变量指向这个区域的一个地址,但是它终归是局部变量,它指向Flash的一个地址,但是其本身还是存放于RAM中的堆栈上的。

RAM

STM32单片机的片内RAM会被链接文件“分区”,为如下几个段:

如上图所示,RAM中包含了如下几个部分,栈(Stack):存放局部变量和函数调用时返回的地址

堆(heap):由malloc申请,free释放

bss:存放未初始化或者是初始化为0的全局变量

data:存放初始化为非0的全局变量

下面举一个简单的例子来说明变量在各个段中的存储位置:

#include <stdio.h>

int data_var = 500;

int bss_var0;

int bss_var1 = 0;

static int static_var;

void my_function(void)
{
    static int static_var1 = 0;

    int stack = 0;

    char *buffer;
    
    const int value =1;

    buffer = malloc(10);
}

 上述变量的命名已经很清楚的表明了变量处于RAM中的哪一个段,data var是已经初始化的全局变量,存放在RAM的data区,bssvar0和bssvar1是未初始化和初始化为0的全局变量,它们都存放于RAM中的bss段,由static修饰的staticvar和static_var1都存放于bss段,区别只在于两个变量的作用域不同。stack是在函数内部的局部变量,其存放于RAM的栈区域,用const修饰的局部变量value,虽然它是只读的,但是它是存储于RAM中的栈中的,这里也说明一点,并不是所有用const修饰的变量都是存放于只读变量区的。buffer指针变量用malloc函数申请了10字节的内存空间,那这10字节的内存空间位于堆中。

堆栈溢出

如果程序运行过程中,堆得空间也一直在消耗,同时栈的空间也在增加,这时堆和栈如果碰到一起,那么就会造成堆栈溢出,从而导致程序跑飞。

STM32的map文件分析

在用keil编译STM32工程之后,我们会得到一个map文件,map文件的最底部有这么一个信息:

 图中的各个段是和上文所述的能够进行对应起来的,正如下面这张表所示

CodeRO DataRW DataZI Data
Executable CodeRead Only Datadatabs

总结

对于RAM和FLASH空间都有限的MCU来讲,了解各个变量在内存中的存储位置很有必要,它能够很好的帮助我们解决很多问题。

  • 5
    点赞
  • 42
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: STM32是一种广泛应用于嵌入式系统的微控制器系列,而GPS则是一种全球定位系统,将两者结合起来进行数据解析,可以实现位置的定位和追踪功能。 首先,STM32通过串口接收GPS模块发送的原始数据。GPS模块通常使用NMEA(National Marine Electronics Association)协议来发送数据,包括位置、速度、时间等信息。 接收到的数据是以ASCII字符形式存储的,需要使用STM32的串口接收功能将其读取到缓冲区中。然后,通过解析NMEA协议,可以从数据中提取出经纬度、速度等信息。 在解析过程中,可以使用字符串操作函数和数据类型转换函数来提取所需的数值。例如,使用字符串操作函数strstr可以搜索特定的标识符,如"$GPGGA"或"$GPRMC",以定位数据的起始位置;使用sscanf函数可以将字符转换为数字。 然后,可以将提取出的数据存储到相应的变量中,以供后续处理和显示。例如,使用浮点数变量存储经纬度和速度值,使用整数变量存储时间等信息。 最后,可以根据需要对数据进行进一步处理和应用,例如将经纬度转换为地图上的实际位置,计算两点之间的距离等。 需要注意的是,由于GPS数据通常是实时不断发送的,解析过程需要进行周期性的循环读取和处理。同时,为了提高解析效率和减少资源占用,可以使用中断方式进行串口数据接收,并使用DMA(Direct Memory Access)来传输数据。 综上所述,通过使用STM32的串口接收功能和字符串处理函数,可以对GPS模块发送的数据进行解析,并提取出所需的位置和速度等信息,实现GPS数据的解析和应用。 ### 回答2: STM32是一种32位微控制器,它可以通过串口接收GPS模块发送的数据,并进行解析。要解析GPS数据,我们需要首先了解GPS数据的格式和内容。 GPS数据通常以NMEA格式进行传输,其中包含了位置、速度、方向等信息。在STM32中,我们可以使用串口接收数据,并通过解析数据的每个字段来提取所需的信息。 首先,我们需要设置串口的波特率、数据位、停止位和校验位等参数。然后,我们可以使用串口的中断功能来接收数据。当接收到完整的一行数据后,我们可以使用字符串函数来对数据进行分割和解析。 在解析过程中,我们可以使用字符串函数如strtok或strstr来找到特定的字段,比如经度、纬度或速度。然后,我们可以将这些字段的字符串转换为对应的数值型数据,以进行后续的处理和显示。 在进行解析之前,我们需要根据NMEA协议的格式,判断每个字段的起始和结束位置。需要注意的是,不同的GPS模块可能使用不同的NMEA协议版本,所以解析过程中需要根据具体情况进行调整。 解析完数据后,我们可以将提取到的信息显示在LCD等显示设备上,或者通过串口发送给其他设备。 需要注意的是,GPS数据解析过程中需要考虑错误处理和数据的稳定性。比如,如果接收到的数据出现错误或者缺失某些字段,我们需要进行相应的处理,避免对后续的计算和应用造成影响。 通过以上的步骤,我们可以成功地在STM32上进行GPS数据的解析和应用。这可以在很多应用场景中得到广泛的应用,比如车载导航、航空导航和地理信息系统等。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值