Thư viện EEPROM.h: lưu cấu hình vào flash Arduino
Arduino có vùng nhớ EEPROM (Electrically Erasable Programmable Read-Only Memory) tích hợp sẵn — giữ dữ liệu kể cả khi tắt nguồn. Đó là nơi lưu cấu hình (SSID WiFi, mật khẩu, ngưỡng cảm biến, lần khởi động) mà không cần thẻ SD. Bài viết tổng hợp thư viện EEPROM.h và cách dùng đúng.
1. Dung lượng EEPROM theo board
| Board | EEPROM |
|---|---|
| Arduino Uno (ATmega328P) | 1024 byte |
| Arduino Nano | 1024 byte |
| Arduino Mega 2560 | 4096 byte |
| ESP8266 / ESP32 | Không có EEPROM thật — giả lập trên flash. ESP32 nên dùng Preferences.h thay thế. |
2. API căn bản
#include
EEPROM.write(addr, value); // ghi 1 byte (0..255)
uint8_t v = EEPROM.read(addr);
EEPROM.update(addr, value); // ghi chỉ khi khác giá trị hiện tại
uint16_t size = EEPROM.length();
Luôn dùng update() thay vì write() — EEPROM chỉ chịu được ~100.000 chu kỳ ghi mỗi ô. update() tránh ghi không cần thiết.
3. Ghi/đọc biến đa byte với put() và get()
Đây là cách bạn sẽ dùng 90% thời gian:
float temp = 25.5;
EEPROM.put(0, temp); // ghi 4 byte ở địa chỉ 0
float val;
EEPROM.get(0, val); // đọc 4 byte vào val
put()/get() tự xác định kích thước biến qua template, hoạt động với mọi kiểu (int, float, double, struct, mảng). Bên trong dùng update() nên an toàn.
4. Lưu struct cấu hình
struct Config {
uint32_t magic; // để detect EEPROM trắng
char ssid[32];
char pass[32];
uint16_t threshold;
};
const uint32_t MAGIC = 0xCAFE1234;
void saveConfig(const Config& c) {
EEPROM.put(0, c);
#if defined(ESP32) || defined(ESP8266)
EEPROM.commit(); // ESP cần commit thủ công
#endif
}
bool loadConfig(Config& c) {
EEPROM.get(0, c);
return c.magic == MAGIC;
}
Trường magic giúp phát hiện EEPROM lần đầu (toàn 0xFF) để đặt giá trị mặc định.
5. ESP32 / ESP8266 — khác biệt quan trọng
ESP không có EEPROM thật. Thư viện EEPROM.h được "giả lập" bằng cách:
- Phải gọi
EEPROM.begin(size)với kích thước RAM buffer trước khi dùng. - Mọi
write()/put()chỉ ghi vào RAM — phảiEEPROM.commit()để flush xuống flash. - Tuổi thọ flash 10k–100k lần ghi — kém EEPROM thật.
EEPROM.begin(512);
EEPROM.put(0, value);
EEPROM.commit();
EEPROM.end();
Khuyến nghị mạnh: ESP32 nên dùng Preferences.h (key-value API) hoặc LittleFS — hiện đại hơn và wear-leveling tốt hơn.
6. Iterate toàn bộ EEPROM
for (uint16_t i = 0; i < EEPROM.length(); i++) {
uint8_t b = EEPROM.read(i);
if (b != 0xFF) {
Serial.print(i); Serial.print("="); Serial.println(b, HEX);
}
}
EEPROM "chưa ghi" có giá trị 0xFF (255).
7. Reset EEPROM
for (uint16_t i = 0; i < EEPROM.length(); i++) {
EEPROM.update(i, 0xFF);
}
Hoặc giữ một nút bấm khi khởi động → nếu nhấn thì clear.
8. Cảnh báo wear-out
100.000 chu kỳ nghe nhiều nhưng nếu bạn ghi trong loop() không debounce, EEPROM chết trong vài giờ. Quy tắc:
- Chỉ ghi khi giá trị thực sự thay đổi (dùng
update()). - Đừng ghi liên tục mỗi loop — gom các thay đổi và ghi 1 lần.
- Cấu hình WiFi, ngưỡng cảnh báo → ghi vài lần/ngày là OK. Đếm số bước motor → ghi mỗi giây sẽ phá EEPROM trong tuần.
9. Bảng tóm tắt
| Hàm | Khi dùng |
|---|---|
read(addr) | Đọc 1 byte |
write(addr, v) | Ghi 1 byte (hạn chế dùng) |
update(addr, v) | Ghi 1 byte chỉ khi khác — DÙNG NÀY |
put(addr, anyType) | Ghi struct/biến nhiều byte |
get(addr, anyType) | Đọc struct/biến nhiều byte |
length() | Dung lượng EEPROM |
begin(size) | Chỉ ESP32/ESP8266 |
commit() | Chỉ ESP32/ESP8266 — flush RAM xuống flash |
Liên quan
Trên ESP32, đọc bài Preferences.h: thay EEPROM trên ESP32. Để lưu dữ liệu lớn hơn, xem SD.h: đọc/ghi file CSV trên Arduino.