EEPROM前言
在EPS32中已经将EEPROM弃用。对于ESP32上的新应用程序,建议使用NVS为首选项。提供EEPROM是为了向后兼容现有的Arduino应用程序。EEPROM是使用NVS中的单个blob实现的,因此它是容器(Flash)中的容器(NVS)(弟中弟)。因此,它不会是一种高性能存储方法。首选项将直接使用nvs,并将每个条目存储为其中的单个对象。所以现在的EEPROM也仅是在函数功能上向后兼容,实际储存方式已经完全变了,这需要我们在实际应用中注意。NVS小知识链接
主要API介绍
bool begin(size_t size); // 开启一块分区访问存储 uint8_t read(int address); // 读取指定地址数据 void write(int address, uint8_t val); // 在指定地址保存数据 uint16_t length(); // 获取申请的分区大小 bool commit(); // 将数据从缓存区存入flash中 void end(); // 结束访问
在实际应用中主要思路是,先申明begin(想要保存的数据大小),再利用write(地址偏移,单个字符数据0-255),当所有数据通过write写完后,一定要记得中commit()提交,使数据从暂存区保存到flash中,实现掉电保护。read的使用直接利用地址偏移可以直接读出数据。
例子1(随机数的保存)
1 #include <Arduino.h> 2 #include "EEPROM.h" 3 4 int addr = 0; 5 #define EEPROM_SIZE 64 6 void setup() 7 { 8 Serial.begin(9600); 9 Serial.println("start..."); 10 if (!EEPROM.begin(EEPROM_SIZE)) // 申请存储空间 11 { 12 Serial.println("failed to initialise EEPROM"); delay(1000000); 13 } 14 Serial.println(" bytes read from Flash . Values are:"); 15 for (int i = 0; i < EEPROM_SIZE; i++) 16 { 17 Serial.print(byte(EEPROM.read(i))); Serial.print(" "); //直接读出数据 18 } 19 Serial.println(); 20 Serial.println("writing random n. in memory"); 21 } 22 23 void loop() 24 { 25 int val = byte(random(10020)); 26 EEPROM.write(addr, val); 27 Serial.print(val); Serial.print(" "); 28 addr = addr + 1; 29 if (addr == EEPROM_SIZE) 30 { 31 Serial.println(); 32 addr = 0; 33 EEPROM.commit(); 34 Serial.print(EEPROM_SIZE); 35 Serial.println(" bytes written on Flash . Values are:"); 36 for (int i = 0; i < EEPROM_SIZE; i++) 37 { 38 Serial.print(byte(EEPROM.read(i))); Serial.print(" "); 39 } 40 Serial.println(); Serial.println("----------------------------------"); 41 } 42 delay(100); 43 }
特殊API直接调用
前面的写入与读取只能是单字符的读取与写入,官方为了方便调用,还提供了对于各数据类型的支持:
uint8_t readByte(int address); int8_t readChar(int address); uint8_t readUChar(int address); int16_t readShort(int address); uint16_t readUShort(int address); int32_t readInt(int address); uint32_t readUInt(int address); int32_t readLong(int address); uint32_t readULong(int address); int64_t readLong64(int address); uint64_t readULong64(int address); float_t readFloat(int address); double_t readDouble(int address); bool readBool(int address); size_t readString(int address, char* value, size_t maxLen); String readString(int address); size_t readBytes(int address, void * value, size_t maxLen); template <class T> T readAll (int address, T &); size_t writeByte(int address, uint8_t value); size_t writeChar(int address, int8_t value); size_t writeUChar(int address, uint8_t value); size_t writeShort(int address, int16_t value); size_t writeUShort(int address, uint16_t value); size_t writeInt(int address, int32_t value); size_t writeUInt(int address, uint32_t value); size_t writeLong(int address, int32_t value); size_t writeULong(int address, uint32_t value); size_t writeLong64(int address, int64_t value); size_t writeULong64(int address, uint64_t value); size_t writeFloat(int address, float_t value); size_t writeDouble(int address, double_t value); size_t writeBool(int address, bool value); size_t writeString(int address, const char* value); size_t writeString(int address, String value); size_t writeBytes(int address, const void* value, size_t len); template <class T> T writeAll (int address, const T &);
例子2(各数据类型):
1 #include <Arduino.h> 2 3 #include "EEPROM.h" 4 5 void setup() { 6 // put your setup code here, to run once: 7 Serial.begin(9600); 8 Serial.println(" Testing EEPROM Library "); 9 if (!EEPROM.begin(1000)) { 10 Serial.println("Failed to initialise EEPROM"); 11 Serial.println("Restarting..."); 12 delay(1000); 13 ESP.restart(); 14 } 15 16 int address = 0; 17 18 EEPROM.writeByte(address, -128); // -2^7 19 address += sizeof(byte); 20 21 EEPROM.writeChar(address, 'A'); // Same as writyByte and readByte 22 address += sizeof(char); 23 24 EEPROM.writeUChar(address, 255); // 2^8 - 1 25 address += sizeof(unsigned char); 26 27 EEPROM.writeShort(address, -32768); // -2^15 28 address += sizeof(short); 29 30 EEPROM.writeUShort(address, 65535); // 2^16 - 1 31 address += sizeof(unsigned short); 32 33 EEPROM.writeInt(address, -2147483648); // -2^31 34 address += sizeof(int); 35 36 EEPROM.writeUInt(address, 4294967295); // 2^32 - 1 37 address += sizeof(unsigned int); 38 39 EEPROM.writeLong(address, -2147483648); // Same as writeInt and readInt 40 address += sizeof(long); 41 42 EEPROM.writeULong(address, 4294967295); // Same as writeUInt and readUInt 43 address += sizeof(unsigned long); 44 45 int64_t value = -1223372036854775808LL; // -2^63 46 EEPROM.writeLong64(address, value); 47 address += sizeof(int64_t); 48 49 uint64_t Value = 18446744073709551615ULL; // 2^64 - 1 50 EEPROM.writeULong64(address, Value); 51 address += sizeof(uint64_t); 52 53 EEPROM.writeFloat(address, 1234.1234); 54 address += sizeof(float); 55 56 EEPROM.writeDouble(address, 123456789.123456789); 57 address += sizeof(double); 58 59 EEPROM.writeBool(address, true); 60 address += sizeof(bool); 61 62 String sentence = "I love ESP32."; 63 EEPROM.writeString(address, sentence); 64 address += sentence.length() + 1; 65 66 char gratitude[21] = "Thank You Espressif!"; 67 EEPROM.writeString(address, gratitude); 68 address += 21; 69 70 // See also the general purpose writeBytes() and readBytes() for BLOB in EEPROM library 71 EEPROM.commit(); 72 address = 0; 73 74 Serial.println(EEPROM.readByte(address)); 75 address += sizeof(byte); 76 77 Serial.println((char)EEPROM.readChar(address)); 78 address += sizeof(char); 79 80 Serial.println(EEPROM.readUChar(address)); 81 address += sizeof(unsigned char); 82 83 Serial.println(EEPROM.readShort(address)); 84 address += sizeof(short); 85 86 Serial.println(EEPROM.readUShort(address)); 87 address += sizeof(unsigned short); 88 89 Serial.println(EEPROM.readInt(address)); 90 address += sizeof(int); 91 92 Serial.println(EEPROM.readUInt(address)); 93 address += sizeof(unsigned int); 94 95 Serial.println(EEPROM.readLong(address)); 96 address += sizeof(long); 97 98 Serial.println(EEPROM.readULong(address)); 99 address += sizeof(unsigned long); 100 101 value = 0; 102 value = EEPROM.readLong64(value); 103 Serial.printf("0x%08X", (uint32_t)(value >> 32)); // Print High 4 bytes in HEX 104 Serial.printf("%08X ", (uint32_t)value); // Print Low 4 bytes in HEX 105 address += sizeof(int64_t); 106 107 Value = 0; // Clear Value 108 Value = EEPROM.readULong64(Value); 109 Serial.printf("0x%08X", (uint32_t)(Value >> 32)); // Print High 4 bytes in HEX 110 Serial.printf("%08X ", (uint32_t)Value); // Print Low 4 bytes in HEX 111 address += sizeof(uint64_t); 112 113 Serial.println(EEPROM.readFloat(address), 4); 114 address += sizeof(float); 115 116 Serial.println(EEPROM.readDouble(address), 8); 117 address += sizeof(double); 118 119 Serial.println(EEPROM.readBool(address)); 120 address += sizeof(bool); 121 122 Serial.println(EEPROM.readString(address)); 123 address += sentence.length() + 1; 124 125 Serial.println(EEPROM.readString(address)); 126 address += 21; 127 } 128 129 void loop() { 130 // put your main code here, to run repeatedly: 131 132 }
初步展现底层:
前面提到过,在目前的ESP32中并没有EEPROM,而是利用NVS模拟出来的,仅是了程序的向后兼容性,而前面的程序中的EEPROM储存空间也仅仅是NVS的单个blob实现的,也就是说我们可以创造多个EEPROM来存储数据。
在EEPROMClass类中,有三个:
EEPROMClass(uint32_t sector);
EEPROMClass(const char* name, uint32_t user_defined_size);
EEPROMClass(void);
程序在默认状态下使用的是最后一个:extern EEPROMClass EEPROM;而从定义中,我们可知这个类是可以指定名称与大小的。
且提供了函数get与put用于保存数据与读取:
template<typename T> T &get(int address, T &t) { if (address < 0 || address + sizeof(T) > _size) return t; memcpy((uint8_t*) &t, _data + address, sizeof(T)); return t; } template<typename T> const T &put(int address, const T &t) { if (address < 0 || address + sizeof(T) > _size) return t; memcpy(_data + address, (const uint8_t*) &t, sizeof(T)); _dirty = true; return t; }
例子(对EEPROMClass的调用):
#include <Arduino.h> #include "EEPROM.h" // Instantiate eeprom objects with parameter/argument names and sizes EEPROMClass NAMES("eeprom0", 0x500); EEPROMClass HEIGHT("eeprom1", 0x200); EEPROMClass AGE("eeprom2", 0x100); void setup() { Serial.begin(9600); Serial.println("Testing EEPROMClass "); if (!NAMES.begin(NAMES.length())) { Serial.println("Failed to initialise NAMES"); Serial.println("Restarting..."); delay(1000); ESP.restart(); } if (!HEIGHT.begin(HEIGHT.length())) { Serial.println("Failed to initialise HEIGHT"); Serial.println("Restarting..."); delay(1000); ESP.restart(); } if (!AGE.begin(AGE.length())) { Serial.println("Failed to initialise AGE"); Serial.println("Restarting..."); delay(1000); ESP.restart(); } const char* name = "Teo Swee Ann"; char rname[32]; double height = 5.8; uint32_t age = 47; // Write: Variables ---> EEPROM stores NAMES.put(0, name); HEIGHT.put(0, height); AGE.put(0, age); Serial.print("name: "); Serial.println(name); Serial.print("height: "); Serial.println(height); Serial.print("age: "); Serial.println(age); Serial.println("------------------------------------ "); // Clear variables name = '