通用步骤
本文档总结了 ESP-IDF 中 非易失性存储(NVS)的通用实现流程,涵盖其基础说明、初始化步骤以及相关执行流程。
通过掌握本文档内容,开发者能够快速理解有关 NVS 关键逻辑,为后续示例学习提供统一参考。
非易失性存储(NVS)
概述
NVS(Non-Volatile Storage)是 ESP 提供的非易失性存储机制,保存在其中的数据即使设备断电或重启后仍然不会丢失。它为开发者提供了一种轻量级、可靠的方式来存储设备配置、状态信息或标记类数据。NVS 的设计理念是简单、结构化和持久化,核心特点是以键值对存储数据,并通过命名空间进行组织和隔离,从而避免不同模块之间的数据冲突。NVS 通过内部页管理机制保证数据安全,并提供标准 API 来进行读写、更新和删除操作。
Flash 存储特性
NVS 的数据最终存储在 ESP 芯片的 Flash 上,因此 Flash 的特性直接影响 NVS 的使用:
按页擦写:Flash 数据以页为单位操作,每页通常为 4 KB 或 16 KB,写入前必须先擦除整页。
擦写寿命有限:每个存储单元的擦写次数有限(例如 10 万次),频繁擦写会加速 Flash 损耗。
页管理机制:NVS 写入或更新数据时,如果页空间不足,会触发垃圾回收,将有效数据搬到新页并擦除旧页,以保证数据完整性。
由于这些特性,NVS 不适合存储大文件或频繁更新的数据,例如音频文件、日志文件等,否则容易造成 Flash 提前损坏和性能下降。NVS 更适合保存少量、结构简单的数据,例如:
配置信息:Wi-Fi SSID、密码、蓝牙配对信息等。
用户设置:亮度、音量、语言偏好等。
状态信息:例如上一次运行的模式、计数器值等。
键值对(Key-Value)
NVS 的核心存储单元是键值对,每条数据都以键值对形式存储,从而实现高效且安全的查找、更新和删除操作。每个键值对由两个部分组成:
键:类似标签或名称,为字符串类型,用于唯一标识某条数据,长度有限(最长 15 个字符)。
值:实际要保存的数据,可存储多种数据类型,包括整数(int32_t、int64_t)、字符串或二进制数据(blob)。
写入新数据时,NVS 会找到空闲页空间存储新值。更新已有键时,旧值将被标记为无效,并将新值写入空闲位置,保证数据安全。键值对的概念使 NVS 可以灵活管理不同类型的数据,并且通过唯一键的索引可以快速访问数据。其他说明可参考 键值对。
命名空间(Namespace)
命名空间是 NVS 用于隔离不同模块数据的机制,每个命名空间独立管理自己的键值集合,以避免不同模块使用相同键名导致冲突,同时提供逻辑分组,便于管理和访问。
在 Flash 内部,NVS 会根据命名空间分配页进行管理。写入或更新数据时,会定位到对应命名空间所在的页;如果页满,则触发垃圾回收,将有效数据搬到新页并擦除旧页,从而保证数据完整性和安全性。其他说明可参考 命名空间。
NVS 通用步骤
NVS 初始化
初始化非易失性存储:
调用
nvs_flash_init()
初始化 NVS,完成对存储介质的准备和挂载。相关参数说明请参考 非易失性存储库 API。
检查返回值:
及时发现初始化过程中可能出现的问题,比如 NVS 分区已满或版本不匹配等异常情况,避免程序在后续读写数据时出现错误,导致功能异常甚至崩溃。
若返回异常,调用
nvs_flash_erase()
擦除 NVS 分区。相关参数说明请参考 非易失性存储库 API。
ESP_ERR_NVS_NO_FREE_PAGES
:表示 NVS 分区已满,没有可用的空闲页,无法写入新数据。
ESP_ERR_NVS_NEW_VERSION_FOUND
:表示当前 NVS 分区的数据版本与库期望版本不匹配,可能需要升级或格式化分区。擦除分区后需要重新调用初始化函数,并再次检查返回值,确保初始化成功。
打开 NVS 句柄
创建
nvs_handle_t
类型的句柄变量,用于后续存储 NVS 句柄。相关说明可参考 非易失性存储库。调用
nvs_open()
获取指定命名空间的 NVS 句柄,用于对其中的键值对进行读写操作。相关使用及参数说明可参考 非易失性存储库。
..note:
获取句柄时,如果指定的命名空间不存在,``nvs_open()`` 会在默认分区中自动创建该命名空间,并返回访问句柄;如果命名空间已存在,则直接返回其访问句柄。
数据读写
整数值读写:
字符串读写:
..note:
调用 ``nvs_set_*()`` 写入数据时,数据并不是立即写入闪存,而是先存放在 RAM 中的缓存或 NVS 内部管理的数据结构里。这样做可以减少闪存写操作,延长闪存寿命,并提高写入效率。
查询 NVS 键值
使用迭代器遍历指定命名空间下的所有键,并根据需求执行相应操作。具体说明可查看 NVS 迭代器。
删除 NVS 键值
调用
nvs_erase_key()
删除指定键。相关使用及参数说明可参考 非易失性存储库。
提交更改
调用
nvs_commit()
提价更改,确保将对 NVS 的更改写入闪存存储。相关使用及参数说明可参考 非易失性存储库。
..note:
将之前通过 ``nvs_set_*()`` 写入的所有数据真正写入闪存,保证数据持久化。如果不调用 ``nvs_commit()``,即使程序运行结束或断电,RAM 中的数据不会保存到闪存,写入会丢失。
关闭 NVS 句柄
调用
nvs_close()
关闭 NVS 句柄,释放资源。相关使用及参数说明可参考 非易失性存储库。