文章目录

  • nvs_flash(非易失性存储库)
  • 简介
  • 数据类型:
  • 常用函数
  • 应用实例
  • 参考文档


nvs_flash(非易失性存储库)


简介

非易失性存储 (NVS) 库主要用于在 flash 中存储键值对格式的数据。NVS 库通过调用esp_partitionAPI使用主 flash 的部分空间。nvs_flash库的封装,使用户操作更加便捷。

数据类型:
  1. 整数型:uint8_tint8_tuint16_tint16_tuint32_tint32_tuint64_tint64_t
  2. 以 0 结尾的字符串;
  3. 可变长度的二进制数据 (BLOB)

注:

  1. NVS 最适合存储一些较小的数据,而非字符串或二进制大对象 (BLOB) 等较大的数据。如需存储较大的 BLOB 或者字符串,请考虑使用基于磨损均衡库的 FAT 文件系统。
  2. 如果 NVS 分区被截断(例如,更改分区表布局时),则应擦除分区内容。可以使用 ESP-IDF 构建系统中的 idf.py erase-flash 命令擦除 flash 上的所有内容。
  3. 键必须唯一。为现有的键写入新值时,会将旧的值及数据类型更新为写入操作指定的值和数据类型。读取值时会执行数据类型检查。如果读取操作预期的数据类型与对应键的数据类型不匹配,则返回错误。
  4. 命名空间最多可占 15 个字符。单个 NVS 分区最多只能容纳 254 个不同的命名空间。不同命名空间可以有相同的键值。不同分区中也可以有相同的命名空间。一个句柄关联一个命名空间。

常用函数

/**
简介:初始化默认 NVS 分区。此 API 初始化默认 NVS 分区。默认的 NVS 分区是在分区表中标	 记为“nvs”的分区。
返回值: ESP_OK存储是否已成功初始化。
	   ESP_ERR_NVS_NO_FREE_PAGES 如果 NVS 存储不包含空页(如果 NVS 分区被截断,则可能会发生这种情况)
	   ESP_ERR_NOT_FOUND如果在分区表中找不到带有标签“nvs”的分区
	   ESP_ERR_NO_MEM,以防无法为内部结构分配内存
**/
esp_err_t nvs_flash_init(void);
/**
简介:初始化指定分区的NVS闪存。
参数:const char *partition_label:初始化分区的名字.nvs_flash_init()函数的名字默	   认为 "nvs"
返回值:上同
**/
esp_err_t nvs_flash_init_partition(const char *partition_label);
/**
简介:擦除默认的 NVS 分区。
**/
esp_err_t nvs_flash_erase(void);
esp_err_t nvs_flash_erase_partition(const char *part_name);
/**
简介:从默认 NVS 分区使用给定命名空间打开非易失性存储。
参数:namespace_name: 命名空间名称。最大长度为 (NVS_KEY_NAME_MAX_SIZE-	  			 			1)(15)个字符。不应为空。
	 open_mode:NVS_READWRITE 或 NVS_READONLY。如果NVS_READONLY,将打				        开一个仅供读取的句柄。此句柄的所有写入请求都将被拒绝。
	 out_handle: 如果成功(返回代码为零),则在此参数中将返回句柄。
返回值: ESP_OK存储句柄是否已成功打开
	   ESP_FAIL是否存在内部错误;最有可能是由于 NVS 分区损坏(仅当禁用 NVS 断言检查时)
	   ESP_ERR_NVS_NOT_INITIALIZED如果存储驱动程序未初始化
	   如果找不到带有标签“nvs”的分区,则ESP_ERR_NVS_PART_NOT_FOUND
	   ESP_ERR_NVS_NOT_FOUND id 命名空间尚不存在,并且模式已NVS_READONLY
	   如果命名空间名称不满足约束,则ESP_ERR_NVS_INVALID_NAME
	   ESP_ERR_NO_MEM,以防无法为内部结构分配内存
	   ESP_ERR_NVS_NOT_ENOUGH_SPACE 如果没有新条目的空间或有太多不同的命名空间(允许的最大不同命名空间:254)
	   如果 NVS 分区是只读的,并且模式是NVS_READWRITE,则ESP_ERR_NOT_ALLOWED
	   ESP_ERR_INVALID_ARG 如果 out_handle 等于 NULL
**/
esp_err_t nvs_open(const char *namespace_name, nvs_open_mode_t open_mode, nvs_handle_t *out_handle);
/**
简介:为给定键设置int16_t值
参数:nvs_handle_t handle:nvs_open()赋值的句柄,应先调用nvs_open()。
	 const char *key:键值 最大长度为 (NVS_KEY_NAME_MAX_SIZE-1) 个字符。不应为空。
	 int16_t value:要设置的值
返回值:ESP_OK值是否设置成功
	  ESP_FAIL是否存在内部错误;最有可能是由于 NVS 分区损坏(仅当禁用 NVS 断言检查时)
	  ESP_ERR_NVS_INVALID_HANDLE句柄是否已关闭或为 NULL
	  ESP_ERR_NVS_READ_ONLY存储句柄是否以只读方式打开
	  ESP_ERR_NVS_INVALID_NAME键名称不满足约束
	  如果底层存储中没有足够的空间来保存值,则ESP_ERR_NVS_NOT_ENOUGH_SPACE
	  ESP_ERR_NVS_REMOVE_FAILED如果由于闪存写入操作失败而未更新该值。但是,该值已写	   入,并且更新将在重新初始化 nvs 后完成,前提是闪存操作不会再次失败。
**/
esp_err_t nvs_set_i16(nvs_handle_t handle, const char *key, int16_t value);
/**
简介:给指定键设置字符串值。
参数:上同
返回值:上同
**/
esp_err_t nvs_set_str(nvs_handle_t handle, const char *key, const char *value);
/**
简介:给指定键设置二进制值。
参数: 上同
	  size_t length:要设置的二进制值的长度(单位:字节)
返回值:上同
**/
esp_err_t nvs_set_blob(nvs_handle_t handle, const char *key, const void *value, size_t length);
/**
简介:将任何挂起的更改写入非易失性存储。
参数:nvs_handle_t handle:句柄
返回值:ESP_OK更改是否已成功写入
      ESP_ERR_NVS_INVALID_HANDLE句柄是否已关闭或为 NULL
**/
esp_err_t nvs_commit(nvs_handle_t handle);
/**
简介:获取给定键的int16_t值
参数:nvs_handle_t handle:句柄
	 const char *key:键值
	 int16_t *out_value: 指向输出值的指针
返回值:ESP_OK是否成功检索了该值
	  ESP_FAIL是否存在内部错误;最有可能是由于 NVS 分区损坏(仅当禁用 NVS 断言检查时)
	  ESP_ERR_NVS_NOT_FOUND请求的密钥是否不存在
	  ESP_ERR_NVS_INVALID_HANDLE句柄是否已关闭或为 NULL
	  ESP_ERR_NVS_INVALID_NAME键名称不满足约束
	  如果长度不足以存储数据,则ESP_ERR_NVS_INVALID_LENGTH
**/
esp_err_t nvs_get_i16(nvs_handle_t handle, const char *key, int16_t *out_value);
/**
简介:获取给定键的字符串值
参数:上同
  	  char *out_value:指向输出值的指针
  	  size_t *length:指向长度为 out_value 的变量的非零指针。如果out_value零,则将设置为保存值所需的长度。如果 out_value 不为零,则设置为写入值的实际长度。对于nvs_get_str这包括零终结符。
返回值:上同
**/
esp_err_t nvs_get_str(nvs_handle_t handle, const char *key, char *out_value, size_t *length);
/**
简介:初始化指定分区的NVS闪存。
参数:上同
返回值:上同
**/
esp_err_t nvs_set_blob(nvs_handle_t handle, const char *key, const void *value, size_t length);
/**
简介:关闭存储句柄并释放所有已分配的资源。

**/
void nvs_close(nvs_handle_t handle);

应用实例

#include <stdio.h>
#include <inttypes.h>
#include "sdkconfig.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_chip_info.h"
#include "esp_flash.h"
#include "nvs_flash.h"
#include "esp_log.h"

const char* TAG="NVSFLASH";
const char* NAMESPACE="nvsflash";

void app_main(void)
{
    esp_err_t err=ESP_OK;

    err=nvs_flash_init();
    if(err==ESP_ERR_NVS_NO_FREE_PAGES){
        
        ESP_ERROR_CHECK(nvs_flash_erase());
        err=nvs_flash_init();
        if(err==ESP_ERR_NVS_NO_FREE_PAGES){
            ESP_LOGE(TAG, "nvs_flash_init error: %d\n", err);
            return;
        }
        
    }
    printf("Opening Non-Volatile Storage (NVS) handle... ");

    nvs_handle_t nvs_handle;
    /*
    最大长度为(NVS_KEY_NAME_MAX_SIZE-1)默认为15个 字符。
    */
    err=nvs_open(NAMESPACE,NVS_READWRITE,&nvs_handle);
    if(err!=ESP_OK){
        ESP_LOGE(TAG, "nvs_open error: %d\n", err);
        return;
    }
    int16_t i=0;
    size_t len=15;
    char str[15];
    uint8_t binary[4]={0x01,0x02,0x03,0x04};
    uint8_t get_binary[4];
    size_t  get_binary_len=4;

    nvs_set_i16(nvs_handle,"demo1",12);
    nvs_set_str(nvs_handle,"demo2","HelloWorld");
    nvs_set_blob(nvs_handle,"demo3",binary,sizeof(binary)/sizeof(uint8_t));
    nvs_commit(nvs_handle);


    nvs_get_i16(nvs_handle,"demo1",&i);
    //长度必须非零并且必须指向out_value 中可用的长度。len=sizeof(str)/sizeof(char); 包括零终止符
    nvs_get_str(nvs_handle,"demo2",str,&len);
    nvs_get_blob(nvs_handle,"demo3",get_binary,&get_binary_len);

    printf("demo1: %d\n",i);
    printf("demo2: %s\n",str);
    printf("demo3: %x,%x,%x,%x\n",get_binary[0],get_binary[1],get_binary[2],get_binary[3]);
    nvs_close(nvs_handle);

    /**
    输出结果:
        demo1: 12
        demo2: HelloWorld
        demo3: 1,2,3,4
    */

参考文档

  1. https://docs.espressif.com/projects/esp-idf/zh_CN/latest/esp32/api-reference/storage/nvs_flash.html