单片机中各类变量存储区域
在单片机中,申请的变量通常存放在内存中,具体存放位置取决于变量的类型、作用域以及存储方式。单片机的内存主要分为数据存储器(RAM)和程序存储器(ROM)两部分。
一、数据存储器(RAM)
1.1 栈区(stack):
.主要解释就是由编译器自动分配和释放,例如我们在某个函数内申请一个局部变量,这个变量会由编译器自动分配一个合适大小的栈区存储。
如下:
#include <stdint.h>
int main(void)
{
uint8_t a; // 定义一个无符号的8位整型局部变量a
return 0;
}
1.2 堆区(Heap):
.如果想将数据存入堆区,必须通过动态内存函数来实现,这些函数允许程序在运行时根据需要分配内存,而不是在编译时静态地分配。以下是如何在堆区申请数据的详细步骤和注意事项:
1.2.1 使用动态内存分配函数
malloc函数:
malloc
(memory allocation)函数用于在堆区分配指定大小的内存块。void* malloc(size_t size);
size
表示要分配的字节数。calloc函数:
calloc
(contiguous allocation)函数也用于在堆区分配内存,但它会自动将分配的内存块初始化为零。void* calloc(size_t num, size_t size);
num
表示要分配的元素个数,size
表示每个元素的字节数。realloc函数:
realloc
(reallocation)函数用于调整之前分配的内存块的大小。void* realloc(void* ptr, size_t size);
ptr
是指向之前分配的内存块的指针,size
是新的内存块大小。ptr
为NULL,realloc
的行为与malloc
相同。使用示例:
#include <stdio.h>
#include <stdlib.h>
int main() {
// 使用malloc分配内存
// 分配一个可以存储10个整数的数组的内存空间
int *arr = (int*)malloc(10 * sizeof(int));
// 检查内存分配是否成功
if (arr == NULL) {
printf("内存分配失败\n");
return 1; // 如果分配失败,返回1并结束程序
}
// 使用calloc分配并初始化内存
// 分配一个可以存储5个浮点数的数组的内存空间,并将所有位初始化为0
float *fArr = (float*)calloc(5, sizeof(float));
// 检查内存分配是否成功
if (fArr == NULL) {
printf("内存分配失败\n");
free(arr); // 释放之前已经分配的内存
return 1; // 如果分配失败,返回1并结束程序
}
// 使用realloc调整内存大小
int newSize = 20; // 新的数组大小
// 重新分配arr指向的内存,使其可以存储20个整数
int *newArr = (int*)realloc(arr, newSize * sizeof(int));
// 检查内存重新分配是否成功
if (newArr == NULL) {
printf("内存重新分配失败\n");
free(fArr); // 释放之前已经分配的内存
free(arr); // 在realloc失败的情况下,原内存仍然有效且需要释放
arr = NULL; // 将arr设置为NULL,避免悬挂指针(指向已释放内存的指针)
return 1; // 如果重新分配失败,返回1并结束程序
} else {
arr = newArr; // 更新arr指针,使其指向新的内存地址
}
// 使用分配的内存(示例)
// 初始化arr数组的每个元素为其索引的平方
for (int i = 0; i < newSize; i++) {
arr[i] = i * i;
}
// 释放内存
free(arr); // 释放arr指向的内存
free(fArr); // 释放fArr指向的内存
return 0; // 程序正常结束,返回0
}
注意事项:
1.3全局/静态变量数据区
使用示例:
uint8_t a=0; //初始化全局变量
uint8_t b; //未初始化全局变量
static uint8_t c=0; //初始化静态变量
static uint8_t d; //未初始化静态变量
int main(void)
{
}
┌────────────────────────────────────────────────────┐
│ 单片机存储区 │ │ ┌──────────────────────────────────────────────┐
│ │ │ 程序存储区(Flash等) │ │ │ └──────────────────────────────────────────────┘ │ │ ┌──────────────────────────────────────────────┐
│ │ │ 数据存储区 │ │ │ │
┌──────────────────────────────────────────┐
│ │ │ │ │ 已初始化的全局/静态变量区 │ │ │ │ │ └──────────────────────────────────────────┘ ┌──────────────────────────────────────────┐
│ │ │ │ │ 未初始化的全局/静态变量区 │ │ │ │ │ └──────────────────────────────────────────┘ │ │ │ └──────────────────────────────────────────────┘
二、程序存储器(ROM)
三、特殊存储区
翻阅很多资料我也没得到一个确切的答案,本人目前直接使用指针操控寄存器,所以不多说这个。
对于使用各类通信接口,可以外部扩展存储数据的存储器,我定义为外部存储器,具体包括EEPROM、FLASH、SDRAM等。
可以使用IIC,SPI等通讯协议操控读写数据。
四、keil编译器输出说明
map文件内容:
如上图所示:
Code是代码占用的空间;
RO-data是 Read Only 只读常量的大小,如const型;
RW-data是(Read Write) 初始化了的可读写变量的大小;
ZI-data是(Zero Initialize) 没有初始化的可读写变量的大小。ZI-data不会被算做代码里因为不会被初始化;
FLASH占用大小为:Code + RO Data + RW Data
RAM占用大小为:RW Data + ZI Data
值得一提的是,有的MCU内部集成了SDRAM作为UI运行的显示缓存,一般是2M/4M/8M/16M,这个时候ZI-data会加上UI运行时的缓存,如下:
map文件内容:
可以看到RW Size 非常庞大,无法计算出实际占用RAM大小,这个时候可以网上寻找RW_IRAM1(单片机不同,这个名称也不同)的位置,算出实际变量占用RAM的大小,如下:
Execution Region RW_IRAM1 (Exec base: 0x20000000, Load base: 0x000570e0, Size: 0x0000bab0, Max: 0x00010000, ABSOLUTE, COMPRESSED[0x00000140]),
大约46K。
五、单片机中注意事项:
作者:sakuraifapig