ESP32学习笔记(23)——NVS(非易失性存储)接口使用

发布者:WanderlustGlow最新更新时间:2025-02-28 来源: cnblogs关键字:ESP32  NVS  非易失性存储 手机看文章 扫描二维码
随时随地手机看文章

一、简介

非易失性存储 (NVS) 库主要用于在 flash 中存储键值格式的数据。

NVS适合存储一些小数据,如果对象占用空间比较大,使用负载均衡的FAT文件系统。

如果NVS分区被截断,比如更改分区表布局的时候,应该擦除分区内容。可以使用 idf.py erase_flash 命令擦除flash上全部的内容。

NVS 的操作对象为键值对,其中键是 ASCII 字符串,当前支持最大键长为 15 个字符,值可以为以下几种类型:

  • 整数型: uint8_t、int8_t、uint16_t、int16_t、uint32_t、int32_t、uint64_t 和 int64_t;

  • 字符型: 以 结尾的字符串;

  • 二进制数据: 可变长度的二进制数据 (BLOB)。

ESP-IDF 编程指南——非易失性存储库

二、API说明

以下 NVS 接口位于 nvs_flash/include/nvs_flash.h。

2.1 nvs_flash_init

2.2 nvs_flash_erase

2.3 nvs_open

2.4 读取函数

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.5 写入函数

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);

//用来存储大二进制数据的函数(比如说结构体)

esp_err_t nvs_set_blob(nvs_handle_t handle, const char* key, const void* value, size_t length);

2.6 nvs_commit

2.7 nvs_close

三、编程流程

1. 配置分区表

配置分区表: 我们也可以使用默认的分区表。默认分区表中nvs大小是24k(0x6000),可以根据自己需要对nvs空间进行修改。

2. 初始化NVS Flash

使用 nvs_flash_init(),如果 Flash 满了或者希望清空原来的数据,就使用 nvs_flash_erase() 清空。

3. 打开NVS,配置句柄


对NVS空间进行操作的时候,是使用句柄实现的。


同时,为了尽可能减少键值对的冲突,NVS引入了命名空间的概念,不同命名空间下的key捕获产生冲突。


同时也要在这里配置对NVS空间进行操作的权限,分为读和读写两种。


nvs_handle_t handle;nvs_open('namespace1', NVS_READWRITE, &handle);

4. 读写操作

按照不同的数据类型,对数据进行get和set操作

调用中使用nvs_get_*,nvs_set_*和nvs_commit()功能函数。

5. 关闭NVS


nvs_close(handle);

四、应用实例

4.1 单变量读写

使用 esp-idfexamplesstoragenvs_rw_value 中的例程


#include #include 'freertos/FreeRTOS.h'#include 'freertos/task.h'#include 'esp_system.h'#include 'nvs_flash.h'#include 'nvs.h'void app_main(void){

    // Initialize NVS

    esp_err_t err = nvs_flash_init();

    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 );


    // Open

    printf('n');

    printf('Opening Non-Volatile Storage (NVS) handle... ');

    nvs_handle_t 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('Donen');


        // Read

        printf('Reading restart counter from NVS ... ');

        int32_t restart_counter = 0; // value will default to 0, if not set yet in NVS

        err = nvs_get_i32(my_handle, 'restart_counter', &restart_counter);

        switch (err) {

            case ESP_OK:

                printf('Donen');

                printf('Restart counter = %dn', 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));

        }


        // Write

        printf('Updating restart counter in NVS ... ');

        restart_counter++;

        err = nvs_set_i32(my_handle, 'restart_counter', restart_counter);

        printf((err != ESP_OK) ? 'Failed!n' : 'Donen');


        // Commit written value.

        // After setting any values, nvs_commit() must be called to ensure changes are written

        // to flash storage. Implementations may write to storage at other times,

        // but this is not guaranteed.

        printf('Committing updates in NVS ... ');

        err = nvs_commit(my_handle);

        printf((err != ESP_OK) ? 'Failed!n' : 'Donen');


        // Close

        nvs_close(my_handle);

    }


    printf('n');


    // Restart module

    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();}

查看打印:




4.2 字符串及数组读写

初始化后


#include 'nvs_flash.h'void main(void){

    ...

    ESP_ERROR_CHECK(nvs_flash_init());

    ...}

写入


void NvsWriteDataToFlash(void){

    nvs_handle handle;

    // 写入一个整形数据,一个字符串,WIFI信息以及版本信息

    static const char *NVS_CUSTOMER = 'customer data';

    static const char *DATA2 = 'String';

    static const char *DATA3 = 'blob_wifi';

    static const char *DATA4 = 'blob_version';


    // 要写入的字符串

    char str_for_store[32] = 'i am a string.';

    // 要写入的WIFI信息

     wifi_config_t wifi_config_to_store = {

        .sta = {

            .ssid = 'store_ssid:hello_kitty',

            .password = 'store_password:1234567890',

        },

    };

    // 要写入的版本号

    uint8_t version_for_store[4] = {0x01, 0x01, 0x01, 0x00};

    

    printf('set size:%urn', sizeof(wifi_config_to_store));

    ESP_ERROR_CHECK( nvs_open( NVS_CUSTOMER, NVS_READWRITE, &handle) );

    ESP_ERROR_CHECK( nvs_set_str( handle, DATA2, str_for_store) );

    ESP_ERROR_CHECK( nvs_set_blob( handle, DATA3, &wifi_config_to_store, sizeof(wifi_config_to_store)) );

    ESP_ERROR_CHECK( nvs_set_blob( handle, DATA4, version_for_store, 4) );


    ESP_ERROR_CHECK( nvs_commit(handle) );

    nvs_close(handle);}

读出


void NvsReadDataFromFlash(void){

    esp_err_t err;


    nvs_handle handle;

    static const char *NVS_CUSTOMER = 'customer data';

    static const char *DATA2 = 'String';

    static const char *DATA3 = 'blob_wifi';

    static const char *DATA4 = 'blob_version';


    uint32_t str_length = 32;

    char str_data[32] = {0};

    wifi_config_t wifi_config_stored;

    uint8_t version[4] = {0};

    uint32_t version_len = 4;

    

    memset(&wifi_config_stored, 0x0, sizeof(wifi_config_stored));

    uint32_t wifi_len = sizeof(wifi_config_stored);


    ESP_ERROR_CHECK( nvs_open(NVS_CUSTOMER, NVS_READWRITE, &handle) );


    ESP_ERROR_CHECK ( nvs_get_str(handle, DATA2, str_data, &str_length) );

    ESP_ERROR_CHECK ( nvs_get_blob(handle, DATA3, &wifi_config_stored, &wifi_len) );

    ESP_ERROR_CHECK ( nvs_get_blob(handle, DATA4, version, &version_len) );


    printf('[data1]: %s len:%urn', str_data, str_length);

    printf('[data2]: %drn', value);

    printf('[data3]: ssid:%s passwd:%srn', wifi_config_stored.sta.ssid, wifi_config_stored.sta.password);


    nvs_close(handle);}


关键字:ESP32  NVS  非易失性存储 引用地址:ESP32学习笔记(23)——NVS(非易失性存储)接口使用

上一篇:ESP32学习笔记(24)——OTA(空中升级)接口使用(原生API)
下一篇:ESP32学习笔记(22)——ADC接口使用

推荐阅读最新更新时间:2026-03-19 23:44

Deca与冠捷半导体(SST)达成战略合作 共同推进存储(NVM)芯粒解决方案
Deca与冠捷半导体(SST)达成战略合作 共同推进非易失性存储(NVM)芯粒解决方案 双方携手为客户打造以存储为核心的模块化基础架构,支持先进的多裸片架构设计 随着传统单片芯片设计的复杂度和成本不断攀升,小芯片技术在半导体行业的关注度和应用率也持续上升。Deca Technologies与Microchip Technology Inc.(微芯科技公司)旗下子公司冠捷半导体(SST ® )宣布达成战略合作,双方将共同打造一款完整的非易失性存储(NVM)芯粒化封装解决方案,助力客户加速采用模块化、多芯片系统。 此次合作将Deca的M-Series™(M系列)扇出封装技术与Adaptive Patterning ® (自
[嵌入式]
Deca与冠捷半导体(SST)达成战略合作   共同推进<font color='red'>非</font><font color='red'>易</font><font color='red'>失</font><font color='red'>性</font><font color='red'>存储</font>(NVM)芯粒解决方案
ESP32/8266固件备份方法
Esptool是一个开源且官方的命令行工具,主要用于对乐鑫(Espressif)的ESP系列芯片进行固件读写和调试。它通过串口(UART)与ESP设备的Bootloader(引导加载程序)通信,按照特定协议发送指令和数据,以执行各种底层操作。由于esptool是一个Python脚本,因此需要先安装Python环境。安装完成后,用户即可在命令行中使用esptool.py命令。 与其他工具的关系: IDE:当您在 Arduino IDE 中点击“上传”按钮时,IDE 实际上是在后台调用了 esptool(或其变种 arduino-esp32 中的工具)来完成固件烧录。您无需手动操作。 PlatformIO:PlatformIO 同样
[嵌入式]
<font color='red'>ESP32</font>/8266固件备份方法
串口、并口、USB、UART及RS232/RS485接口与ESP32、STM32的应用解析
在嵌入式系统和电子设备开发中,理解各种通信接口和主流微控制器的区别至关重要。本文将清晰梳理几组关键概念的区别,助您在项目选型时做出明智决策。 一、 串行接口 vs. 并行接口 核心区别:数据传输方式 串行接口: 数据位在一根(单工)或一对(双工) 信号线上依次、一位接一位地传输。例如:UART、I2C、SPI、USB、RS232、RS485、以太网等。 优点: 线路简单、成本低、抗干扰能力强(尤其远距离)、连接器引脚少、布线方便。 缺点: 相对并行接口,速度较慢(同一时钟周期只传1位)。 典型应用: 远距离通信、设备间点对点或总线通信、对速度要求不极端高的场景。 并行接口: 数据位通过多根(通常8位、16位、32位等)
[单片机]
串口、并口、USB、UART及RS232/RS485接口与<font color='red'>ESP32</font>、STM32的应用解析
ESP32引脚参考
ESP32芯片配有48个具有多种功能的引脚。并非所有的引脚都暴露在所有的ESP32开发板中,有些引脚不能使用。 关于如何使用ESP32 GPIO有很多问题。你应该用什么pin?在项目中应该避免使用哪些pin?本文旨在成为一个为ESP32的GPIO提供一个简单易懂的参考指南。 下图显示了ESP-WROOM-32引脚。如果使用ESP32裸芯片构建自定义板,可以将其用作参考: 注意:并非所有的GPIO都可以在所有的开发板中访问,但是每个特定的GPIO都以相同的方式工作,而不管您使用的是什么开发板。 ESP32外围设备 ESP32外围设备包括: 18个模数转换器(ADC)通道 3个SPI接口 3个UART接口 2个I2C接口
[单片机]
<font color='red'>ESP32</font>引脚参考
按键控制LED灯-ESP32中断处理
#include driver/gpio.h #include esp_task_wdt.h #include freertos/FreeRTOS.h #include freertos/queue.h #include freertos/semphr.h #include freertos/task.h #include math.h #include sdkconfig.h #define MIN_DELAY 500 #define BUTTON_GPIO GPIO_NUM_14 #define BLINK_GPIO GPIO_NUM_13 static char *TAG = SMART-WATER ;
[单片机]
ESP32存储blog笔记
基于ESP-IDF4.1 1 #include stdio.h 2 #include freertos/FreeRTOS.h 3 #include freertos/task.h 4 #include esp_system.h 5 #include nvs_flash.h 6 #include nvs.h 7 #include driver/gpio.h 8 9 #define STORAGE_NAMESPACE storage 10 11 12 //保存设备重启数 13 esp_err_t save_restart_counter(void) 14 { 15 nvs_hand
[单片机]
ESP32的Flash加密知识
一、Flash 加密功能用于加密与 ESP32-S2 搭载使用的 SPI Flash 中的内容。启用 Flash 加密功能后,物理读取 SPI Flash 便无法恢复大部分 Flash 内容。通过明文数据烧录 ESP32-S2 可应用加密功能,(若已启用加密功能)引导加载程序会在首次启动时对数据进行加密。 启用 Flash 加密后,系统将默认加密下列类型的 Flash 数据: 引导加载程序 分区表 所有 “app” 类型的分区 其他类型的 Flash 数据将视情况进行加密: 安全启动引导加载程序摘要(如果已启用安全启动) 分区表中标有“加密”标记的分区 二、开发模式:可使用 ESP32-S2 内部生成的密钥或外部主
[单片机]
使用树莓派进行 ESP32 Jtag 调试
本来购买 ESP-Prog 调试 ESP32,发现无论如何 Ubuntu 22.04 都无法发现该设备(不知道是硬件问题还是驱动问题)(2024-02-13更新,是micro usb线的问题。有些micro usb线其实只有电源线,数据线不生效)。在网上看到一篇文章,可以利用树莓派进行 Jtag 调试。链接如下:ESP32 JTAG Debugging using Raspberry Pi。 这里需要说明下,随着openocd-esp32 项目的更新,这篇文章有些过期了,具体可见下面的文件: openocd-esp32/tcl/interface/raspberrypi-gpio-connector.cfg # GPIO 25
[单片机]
小广播
最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

厂商技术中心

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

 
机器人开发圈

电子工程世界版权所有 京ICP证060456号 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2026 EEWORLD.com.cn, Inc. All rights reserved