单片机Flash模拟EEPROM的核心约束是擦写寿命有限、最小擦除单位为页、写前必须先擦。这导致不能直接覆盖写,需搬移数据、整页擦除重写,进而引出磨损均衡需求。

单片机 Flash 模拟 EEPROM 的核心约束是什么
Flash 模拟 EEPROM 不是“把 Flash 当 RAM 用”,而是利用 Flash 的页擦除、字节写入(部分 MCU 支持)特性,构建一个可随机读写、掉电不丢的键值存储层。关键约束有三个:擦写寿命有限(通常 10k–100k 次)、最小擦除单位是页(不是字节)、写前必须先擦(即使只改一个字节)。这意味着不能直接覆盖写,必须搬移有效数据、合并更新、再整页擦除重写——磨损均衡就从这里开始。
常见错误现象包括:某一页反复被擦写导致提前失效、写入后读出乱码、断电后数据丢失或错位。根本原因往往是忽略页边界对齐、未校验写入结果、或在擦写中途掉电没做恢复逻辑。
怎么设计最简可行的双页轮换结构 双页轮换(Two-page Rolling Buffer)是最适合资源受限单片机的磨损均衡起点。它用两页 Flash(比如 PageA 和 PageB),始终保证其中一页是“当前有效页”,另一页用于累积新写入和更新,通过页头标记(如 magic number + version counter)识别哪页更新、更完整。
实操建议:
立即学习“C++免费学习笔记(深入)”;
- 每页开头预留 16–32 字节作为页头,存
MAGIC(如0xA5A5)、page_version(递增 uint16_t)、valid_entries(有效键值对数量) - 写入时,总往“非当前页”追加新记录(key + value + timestamp + CRC16),不覆盖旧记录;写满或触发刷新时,将当前页中未被新版本覆盖的旧记录+新记录一起复制到目标页,然后擦除原页
- 每次上电初始化时,扫描两页页头,选
page_version更大的那页为当前页;若版本相同,选valid_entries更多的页 - 务必在每次写入后读回校验,并用
FLASH_WaitForLastOperation()(STM32)或等效阻塞等待函数确保完成,否则断电极易损坏页头
如何避免“伪磨损均衡”:页内偏移管理与垃圾回收 很多实现只轮换页,却在单页内无序追加,导致某一页很快写满、被迫提前擦除,实际磨损集中在少数页——这不是均衡,是伪装。真正的关键在于控制页内写入位置和定期压缩。
使用场景:当单页容量为 2KB,每条记录 32 字节(含开销),理论最多存 64 条;但若频繁更新同一 key,旧记录会残留成“垃圾”,不清理就会撑满页。
实操建议:
立即学习“C++免费学习笔记(深入)”;
- 每条记录头部加
key_id(uint8_t)和record_seq(uint16_t),按key_id聚合查找最新值,而非依赖写入顺序 - 定义“垃圾率”阈值(如 >30%),当当前页垃圾记录占比超限时,触发一次后台压缩:遍历当前页,提取所有 key 的最新 record_seq 值,合并写入空闲页,再擦除旧页
- 不要在中断里做擦除;擦除是毫秒级操作,必须放在主循环或低优先级任务中,且需屏蔽全局中断或使用原子标志防止并发访问
- STM32F0/F1 系列注意:Flash 写入前需解锁
FLASH_Unlock(),写完必须锁住FLASH_Lock(),漏锁会导致后续写失败但无报错
为什么 CRC 和写保护位比算法本身更重要 磨损均衡算法再精巧,也扛不住一次掉电写半截或 Flash 寄存器误置。真实项目中最常崩溃的点,不是算法逻辑错,而是校验缺失或保护绕过。
性能与兼容性影响:加 CRC16 每条记录仅多 2 字节、计算开销可忽略;但能立刻捕获写入错位、页头损坏、Flash 位翻转等问题。而启用写保护位(如 STM32 的 WRP 寄存器)可防止 OTA 升级或看门狗复位时意外擦写 EEPROM 区域。
实操建议:
立即学习“C++免费学习笔记(深入)”;
- 每条记录末尾放
CRC16-CCITT(初始值 0xFFFF),读取时全段校验;页头单独校验,失败则整页判为无效 - 在链接脚本(.ld 文件)中严格划分 Flash 区域,例如
.eeprom_section (RX) : { *(.eeprom_data) } > 0x0800F000,并用__attribute__((section(".eeprom_data")))标记变量,避免与代码区重叠 - 首次烧录固件时,用 J-Link 或 OpenOCD 手动擦除 EEPROM 区域(如
flash erase_sector 0 127),否则残留垃圾数据会干扰页头识别 - 调试阶段打开
#define EEPROM_DEBUG_LOG,把关键状态(当前页号、写入地址、CRC 结果)通过 UART 打印,比猜问题快十倍


















