该功能类似AVR单片机里面的EEPROM存储区域。
Preferences
中数据以键值对(key - value
)的方式存储。在键值对之上还有一层命名空间(namespace
),不同命名空间中可以有相同的键名存在。在Preferences中命名空间和键名均为字符串,并且长度不大于15个字节。
# ESP-IDF Partition Table
# Name, Type, SubType, Offset, Size, Flags
nvs, data, nvs, 0x9000, 0x4000,
otadata, data, ota, 0xd000, 0x2000,
phy_init, data, phy, 0xf000, 0x1000,
factory, app, factory, 0x10000, 1M,
ota_0, app, ota_0, 0x110000, 1M,
ota_1, app, ota_1, 0x210000, 1M,
那么跟给nvs的容量就是
0x4000
,也就是4KB
/* Code gathered by Marc MERLIN from code found
on gitter (license unknown) and in esp32-arduino's
libraries/FFat/examples/FFat_Test/FFat_Test.ino */
#include
#include "FFat.h"
void partloop(esp_partition_type_t part_type) {
esp_partition_iterator_t iterator = NULL;
const esp_partition_t *next_partition = NULL;
iterator = esp_partition_find(part_type, ESP_PARTITION_SUBTYPE_ANY, NULL);
while (iterator) {
next_partition = esp_partition_get(iterator);
if (next_partition != NULL) {
Serial.printf("partition addr: 0x%06x; size: 0x%06x; label: %s\n", next_partition->address, next_partition->size, next_partition->label);
iterator = esp_partition_next(iterator);
}
}
}
void listDir(fs::FS &fs, const char * dirname, uint8_t levels){
Serial.printf("Listing directory: %s\r\n", dirname);
File root = fs.open(dirname);
if(!root){
Serial.println("- failed to open directory");
return;
}
if(!root.isDirectory()){
Serial.println(" - not a directory");
return;
}
File file = root.openNextFile();
while(file){
if(file.isDirectory()){
Serial.print(" DIR : ");
Serial.println(file.name());
if(levels){
listDir(fs, file.name(), levels -1);
}
} else {
Serial.print(" FILE: ");
Serial.print(file.name());
Serial.print("\tSIZE: ");
Serial.println(file.size());
}
file.close();
file = root.openNextFile();
}
}
void setup(){
Serial.begin(115200);
Serial.setDebugOutput(true);
Serial.println("Partition list:");
partloop(ESP_PARTITION_TYPE_APP);
partloop(ESP_PARTITION_TYPE_DATA);
Serial.println("\n\nTrying to mount ffat partition if present");
// Only allow one file to be open at a time instead of 10, saving 9x4 - 36KB of RAM
if(!FFat.begin( 0, "", 1 )){
Serial.println("FFat Mount Failed");
return;
}
Serial.println("File system mounted");
Serial.printf("Total space: %10lu\n", FFat.totalBytes());
Serial.printf("Free space: %10lu\n\n", FFat.freeBytes());
listDir(FFat, "/", 5);
}
void loop(){}
我们在有效数据读取和存储方面,我们更多的关注是如何去利用它。
Preferences
Preferences.h
头文件涵盖的所支持的数据类型API函数:Char
putChar(const char* key, int8_t value)Unsigned Char
putUChar(const char* key, int8_t value)Short
putShort(const char* key, int16_t value)Unsigned Short
putUShort(const char* key, uint16_t value)Int
putInt(const char* key, int32_t value)Unsigned Int
putUInt(const char* key, uint32_t value)Long
putLong(const char* key, int32_t value)Unsigned Long
putULong(const char* key, uint32_t value)Long64
putLong64(const char* key, int64_t value)Unsigned Long64
putULong64(const char* key, uint64_t value)Float
putFloat(const char* key, const float_t value)Double
putDouble(const char* key, const double_t value)Bool
putBool(const char* key, const bool value)String
putString(const char* key, const String value)Bytes
putBytes(const char* key, const void* value, size_t len)Char
getChar(const char* key, const int8_t defaultValue)Unsigned Char
getUChar(const char* key, const uint8_t defaultValue)Unsigned Short
getUShort(const char* key, const uint16_t defaultValue)Int
getInt(const char* key, const int32_t defaultValue)Unsigned Int
getUInt(const char* key, const uint32_t defaultValue)Long
getLong(const char* key, const int32_t defaultValue)Unsigned Long
getULong(const char* key, const uint32_t defaultValue)Long64
getLong64(const char* key, const int64_t defaultValue)Unsigned Long64
gettULong64(const char* key, const uint64_t defaultValue)Float
getFloat(const char* key, const float_t defaultValue)Double
getDouble(const char* key, const double_t defaultValue)Bool
getBool(const char* key, const bool defaultValue)String
getString(const char* key, const String defaultValue)String
getString(const char* key, char* value, const size_t maxLen)Bytes
getBytes(const char* key, void * buf, size_t maxLen)不管是存储还是读取函数,都至少包含2个参数:键名和键值,我们从上面不难发现,不管是获取键值还是存放键值,它们的第二个参数的返回值和操作的对象都是相同的。
clear()
:清除打开的首选项中的所有键。freeEntries()
:获取剩余可用空间.remove()
:删除单独一个键值对象。与clear()
不同,end()
:关闭命名空间(namespace)bool begin(const char * name, bool readOnly=false, const char* partition_label=NULL);
:第一个参数是必填的,命名空间
,第二个参数是默认初始化是只读模式,第三个参数为空,不填。#include
void setup() {
Serial.begin(115200);
Serial.println();
delay(2000);
Preferences prefs;
prefs.begin("mynamespace");
Serial.println(prefs.freeEntries());//查询剩余空间
prefs.putString("wifiname", "MERCURY_D268G");
Serial.println(prefs.freeEntries());
prefs.putInt("int", 1234567890);
Serial.println(prefs.freeEntries());
prefs.putChar("char", 127);
Serial.println(prefs.freeEntries());
uint8_t buf[5] = {1, 2, 3, 4, 5};
prefs.putBytes("byte", buf, 5);
Serial.println(prefs.freeEntries());
prefs.end();
}
void loop() {}