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("\nTesting EEPROM Library\n"); 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\n", (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\n", (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\n"); 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("------------------------------------\n"); // Clear variables name = '\0'; height = 0; age = 0; Serial.print("name: "); Serial.println(name); Serial.print("height: "); Serial.println(height); Serial.print("age: "); Serial.println(age); Serial.println("------------------------------------\n"); // Read: Variables <--- EEPROM stores NAMES.get(0, rname); HEIGHT.get(0, height); AGE.get(0, age); Serial.print("name: "); Serial.println(rname); Serial.print("height: "); Serial.println(height); Serial.print("age: "); Serial.println(age); Serial.println("Done!"); } void loop() { delay(0xFFFFFFFF); }