断电以后,程序和设置去哪了?|单片机动画课 11

课程插图

单片机运行时,有程序、有变量,也可能有用户设置。拔掉电源再插回去,程序往往还在,刚才的计数却归零。这些信息为什么命运不同?

关键是它们存放的位置不同。普通 RAM 用来保存运行中的数据,Flash 等非易失存储用来保存掉电后仍需保留的内容。

本文用简化存储框图讲原理,以 Uno R3 为主要例子,并补充 ESP32 的持久化方式。动画非仿真、非实测;“断电”指没有保留电源的正常掉电,不讨论特殊保持电路。

程序放在哪里,变量又放在哪里?

你写下的源代码先被编译、链接,得到可供目标芯片运行的固件。上传时写进去的通常是这些编译后的内容,并不是芯片每次开机都重新阅读你的 .ino 文本。

程序存储与运行数据是不同的角色

在 Uno R3 上,程序通常存放在 Flash 中;普通运行变量、栈等使用 SRAM。动画把它们画成两个盒子,是为了区分职责,不表示所有芯片都有完全相同的物理布局和总线结构。

还要区分“存储容量”和“当前数据”。Flash 有空间,不等于程序会自动把每一次变量变化备份进去。让变量加一,通常只是改变运行中的那个值。

例如,把全局计数写成这样:

int count = 0;
// 程序运行中某次事件发生
count++;

源代码规定了初始值为 0,运行时它可以变成 1、2、3。这个运行中的变化,不会反过来改写源代码,也不会自动改写 Flash 中的初始数据。

掉电之后,重新开始

普通 SRAM 需要供电维持内容,完整掉电后不能依赖它保留先前值。Flash 设计用于非易失存储,正常掉电不会像 SRAM 那样丢失程序。

掉电时运行数据不再保留,重新启动后按初始化规则建立变量

注意动画把断电时的 RAM 画成“不可依赖”,而不是画成一个可靠的全零数组。开机后看到计数为 0,通常来自启动和程序初始化规则,不能反推“断电会主动把所有 RAM 写成零”。

对于正常 Arduino 程序,启动过程先建立运行环境,再进入 setup(),随后反复运行 loop()。setup() 的“一次”,是每次正常启动的一次,并不是一块板买回来后永远只执行一次。

不同芯片还可能先经过 ROM 启动代码、引导程序等阶段。它们负责怎样找到应用、是否进入下载模式,属于启动流程的一部分;本课用“启动过程”合并表示,不把某一条路径当作所有开发板的唯一方式。

想保留设置,就要明确保存

如果需要重启后还记得音量、阈值或用户选择,就要通过相应机制,把设置写到非易失存储中;下次启动再读出来。

用户设置先明确保存,重启时再从非易失存储恢复

Uno R3 的 ATmega328P 有 EEPROM,可用于保存少量持久化数据。ESP32 常用基于 NVS 的 Preferences 库保存键值设置。两者 API 和底层实现不同,不能因为都能“记住”就认为写法完全一样。

动画选择一个虚构阈值 25:先在 RAM 中调整,再执行保存;重新启动后,从已保存位置读回。只有明确保存成功,程序才有依据恢复这个值。若从未保存,应用还需要安排默认值。

持久化写入也不是无限免费操作。Flash、EEPROM 都有写入寿命和写入时序约束,不应在高速循环中毫无必要地反复写同一个设置。实际项目常在设置变化、用户确认或合适时机再保存,并检查操作结果。

一个常见误区

“变量加上 const 或 volatile,就可以掉电保存。”这两个关键字描述的是程序语义,不是通用的持久化开关。特别是第 09 课的 volatile,不会让普通 RAM 获得非易失能力。

文件系统、EEPROM、NVS 等不同方案,还可能涉及版本、格式和异常中断后的恢复设计。这一课先抓住共同步骤:明确写入,再在启动时明确读取。

看完再猜

把阈值从 25 改成 30,但只改了 RAM,随后断电。下次从此前保存的位置读取,会自动变成 30 吗?

不会。若上一次保存的是 25,恢复时仍会得到 25。最后一课,我们把前面所有概念放到三类常见开发板上,看看换板时哪些原理相通,哪些条件必须重新确认。

资料:Arduino Memory Guide、Arduino AVR 启动主循环、Espressif Preferences。

发现更多好玩的开源项目

专注 Arduino、开源硬件、端侧 AI 和值得收藏的开发者工具。

课程插图

长按二维码关注「GitStar」

所有动画为教学原理示意,非芯片仿真、非硬件实测。网页发布:2026-09-21。