STM32具有和PC机类似的结构组成。那么我们平时听到的RAM和ROM就相当于PC的内存条和硬盘,当然了PC的硬盘和单片机的ROM也并不是所谓的只读,只不过以前的技术原因很难做到多次读写,因为最初的存储器是纸带、熔丝或者其他一次性存储器,因此只能读取,也就是ROM,当然那时候也不需要持续的修改。随着技术的革新,这些最初的ROM慢慢的增大内存、增加写功能、提高读写速度。而ROM的叫法也一直延续下来。
那这两大块内存在单片机上是怎么分布的呢?以F103C8T6为例。 或者看一下默认的分散加载文件,也可以得到ROM和RAM的地址和大小。
CPU就非常快了,上到GHz级别,因此如果需要进行数据的读写,显然ROM速度完全跟不上,但是RAM一断电就没了,所以完美的结构是先从ROM读取到RAM,然后再运行。这就是为什么同时需要ROM和RAM。 ROM保存着需要固化的内容,比如函数到底存储着哪些寄存器操作指令,程序到底定义了哪些全局变量,程序使用了哪些字库、图片或者数组(比如使用查表加速计算)。你下载的程序就存储在这里,比如你使用fromelf --bin !L -o .\BIN\Firmware_F4.bin指令生成了bin文件。(bin文件名称:Firmware_F4.bin 可以自定义)那么这些数据就会固化在0x0800 0000这里,就像这样。
BIN文件数据 而你定义的数组则会存在0x2000 0000这块区域,具体是哪里可以使用取址指令得到地址,例如value数组的地址是:0x20000898。
或者你也可以直接看变量窗口的地址,如下。 变量地址查看 当你写了数据,相应的就可以看到RAM的数值变化。比如执行到60行的时候,第59行的赋值就有了效果。
变量地址&数据查看 相对应的内存处也产生了变化。
随着数组内容的写入可以看到数据的变化过程。
数组数据变化 甚至你还可以看到main函数存在了哪里。
主函数存储地址 又或者你直接查看Map文件。
这是你定义的字库的地址:0x08007B96,或者你也可以用同样的方式把它打印出来。 字库存储地址 同样是数组,一个在RAM,一个在ROM,因为字库不需要更改,所以使用const关键字定义在常量区,也就是ROM。而变量数组需要更改,这里没有赋0以外的值,所以你需要多大的空间,编译器到时候给你去RAM分配就是了,然后编译器再把这些分配地址的指令写进BIN,然后你下载存储到0x0800 0000的单片机的硬盘里,到时候单片机的Cortex-M内核就知道0x2000 0000的那一块地址是属于你的数组了。 如果赋值不是0呢?可以看到,地址还是0x2000 0000这块区域。而main函数的局部变量就需要分配了,有初始非0值相当于预定了,而局部变量只有运行的时候才有会给分配地址。
全局非0初始化存储地址 就好像有初始值相当于交了押金,会给你预定包间,虽然你还没住但是已经有了房间号,而你不初始化只有到了再订包间,所以在这之前你完全不知道你的房间号。并且如果你来晚了还有可能没有包间可用,已经被别人包完了,对应到单片机就是堆栈溢出了。那如果你预定都预定不到的话,就是内存不够了。
|