ZZZ-02-Flash和SRAM

理解了 Flash 和 SRAM,你就理解了单片机运行时的“数据流向”,我们继续用“工厂”来做比喻

1. 形象比喻:仓库 vs. 办公桌

  • Flash(闪存):像是一个巨大的“仓库”或“说明书珍藏馆”。
    • 里面存放的是固定的、不常变动的东西。比如你写的代码逻辑、出厂预设的固定数据。
    • 特点: 停电了,里面的东西不会丢。但是,往里放东西(烧录代码)比较慢。
  • SRAM(静态随机存取存储器):像是一张“办公桌”或“黑板”。
    • 它是 CPU 正在干活的地方。存放的是正在变动的、临时的数据。比如程序运行时的变量 i、传感器读到的实时温度。
    • 特点: 办公效率极高(读写飞快),但一停电(或复位),黑板上的字就全擦掉了。

2. 它们分别存什么

在 STM32 的开发中,你的程序会被拆成不同的部分分别存放:

Flash 存的是“只读”内容:

  1. 指令代码:你写的 if…elsewhile(1) 编译后变成的机器码。
  2. 常量 (const):比如你在代码里定义的 const int a = 100;。因为它是常量,不需要在运行时修改,所以直接存在 Flash 里省空间。

SRAM 存的是“读写”内容:

  1. 全局变量:程序运行过程中需要一直记录的数据。
  2. 局部变量:函数内部临时定义的变量。
  3. 堆栈 (Stack/Heap):函数嵌套调用时的现场保存、或者你动态申请的内存。

3. 什么是“存储器映射”

这是初学者最容易听懵的词,其实它非常简单。

STM32 的内核(Cortex-M)是一个 32 位的 CPU,它的“视力”范围是 $2^{32}$ 个地址(即 $0x0000 0000$ 到 $0xFFFF FFFF$)。

存储器映射,就是给这些硬件设备分配“门牌号”

  • Flash 的门牌号:通常从 0x0800 0000 开始。当 CPU 想读代码时,它就去这个地址段找。
  • SRAM 的门牌号:通常从 0x2000 0000 开始。当 CPU 想改变量时,它就去这个地址段找。
  • 外设(寄存器)的门牌号:比如 GPIO、定时器,它们的控制开关也被映射到了特定的地址(通常从 0x4000 0000 开始)。

结论: 对 CPU 来说,无论是读 Flash、写 SRAM,还是控制 LED 灯,本质上都只是在不同的地址(门牌号)上读写数据。这就是“万物皆地址”。

4. 核心区别对比表

特性 Flash (闪存) SRAM (内存)
存放内容 程序代码 (Code)、常量 (RO-data) 变量 (RW-data)、堆栈
断电数据 保存 丢失
读写速度 较慢(所以有时需要等待周期) 极快
擦写寿命 有次数限制(约 10 万次) 无限制
起始地址 0x0800 0000 0x2000 0000

总结

graph TD CPU[Cortex-M 内核] -- 访问地址 --> Bus[4GB 总线地址空间] subgraph "0x0000 0000 - 0xFFFF FFFF (总视野)" Bus --> Flash_Space["【Flash 区】
起始: 0x0800 0000"] Bus --> SRAM_Space["【SRAM 区】
起始: 0x2000 0000"] Bus --> Peripheral_Space["【外设寄存器区】
起始: 0x4000 0000"] end subgraph "Flash (仓库: 掉电不丢失)" Flash_Space --> Code[指令代码 .text] Flash_Space --> RO_Data[只读常量 const] end subgraph "SRAM (办公桌: 掉电丢失)" SRAM_Space --> RW_Data[全局变量/静态变量] SRAM_Space --> Stack_Heap[堆栈: 函数局部变量] end subgraph "Peripherals (功能按钮)" Peripheral_Space --> GPIO[GPIO 控制器] Peripheral_Space --> UART[串口/定时器等] end style CPU fill:#f96,stroke:#333,stroke-width:2px style Flash_Space fill:#bbf,stroke:#333 style SRAM_Space fill:#dfd,stroke:#333 style Peripheral_Space fill:#fff4dd,stroke:#333

在图的最上方,CPU 不直接管硬件的名字。它只管发指令:“去 0x0800 0000 取个东西”或者“往 0x2000 0000 写个数字”。

  • 如果地址落在 Flash 范围,它就读到了代码。
  • 如果地址落在 SRAM 范围,它就访问了变量。
  • 如果地址落在 外设(Peripherals) 范围,它就控制了硬件(比如点亮 LED)。
    • 你会发现,控制 GPIO 引脚的寄存器也有地址。这就是为什么在底层驱动里,我们可以通过指针操作来点灯: *(uint32_t *)0x4001080C = 0x00000001; // 假设这是控制灯的地址 这就是 STM32 编程的底层逻辑。
Licensed under CC BY-NC-SA 4.0