Ir al contenido

← Contadores persistentes con NVS Preferences en PLC ESP32

Piso móvil hidráulico (app BLE)ESP32 PLC 38RNVSDatalogging

Contadores persistentes con NVS Preferences en PLC ESP32 — ejemplo completo

Guarda contadores de ciclos, números de serie y totales en la flash NVS del ESP32 para que sobrevivan a reinicios. Ejemplo con Preferences para el PLC 38R.

Programa completo y ejecutable para el ESP32 PLC 38R (nvs-persistent-counters-38r.ino): incluye cabecera de conexionado, requisitos y notas de integración.

Descarga el pack completo del proyecto — gratisEste ejemplo + los relacionados + lista de materiales

Vista de solo lectura.

/*
 * COMPLETE EXAMPLE — Persistent counters in non-volatile memory (Preferences)
 *
 * Hardware:  ESP32 PLC 38R (Industrial Shields)
 * Based on:  hydraulic moving floor project, AppLink.cpp (NVS)
 *
 * Wiring:
 *   I0_0  "Load cycle" push button    (simulates end of load)
 *   I0_1  "Unload cycle" push button  (simulates end of unload)
 *
 * Logic:
 *   - Serial number, load / unload / lifetime counters, oil volume and
 *     activation flag are stored in NVS ("nvdata" partition).
 *   - They survive reboots, power outages and OTA reflashes.
 *   - Writes are deferred (dirty flag + minimum interval) to avoid
 *     wearing out the flash on every pulse.
 *
 * Integration with other catalog modules:
 *   - The counters are reported to the app over BLE as [C1]loads [C2]unloads
 *     (see ejemplos/piso-movil/ble-mobile-app-control-38r.ino).
 *   - The oil volume is computed with the pulse flow meter
 *     (see ejemplos/piso-movil/pulse-flow-meter-38r.ino).
 */

#include 

#define BTN_LOAD    I0_0
#define BTN_UNLOAD  I0_1

// NVS keys (max. 15 characters)
#define KEY_SERIAL    "serial_num"
#define KEY_LOADS     "cnt_load"
#define KEY_UNLOADS   "cnt_unload"
#define KEY_LIFE      "cnt_life"
#define KEY_OIL       "oil_volume"
#define KEY_ACTIVE    "activated"

#define SAVE_INTERVAL_MS 5000   // minimum time between flash writes

Preferences prefs;

String serialNum;
int   counterLoad   = 0;
int   counterUnload = 0;
int   counterLife   = 0;     // total machine cycles
float oilVolume     = 0.0;   // liters of oil moved
bool  activated     = false;

bool     dirty      = false; // there is data pending to be saved
uint32_t lastSaveMs = 0;

void loadNVS() {
  prefs.begin("nvdata", true);                       // read-only
  serialNum     = prefs.getString(KEY_SERIAL, "SN-0000");
  counterLoad   = prefs.getInt(KEY_LOADS, 0);
  counterUnload = prefs.getInt(KEY_UNLOADS, 0);
  counterLife   = prefs.getInt(KEY_LIFE, 0);
  oilVolume     = prefs.getFloat(KEY_OIL, 0.0);
  activated     = prefs.getBool(KEY_ACTIVE, false);
  prefs.end();
}

void saveNVS() {
  prefs.begin("nvdata", false);                      // read/write
  prefs.putInt(KEY_LOADS, counterLoad);
  prefs.putInt(KEY_UNLOADS, counterUnload);
  prefs.putInt(KEY_LIFE, counterLife);
  prefs.putFloat(KEY_OIL, oilVolume);
  prefs.putBool(KEY_ACTIVE, activated);
  prefs.end();
  dirty = false;
  lastSaveMs = millis();
  Serial.println("-> NVS saved");
}

void setup() {
  Serial.begin(115200);
  pinMode(BTN_LOAD, INPUT);
  pinMode(BTN_UNLOAD, INPUT);

  loadNVS();   // the counters come back exactly as they were after every reboot

  Serial.println("=== Persistent counters (NVS) ===");
  Serial.println("Serial:    " + serialNum);
  Serial.println("Loads:     " + String(counterLoad));
  Serial.println("Unloads:   " + String(counterUnload));
  Serial.println("Lifetime:  " + String(counterLife));
  Serial.println("Oil:       " + String(oilVolume, 1) + " L");
  Serial.println("Activated: " + String(activated ? "yes" : "no"));
}

void loop() {
  // Rising edge with simple debounce
  static bool prevLoad = false, prevUnload = false;
  bool load   = digitalRead(BTN_LOAD);
  bool unload = digitalRead(BTN_UNLOAD);

  if (load && !prevLoad) {
    counterLoad++;
    counterLife++;
    oilVolume += 12.5;            // estimated liters per load cycle
    dirty = true;
    Serial.println("Load #" + String(counterLoad));
  }
  if (unload && !prevUnload) {
    counterUnload++;
    counterLife++;
    dirty = true;
    Serial.println("Unload #" + String(counterUnload));
  }
  prevLoad = load;
  prevUnload = unload;

  // Deferred write: protects the flash from a write on every pulse
  if (dirty && millis() - lastSaveMs > SAVE_INTERVAL_MS) {
    saveNVS();
  }

  delay(50);
}
Descarga el pack completo del proyecto — gratisEste ejemplo + los relacionados + lista de materiales