网站首页 > 技术教程 正文
一、NVS简介
官网文档地址
1. 存储类型
nvs是在Flash中存储键值对数据,适合存储小规模的数据,不适合存储大的数据。
写键值对时,key 的最大长度为154个字符, 值支持常用的数据类型, 如:
- uint8_t
- int8_t
- uint16_t
- int16_t
- uint32_t
- int32_t
- uint64_t
- int64_t
- 字符串(以\0结尾)
- 可变二进制数据(BLOB)
2. 命名空间
NVS为每个键值对分配了一个命名空间,命名空间的长度最大为 NVS_KEY_NAME_MAX_SIZE-1 个字符。
3. 注意事项
另外,Flash的操作要注意:
- Flash在写之前要保证页是空的
- 如果nvs分区被截断,如更改分区表布局,或内容区是满的要先擦除分区内容
二、NVS的使用流程
nvs操作是在库: nvs_flash.h中。
1. 配置分区表
如果使用默认的nvs分区操作,这一步可以不用。
2. 擦除NVS空间
(1)删除默认分区
函数定义
esp_err_t nvs_flash_erase(void)
删除名称为"nvs"的默认nvs分区。如果分区已经被初始化了,则先要执行反初始化。
返回值
- ESP_OK on success
- ESP_ERR_NOT_FOUND 分区表中没有找到"nvs"空间
- 其它值很少出现
(2)删除指定分区
esp_err_t nvs_flash_erase_partition(const char *part_name)
参数
- part_name :分区表名称
返回值
与nvs_flash_erase(void)相同
(3) 删除自定义分区
esp_err_t nvs_flash_erase_partition_ptr(const esp_partition_t *partition)
参数
- partition 指向由 ESP 分区 API 获取的分区指针
返回值
- ESP_OK on success
- ESP_ERR_NOT_FOUND 分区表中没有找到指定分区
- ESP_ERR_INVALID_ARG 分区为NULL
- 其它基础闪存错误代码
3. 初始化NVS空间
(1) 函数原型
esp_err_t err = nvs_flash_init();
默认的NVS分区是在分区表中标记为“nvs"的分区。初始化NVS空间时,注意要检查flash是否已满、另外SDK版本与flash中使用的版本是否一致。
(2) 示例
下面是示例初始化代码:
// 初始化nvs flash
esp_err_t err = nvs_flash_init();
// 如果nvs flash 满了就清空
if (err == ESP_ERR_NVS_NO_FREE_PAGES || err == ESP_ERR_NVS_NEW_VERSION_FOUND) {
// NVS partition was truncated and needs to be erased
// Retry nvs_flash_init
ESP_ERROR_CHECK(nvs_flash_erase());
err = nvs_flash_init();
}
ESP_ERROR_CHECK(err);
4. 获取NVS空间的操作句柄
(1) 函数定义
esp_err_t nvs_open(const char *namespace_name, nvs_open_mode_t open_mode, nvs_handle_t *out_handle)
(2) 参数
- namespace_name:命名空间名称。最大长度为 NVS_KEY_NAME_MAX_SIZE-1 个字符,不能为空。
- open_mode:读写标志,NVS_READWRITE或NVS_READONLY。
- out_handle:操作成功(返回代码为零),将在此参数中返回句柄。
(3) 返回值
- ESP_OK:存储句柄是否成功打开
- ESP_FAIL:是否存在内部错误
- ESP_ERR_NVS_NOT_INITIALIZED:存储驱动程序未初始化
- ESP_ERR_NVS_PART_NOT_FOUND:是否找不到标签为“NVS”的分区
- ESP_ERR_NVS_NOT_FOUND :id 命名空间尚不存在,模式NVS_READONLY
- ESP_ERR_NVS_INVALID_NAME:命名空间名称不满足约束
- ESP_ERR_NO_MEM:无法为内部结构分配内存的情况
- ESP_ERR_NVS_NOT_ENOUGH_SPACE:如果没有空间容纳新条目或有太多不同的命名空间(允许的不同命名空间的最大值:254)
(4) 示例
printf("Opening Non-Volatile Storage (NVS) handle... ");
nvs_handle my_handle;
err = nvs_open("storage", NVS_READWRITE, &my_handle);
if (err != ESP_OK) {
printf("Error (%s) opening NVS handle!\n", esp_err_to_name(err));
}
else {
printf("Done\n");
}
5. 读NVS空间
(1) 函数定义
esp_err_t nvs_get_i8(nvs_handle_t handle, const char *key, int8_t *out_value)
esp_err_t nvs_get_u8(nvs_handle_t handle, const char *key, uint8_t *out_value)
esp_err_t nvs_get_i16(nvs_handle_t handle, const char *key, int16_t *out_value)
esp_err_t nvs_get_u16(nvs_handle_t handle, const char *key, uint16_t *out_value)
esp_err_t nvs_get_i32(nvs_handle_t handle, const char *key, int32_t *out_value)
esp_err_t nvs_get_u32(nvs_handle_t handle, const char *key, uint32_t *out_value)
esp_err_t nvs_get_i64(nvs_handle_t handle, const char *key, int64_t *out_value)
esp_err_t nvs_get_u64(nvs_handle_t handle, const char *key, uint64_t *out_value)
esp_err_t nvs_get_str(nvs_handle_t handle, const char *key, char *out_value, size_t *length)
esp_err_t nvs_get_blob(nvs_handle_t handle, const char *key, void *out_value, size_t *length)
(2) 参数
- handle 从nvs_open函数获取的句柄。
- key 键,最大长度为 (NVS_KEY_NAME_MAX_SIZE-1) 个字符,不应为空。
- out_value : 指向输出值的指针。对于nvs_get_str和nvs_get_blob可能是 NULL,在这种情况下,所需的长度将在长度参数中返回。
(3) 返回
- ESP_OK:是否成功检索
- ESP_FAIL:是否存在内部错误,很可能是 NVS 分区损坏
- ESP_ERR_NVS_NOT_FOUND:请求的密钥不存在
- ESP_ERR_NVS_INVALID_HANDLE: 句柄是否已关闭或为 NULL
- ESP_ERR_NVS_INVALID_NAME:如果键名不满足约束
- ESP_ERR_NVS_INVALID_LENGTH:长度是否不足以存储数据
(4) 示例
// Example of using nvs_get_i32:
int32_t max_buffer_size = 4096; // default value
esp_err_t err = nvs_get_i32(my_handle, "max_buffer_size", &max_buffer_size);
assert(err == ESP_OK || err == ESP_ERR_NVS_NOT_FOUND);
// if ESP_ERR_NVS_NOT_FOUND was returned, max_buffer_size will still
// have its default value.
// Example (without error checking) of using nvs_get_str to get a string into dynamic array:
size_t required_size;
nvs_get_str(my_handle, "server_name", NULL, &required_size);
char* server_name = malloc(required_size);
nvs_get_str(my_handle, "server_name", server_name, &required_size);
// Example (without error checking) of using nvs_get_blob to get a binary data
into a static array:
uint8_t mac_addr[6];
size_t size = sizeof(mac_addr);
nvs_get_blob(my_handle, "dst_mac_addr", mac_addr, &size);
6. 保存
(1) 函数定义
esp_err_t nvs_set_i8(nvs_handle_t handle, const char *key, int8_t value)
esp_err_t nvs_set_u8(nvs_handle_t handle, const char *key, uint8_t value)
esp_err_t nvs_set_i16(nvs_handle_t handle, const char *key, int16_t value)
esp_err_t nvs_set_u16(nvs_handle_t handle, const char *key, uint16_t value)
esp_err_t nvs_set_i32(nvs_handle_t handle, const char *key, int32_t value)
esp_err_t nvs_set_u32(nvs_handle_t handle, const char *key, uint32_t value)
esp_err_t nvs_set_i64(nvs_handle_t handle, const char *key, int64_t value)
esp_err_t nvs_set_u64(nvs_handle_t handle, const char *key, uint64_t value)
esp_err_t nvs_set_str(nvs_handle_t handle, const char *key, const char *value)
(2) 参数
- handle : 由nvs_open函数返回的句柄
- key:键名
- value : 值,如果是字符串且有完整的空间,最大值是4000字节;如果空间是碎片化的,则值会减少。
(3) 返回
- ESP_OK:是否设置成功
- ESP_ERR_NVS_INVALID_HANDLE:句柄是否被关闭或为空
- ESP_ERR_NVS_READ_ONLY:只读
- ESP_ERR_NVS_INVALID_NAME:名称是否无效
- ESP_ERR_NVS_NOT_ENOUGH_SPACE:空间不足
- ESP_ERR_NVS_REMOVE_FAILED:闪存写入操作失败导致无法更新数值,但是该值已写入,并且重新初始化nvs后将更新(前提是闪存不会再次写入失败)。
- ESP_ERR_NVS_VALUE_TOO_LONG : 值太长
7. 删除
(1)删除所有命名空间所有值
esp_err_t nvs_erase_all(nvs_handle_t handle)
函数定义
参数
- handle :由nvs_open返回的句柄
返回
- ESP_OK:删除操作成功
- ESP_FAIL:内部错误,一般是NVS分区故障
- ESP_ERR_NVS_INVALID_HANDLE :无效句柄
- ESP_ERR_NVS_READ_ONLY :句柄只读
- 其它值:其它存储驱动问题
(2) 删除指定键
esp_err_t nvs_erase_key(nvs_handle_t handle, const char *key)
参数
- handle:由nvs_open返回的句柄
- key :键,最大 (NVS_KEY_NAME_MAX_SIZE-1) ,不得为空
返回
与nvs_erase_all相同 。
7. 提交修改
(1) 函数定义
esp_err_t nvs_commit(nvs_handle_t handle)
将任何挂起的更改写入非易失性存储。
(2) 参数
- handle :由nvs_open返回的句柄。
(3) 返回
- ESP_OK 写入成功
- ESP_ERR_NVS_INVALID_HANDLE 句柄为空或关闭
- 其它错误代码:存储驱动故障
8. 关闭NVS空间
(1)函数定义
void nvs_close(nvs_handle_t handle)
参数
- handle 要关闭的句柄
三、 其它操作
1. 获取nvs状态
esp_err_t nvs_get_stats(const char *part_name, nvs_stats_t *nvs_stats)
示例:
// Example of nvs_get_stats() to get the number of used entries and free entries:
nvs_stats_t nvs_stats;
nvs_get_stats(NULL, &nvs_stats);
printf("Count: UsedEntries = (%d), FreeEntries = (%d), AllEntries = (%d)\n",
nvs_stats.used_entries, nvs_stats.free_entries, nvs_stats.total_entries);
结构体定义:
struct nvs_stats_t
- size_t used_entries : 存储条目数量
- size_t free_entries :空闲条目数量
- size_t total_entries:有效条目总数
- size_t namespace_count:命名空间数量
2. 计算命名空间内的存储数量
esp_err_t nvs_get_used_entry_count(nvs_handle_t handle, size_t *used_entries)
// Example of nvs_get_used_entry_count() to get amount of all key-value pairs in one namespace:
nvs_handle_t handle;
nvs_open("namespace1", NVS_READWRITE, &handle);
...
size_t used_entries;
size_t total_entries_namespace;
if(nvs_get_used_entry_count(handle, &used_entries) == ESP_OK){
// the total number of entries occupied by the namespace
total_entries_namespace = used_entries + 1;
}
3. 键搜索
esp_err_t nvs_entry_find(const char *part_name, const char *namespace_name, nvs_type_t type, nvs_iterator_t *output_iterator)
esp_err_t nvs_entry_next(nvs_iterator_t *iterator)
esp_err_t nvs_entry_info(const nvs_iterator_t iterator, nvs_entry_info_t *out_info)
示例:
// Example of listing all the key-value pairs of any type under specified partition and namespace
nvs_iterator_t it = NULL;
esp_err_t res = nvs_entry_find(<nvs_partition_name>, <namespace>, NVS_TYPE_ANY, &it);
while(res == ESP_OK) {
nvs_entry_info_t info;
nvs_entry_info(it, &info); // Can omit error check if parameters are guaranteed to be non-NULL
printf("key '%s', type '%d' \n", info.key, info.type);
res = nvs_entry_next(&it);
}
nvs_release_iterator(it);
四、操作示例
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_system.h"
#include "nvs_flash.h"
#include "nvs.h"
void setup() {
//01 初始化nvs flash
esp_err_t err = nvs_flash_init();
//02 如果nvs flash 满了就清空
if (err == ESP_ERR_NVS_NO_FREE_PAGES || err == ESP_ERR_NVS_NEW_VERSION_FOUND) {
ESP_ERROR_CHECK(nvs_flash_erase());
err = nvs_flash_init();
}
ESP_ERROR_CHECK(err);
//03 打开nvs,配置句柄
printf("\n");
printf("Opening Non-Volatile Storage (NVS) handle... ");
nvs_handle my_handle;
err = nvs_open("storage", NVS_READWRITE, &my_handle);
if (err != ESP_OK) {
printf("Error (%s) opening NVS handle!\n", esp_err_to_name(err));
}
else {
printf("Done\n");
//04 读操作
printf("Reading restart counter from NVS ... ");
int32_t restart_counter = 0;
// 如果没有在nvs中设置,则值默认为0
err = nvs_get_i32(my_handle, "restart_counter", &restart_counter);
switch (err) {
case ESP_OK:
printf("Done\n");
printf("Restart counter = %d\n", restart_counter);
break;
case ESP_ERR_NVS_NOT_FOUND:
printf("The value is not initialized yet!\n");
break;
default:
printf("Error (%s) reading!\n", esp_err_to_name(err));
}
//05 写操作
printf("Updating restart counter in NVS ... ");
restart_counter++;
err = nvs_set_i32(my_handle, "restart_counter", restart_counter);
printf((err != ESP_OK) ? "Failed!\n" : "Done\n");
//06 提交修改
printf("Committing updates in NVS ... ");
err = nvs_commit(my_handle);
printf((err != ESP_OK) ? "Failed!\n" : "Done\n");
//07 关闭nvs
nvs_close(my_handle);
}
printf("\n");
// 定时重启模块
for (int i = 10; i >= 0; i--) {
printf("Restarting in %d seconds...\n", i);
vTaskDelay(1000 / portTICK_PERIOD_MS);
}
printf("Restarting now.\n");
fflush(stdout);
esp_restart();
}
void app_main()
{
printf("main");
setup();
}
猜你喜欢
- 2024-10-25 Auto CAD 常用系统变量 cad2020系统变量
- 2024-10-25 做开发十年,我总结出了这些开发经验
- 2024-10-25 Windows高级工程师:GDI/GDI+绘图;基础入门大全
- 2024-10-25 菜比手把手教你破解游戏多开(轻喷)
- 2024-10-25 JVM 完整深入解析 jvm解析阶段
- 2024-10-25 Linux打开的文件过多Too many open file
- 2024-10-25 一文看完Oracle数据库之PGA概念、组成、自动管理、参数及视图
- 2024-10-25 JavaScript 中内存泄漏的原因以及对策
- 2024-10-25 史上最全Oracle文件损坏处理办法(附实验步骤)
- 2024-10-25 C++消息循环GetMessage/TranslateMessage/DispatchMessage
你 发表评论:
欢迎- 01-09单因素方差分析+作图
- 01-09描述性统计分析 之 均值分析
- 01-0986:重复性和再现性分析GRR(2)-GRR均值极差分析法和方差分析法
- 01-09SPC如何做方差分析,意义又在哪里?
- 01-09MedSPSS小课堂——多因素方差分析
- 01-09MedSPSS小课堂——双因素方差分析
- 01-09SPSS单因素方差分析的操作步骤及结果解读,陈老师SPSS数据分析
- 01-0914单因素方差分析:One-Way ANOVA
- 最近发表
- 标签列表
-
- sd分区 (65)
- raid5数据恢复 (81)
- 地址转换 (73)
- 手机存储卡根目录 (55)
- tcp端口 (74)
- project server (59)
- 双击ctrl (55)
- 鼠标 单击变双击 (67)
- debugview (59)
- 字符动画 (65)
- flushdns (57)
- ps复制快捷键 (57)
- 清除系统垃圾代码 (58)
- web服务器的架设 (67)
- 16进制转换 (69)
- xclient (55)
- ps源文件 (67)
- filezilla server (59)
- 句柄无效 (56)
- word页眉页脚设置 (59)
- ansys实例 (56)
- 6 1 3固件 (59)
- sqlserver2000挂起 (59)
- vm虚拟主机 (55)
- config (61)
本文暂时没有评论,来添加一个吧(●'◡'●)