ESP-IDF是一款由乐鑫科技(Espressif Systems)开发的面向ESP32和ESP32-S系列芯片的开发框架,NVS(Non-Volatile Storage)是其中的一项功能。
NVS是一种用于在嵌入式系统中保存持久化数据的键值存储库。在ESP-IDF中,NVS提供了一种简单且有效的方法来在ESP32芯片上保存和读取配置信息、状态数据、用户设置等应用程序数据,以便在设备重新启动或断电后能够恢复状态。
NVS在ESP-IDF中具有以下特点和优点:
- 非易失性:NVS中的数据在芯片断电或重新启动后仍然保持不变,不会丢失,适合保存需要长期存储的数据。
- 键值对存储:NVS使用简单的键值对(Key-Value)结构来保存数据,方便进行读取和写入操作。
- 分区管理:NVS将数据存储在不同的分区中,可以根据需要创建多个独立的NVS分区,用于不同的数据类型或应用场景,实现数据隔离和管理。
- API丰富:ESP-IDF提供了丰富的NVS API,包括读取、写入、删除、遍历等操作,方便开发者进行数据的处理和管理。
学习和使用ESP-IDF中的NVS可以带来以下好处:
- 持久化数据存储:NVS允许开发者将配置信息、状态数据等持久化保存在芯片中,即使设备断电或重新启动,数据也能够得到保留,从而避免了数据丢失的情况。
- 简单高效的数据管理:NVS提供了简单易用的API,可以方便地进行数据的读取、写入、删除等操作,减少了开发复杂性和提高了代码效率。
- 数据隔离和管理:NVS支持多个分区的管理,可以将不同类型的数据存储在不同的分区中,实现数据隔离和管理,便于维护和升级。
- 节省存储空间:NVS采用了紧凑的键值对结构,可以高效地利用芯片内部的存储空间,避免了使用外部存储器的成本和复杂性。
因此,学习和使用ESP-IDF中的NVS可以帮助开发者在ESP32和ESP32-S系列芯片上实现持久化数据存储,并简化数据管理和提高应用程序的稳定性和效率。
简单来说,我们可以把nvs比喻成一个“U盘”,那接下来我们就开始对这个“U盘”进行操作吧!
接下来我们做一个简单的演示,代码如下:
#include
#include "nvs_flash.h"
void app_main(void)
{
// 对“U盘”进行初始化
nvs_flash_init();
char *bilibili_name_space = "BiliBili";
nvs_handle_t bilibili_handle;
// 创建一个句柄来打卡它
nvs_open(bilibili_name_space, NVS_READWRITE, &bilibili_handle);
// 创建初始变量counter_val记录ESP32重启次数
uint32_t counter_val = 0;
// 创建初始变量counter_val的key,可以将其比喻成文件名
char *counter_key = "counter";
// 查看是否存在counter_val(因为我们的counter_val是uint32_t类型,所以下面我们要用nvs_get_u32())
nvs_get_u32(bilibili_handle, counter_key, &counter_val);
counter_val = counter_val + 1;
// 设置counter_val
nvs_set_u32(bilibili_handle, counter_key, counter_val);
// 提交执行
nvs_commit(bilibili_handle);
// 关闭窗口(句柄)
nvs_close(bilibili_handle);
// 退出“U盘”
nvs_flash_deinit();
}
对于上述代码,我们可以这样形象的理解
当我执行nvs_flash_init()
的时候,相当于插入了“U盘”
当我执行nvs_open(bilibili_name_space , NVS_READWRITE, &bilibili_handle)
时,相当于新建bilibili_name_space文件夹
,并进入其中,其中这个文件夹是NVS_READWRITE
即可读可写的,而bilibili_handle
就相当于这个窗口,我接下来所有的操作都需要通过这个窗口(句柄)进行操作
当我运行nvs_get_u32(bilibili_handle, counter_key, &counter_val)
时,其实就是相当于打开名字为:counter_key
的文件,而文件内的值就是counter_val
nvs_set_u32(bilibili_handle, counter_key, counter_val)
就是设置文件里的内容
nvs_commit(bilibili_handle)
,就是提交执行,nvs_close(bilibili_handle)
就是关闭窗口(句柄),nvs_flash_deinit()
就是退出“U盘”。
优化代码后:
#include
#include "esp_log.h"
#include "nvs_flash.h"
void app_main(void)
{
// 对“U盘”进行初始化
nvs_flash_init();
char *bilibili_name_space = "BiliBili";
nvs_handle_t bilibili_handle;
// 创建一个句柄来打卡它
nvs_open(bilibili_name_space, NVS_READWRITE, &bilibili_handle);
// 创建初始变量counter_val记录ESP32重启次数
uint32_t counter_val = 0;
// 创建初始变量counter_val的key,可以将其比喻成文件名
char *counter_key = "counter";
// 查看是否存在counter_val(因为我们的counter_val是uint32_t类型,所以下面我们要用nvs_get_u32())
nvs_get_u32(bilibili_handle, counter_key, &counter_val);
ESP_LOGI("NVS", "KEY:VALUE %s:%lu", counter_key, counter_val);
// 设置counter_val
nvs_set_u32(bilibili_handle, counter_key, ++counter_val);
// 提交执行
nvs_commit(bilibili_handle);
// 关闭窗口(句柄)
nvs_close(bilibili_handle);
// 退出“U盘”
nvs_flash_deinit();
}
接下来我们来测试一下这段代码:
可以看到,第1次为1,第2次为2,但是按理来说,第一次应该为0,第二次才是1,这是由于ESP-IDF太快了,在打印之前它就重启了一遍,所以才会被记录成1。
这里我们可以通过给几秒的延时来避免这种情况发生,如下:
这里我们重点注意一下这行代码:
nvs_set_u32(bilibili_handle, counter_key, ++counter_val);
在这里,++counter_val
是用于对 counter_val
变量进行自增操作。++
运算符是 C 语言中的自增运算符,用于将变量的值加一,并返回加一后的结果。
在这段代码中,++counter_val
表示先将 counter_val
的值加一,然后将加一后的值作为参数传递给 nvs_set_u32()
函数。这样可以确保在将 counter_val
的值写入 NVS 存储之前,先对其进行自增操作,从而实现每次写入 NVS 存储时计数器的值增加一的效果。
需要注意的是,自增运算符有前缀形式和后缀形式,即 ++counter_val
和 counter_val++
。前缀形式的 ++counter_val
先对变量进行自增操作,然后返回自增后的值;而后缀形式的 counter_val++
先返回变量的值,然后再对变量进行自增操作。在这里使用前缀形式的 ++counter_val
是因为需要将自增后的值传递给 nvs_set_u32()
函数,而不是传递自增前的值。
直接把ESP格式化就好了
![\[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zKZ3JaD7-1681699998245)(https://s3-us-west-2.amazonaws.com/secure.notion-static.com/bb6652b7-0236-42c9-941b-4684efac74b0/Untitled.png)\]](https://img-blog.csdnimg.cn/09ca893cfdc045e789c03a51e555a72a.png)