ArduinoVN
Đăng nhập Tham gia
Thư viện Code /u/linucat /07/05/2026

Thư viện Preferences.h: thay EEPROM trên ESP32

Thảo luận

ESP32 không có EEPROM thực sự — chỉ giả lập trên flash với API giống Arduino. Espressif khuyến nghị không dùng EEPROM.h, mà chuyển sang Preferences.h: API key-value đơn giản, wear-leveling tốt, kiểu dữ liệu rõ ràng. Bài này hướng dẫn đầy đủ.

1. Preferences là gì?

Wrapper xung quanh NVS (Non-Volatile Storage) — phân vùng flash dành riêng. Lưu cặp key-value trong các "namespace":

  • Mỗi namespace như một "thư mục" (≤ 15 ký tự).
  • Mỗi key như tên biến (≤ 15 ký tự).
  • Value: kiểu cụ thể (uint8/16/32/64, string, blob).

Không phải dùng địa chỉ byte như EEPROM — dễ đọc hơn nhiều.

2. Cài đặt

Preferences.h đi kèm Arduino-ESP32 core — KHÔNG cần cài thêm.

#include 
Preferences prefs;

3. Mở namespace

prefs.begin("my-app", false);   // false = read/write
prefs.begin("my-app", true);    // true = read-only

Namespace tự tạo lần đầu. Tối đa ~250 namespace trên partition NVS mặc định.

4. Ghi giá trị

prefs.putUChar("led-mode", 2);
prefs.putUShort("port", 1883);
prefs.putUInt("baud", 115200);
prefs.putULong64("timestamp", 1716000000ULL);
prefs.putFloat("temp-offset", -1.5);
prefs.putDouble("pi", 3.14159265358979);
prefs.putString("ssid", "MyWiFi");
prefs.putString("pass", "secret");
prefs.putBool("enabled", true);
prefs.putBytes("raw", buf, len);

Có overload cho mọi kiểu dữ liệu cơ bản. Mỗi putXxx trả số byte đã ghi.

5. Đọc giá trị (với default fallback)

uint8_t mode  = prefs.getUChar("led-mode", 0);   // default 0 nếu thiếu
uint16_t port = prefs.getUShort("port", 1883);
String ssid   = prefs.getString("ssid", "");
bool en       = prefs.getBool("enabled", false);
float off     = prefs.getFloat("temp-offset", 0.0);
size_t n      = prefs.getBytes("raw", buf, 256);

Luôn có default — tránh giá trị rác khi key chưa tồn tại.

6. Đóng namespace

prefs.end();

Có thể không gọi end() nếu chỉ dùng 1 namespace trong app — tài nguyên tự free khi reboot. Nhưng nên gọi để giải phóng heap.

7. Xoá

prefs.remove("led-mode");      // xoá 1 key
prefs.clear();                  // xoá toàn namespace

8. Kiểm tra tồn tại

if (prefs.isKey("ssid")) {
  // có
}

9. Pattern thực tế — load/save config

struct Config {
  char ssid[33];
  char pass[33];
  uint16_t port;
  bool deepSleep;
};

void loadConfig(Config& c) {
  Preferences p;
  p.begin("cfg", true);
  String s = p.getString("ssid", "");
  strncpy(c.ssid, s.c_str(), sizeof(c.ssid));
  s = p.getString("pass", "");
  strncpy(c.pass, s.c_str(), sizeof(c.pass));
  c.port = p.getUShort("port", 1883);
  c.deepSleep = p.getBool("ds", false);
  p.end();
}

void saveConfig(const Config& c) {
  Preferences p;
  p.begin("cfg", false);
  p.putString("ssid", c.ssid);
  p.putString("pass", c.pass);
  p.putUShort("port", c.port);
  p.putBool("ds", c.deepSleep);
  p.end();
}

10. Lưu mảng / struct dài

uint8_t buf[128];
prefs.putBytes("data", buf, sizeof(buf));

prefs.getBytes("data", buf, sizeof(buf));
size_t actualSize = prefs.getBytesLength("data");

Tốt cho lưu calibration data, lookup table.

11. Wear-leveling và tuổi thọ

NVS tự rotate vị trí ghi để san bằng wear. ESP32 flash chịu ~100.000 chu kỳ ghi mỗi sector. Với NVS, bạn có thể ghi key giá trị mới hàng triệu lần tổng cộng — đủ cho mọi use case thực tế.

Nhưng vẫn nên: chỉ ghi khi giá trị thay đổi, không ghi mỗi loop.

12. Reset NVS — recovery

Khi code crash do data hỏng, có thể wipe NVS từ menu Arduino IDE → Tools → Erase All Flash Before Sketch Upload: Enabled. Hoặc:

nvs_flash_erase();   // xoá toàn NVS
nvs_flash_init();    // init lại

13. So sánh với EEPROM.h

Tính năngEEPROM.h (ESP32)Preferences.h
APIĐịa chỉ byteKey-value
Kiểu dữ liệuByte/struct (put/get)Tất cả kiểu sẵn
Wear-levelingKhông
Phải commitTự lưu sau put
Đa namespaceKhông

Không có lý do gì để dùng EEPROM.h trên ESP32. Preferences thắng về mọi mặt.

14. Lỗi thường gặp

  • begin() returns false: partition NVS không tồn tại → đổi partition scheme.
  • String dài bị truncate: NVS giới hạn ~1984 byte mỗi key. Chia ra nhiều key.
  • Namespace name quá dài: tối đa 15 ký tự. Đặt ngắn.
  • Get sai kiểu: lưu bằng putUInt, đọc bằng getUShort → giá trị sai. Phải khớp kiểu.

Liên quan

So sánh với EEPROM.h: lưu cấu hình vào flash Arduino. Áp dụng để lưu cấu hình WiFi trong dự án ESP32 web server bật/tắt relay.

Thảo luận (0)

Đăng nhập để tham gia thảo luận.
Chưa có bình luận nào. Hãy là người đầu tiên!