一、簡介
非易失性存儲 (NVS) 庫主要用于在 flash 中存儲鍵值格式的數(shù)據(jù)瑰谜。
NVS適合存儲一些小數(shù)據(jù)锌历,如果對象占用空間比較大,使用負(fù)載均衡的FAT文件系統(tǒng)蹄葱。
如果NVS分區(qū)被截斷氏义,比如更改分區(qū)表布局的時候,應(yīng)該擦除分區(qū)內(nèi)容图云」哂疲可以使用
idf.py erase_flash
命令擦除flash上全部的內(nèi)容。
NVS 的操作對象為鍵值對竣况,其中鍵是 ASCII 字符串克婶,當(dāng)前支持最大鍵長為 15 個字符,值可以為以下幾種類型:
-
整數(shù)型:
uint8_t
丹泉、int8_t
情萤、uint16_t
、int16_t
摹恨、uint32_t
筋岛、int32_t
、uint64_t
和int64_t
晒哄; -
字符型: 以
\0
結(jié)尾的字符串睁宰; - 二進制數(shù)據(jù): 可變長度的二進制數(shù)據(jù) (BLOB)肪获。
二、API說明
以下 NVS 接口位于 nvs_flash/include/nvs_flash.h勋陪。
2.1 nvs_flash_init
2.2 nvs_flash_erase
2.3 nvs_open
2.4 讀取函數(shù)
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 寫入函數(shù)
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);
//用來存儲大二進制數(shù)據(jù)的函數(shù)(比如說結(jié)構(gòu)體)
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. 配置分區(qū)表
配置分區(qū)表: 我們也可以使用默認(rèn)的分區(qū)表。默認(rèn)分區(qū)表中nvs大小是24k(0x6000),可以根據(jù)自己需要對nvs空間進行修改诅愚。
2. 初始化NVS Flash
使用 nvs_flash_init()
寒锚,如果 Flash 滿了或者希望清空原來的數(shù)據(jù),就使用 nvs_flash_erase()
清空违孝。
3. 打開NVS刹前,配置句柄
- 對NVS空間進行操作的時候,是使用句柄實現(xiàn)的雌桑。
- 同時喇喉,為了盡可能減少鍵值對的沖突,NVS引入了命名空間的概念校坑,不同命名空間下的key捕獲產(chǎn)生沖突拣技。
- 同時也要在這里配置對NVS空間進行操作的權(quán)限,分為讀和讀寫兩種耍目。
nvs_handle_t handle;
nvs_open("namespace1", NVS_READWRITE, &handle);
4. 讀寫操作
按照不同的數(shù)據(jù)類型膏斤,對數(shù)據(jù)進行g(shù)et和set操作
調(diào)用中使用nvs_get_*
,nvs_set_*
和nvs_commit()
功能函數(shù)邪驮。
5. 關(guān)閉NVS
nvs_close(handle);
四莫辨、應(yīng)用實例
4.1 單變量讀寫
使用 esp-idf\examples\storage\nvs_rw_value 中的例程
#include <stdio.h>
#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("Done\n");
// 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("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));
}
// 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" : "Done\n");
// 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" : "Done\n");
// 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 字符串及數(shù)組讀寫
初始化后
#include "nvs_flash.h"
void main(void)
{
...
ESP_ERROR_CHECK(nvs_flash_init());
...
}
寫入
void NvsWriteDataToFlash(void)
{
nvs_handle handle;
// 寫入一個整形數(shù)據(jù)毅访,一個字符串沮榜,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:%u\r\n", 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:%u\r\n", str_data, str_length);
printf("[data2]: %d\r\n", value);
printf("[data3]: ssid:%s passwd:%s\r\n", wifi_config_stored.sta.ssid, wifi_config_stored.sta.password);
nvs_close(handle);
}
? 由 Leung 寫于 2021 年 6 月 8 日
? 參考:【ESP32-IDF】04-2 存儲-NVS
ESP32 學(xué)習(xí)日志(5)——NVS
ESP32_學(xué)習(xí)筆記(一)NVS的操作(存儲和讀取大數(shù)組)(為什么存入數(shù)據(jù)成功,讀取卻為零的原因)