Ir al contenido

← Electroválvulas con máquina de estados en un PLC ESP32

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

Electroválvulas con máquina de estados en un PLC ESP32 — ejemplo completo

Controla electroválvulas hidráulicas con seguridad desde un ESP32 PLC 38R usando una máquina de estados con timeouts. Ejemplo Arduino con salidas de relé.

Programa completo y ejecutable para el ESP32 PLC 38R (load-unload-solenoid-valves-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 — Load/unload solenoid valve control
 *
 * Hardware:  ESP32 PLC 38R (Industrial Shields)
 * Based on:  hydraulic moving floor project, main.cpp (state machine)
 *
 * Wiring:
 *   I0_0  Physical LOAD push button
 *   I0_1  Physical UNLOAD push button
 *   I0_2  Physical STOP push button
 *   R0_1  Main solenoid valve    (EVG)
 *   R0_2  Unload solenoid valve  (EVD)
 *   R0_3  Load solenoid valve    (EVC)
 *   R0_4  Load indicator LED
 *   R0_5  Unload indicator LED
 *
 * Logic:
 *   - Three states: MOTION_LOAD / MOTION_UNLOAD / MOTION_NONE (idle).
 *   - Each state sets the combination of the 3 solenoid valves and the LEDs
 *     at a single point in the code (atomic transition, no mixed states).
 *   - Driven by physical push buttons; in the real project also over
 *     BLE with [M]1* / [M]2* / [M]0* frames from the mobile app.
 *   - Safety timeout: a motion never lasts longer than MAX_MOTION_MS.
 *
 * Integration with other catalog modules:
 *   - Remote control over BLE: ejemplos/piso-movil/ble-mobile-app-control-38r.ino
 *   - Overpressure stop with 4-20 mA sensors:
 *     ejemplos/piso-movil/pressure-temperature-4-20ma-sensors-38r.ino
 */

#define BTN_LOAD    I0_0
#define BTN_UNLOAD  I0_1
#define BTN_STOP    I0_2

#define OUTPUT_EVG    R0_1   // main solenoid valve
#define OUTPUT_EVD    R0_2   // unload solenoid valve
#define OUTPUT_EVC    R0_3   // load solenoid valve
#define LED_LOAD      R0_4
#define LED_UNLOAD    R0_5

#define MAX_MOTION_MS 30000  // a motion never lasts longer than 30 s

enum Motion { MOTION_NONE, MOTION_LOAD, MOTION_UNLOAD };

Motion   motion        = MOTION_NONE;
uint32_t motionStartMs = 0;

// The only point in the code that touches the solenoid valves:
// impossible to end up in a mixed load+unload state.
void setMotion(Motion m) {
  motion = m;
  motionStartMs = millis();

  switch (m) {
    case MOTION_LOAD:                       // load: EVC + EVG open
      digitalWrite(OUTPUT_EVC, HIGH);
      digitalWrite(OUTPUT_EVD, LOW);
      digitalWrite(OUTPUT_EVG, HIGH);
      digitalWrite(LED_LOAD, HIGH);
      digitalWrite(LED_UNLOAD, LOW);
      Serial.println("State: LOAD");
      break;

    case MOTION_UNLOAD:                     // unload: EVD + EVG open
      digitalWrite(OUTPUT_EVC, LOW);
      digitalWrite(OUTPUT_EVD, HIGH);
      digitalWrite(OUTPUT_EVG, HIGH);
      digitalWrite(LED_LOAD, LOW);
      digitalWrite(LED_UNLOAD, HIGH);
      Serial.println("State: UNLOAD");
      break;

    default:                                // idle: everything closed
      digitalWrite(OUTPUT_EVC, LOW);
      digitalWrite(OUTPUT_EVD, LOW);
      digitalWrite(OUTPUT_EVG, LOW);
      digitalWrite(LED_LOAD, LOW);
      digitalWrite(LED_UNLOAD, LOW);
      Serial.println("State: IDLE");
  }
}

void setup() {
  Serial.begin(115200);

  pinMode(BTN_LOAD, INPUT);
  pinMode(BTN_UNLOAD, INPUT);
  pinMode(BTN_STOP, INPUT);
  pinMode(OUTPUT_EVG, OUTPUT);
  pinMode(OUTPUT_EVD, OUTPUT);
  pinMode(OUTPUT_EVC, OUTPUT);
  pinMode(LED_LOAD, OUTPUT);
  pinMode(LED_UNLOAD, OUTPUT);

  setMotion(MOTION_NONE);   // always start in safe idle
  Serial.println("Solenoid valve control ready (ESP32 PLC 38R)");
}

void loop() {
  // Physical push buttons with edge detection
  static bool prevLoad = false, prevUnload = false, prevStop = false;
  bool load   = digitalRead(BTN_LOAD);
  bool unload = digitalRead(BTN_UNLOAD);
  bool stop   = digitalRead(BTN_STOP);

  if (stop && !prevStop)                         setMotion(MOTION_NONE);
  else if (load && !prevLoad && motion == MOTION_NONE)
    setMotion(MOTION_LOAD);
  else if (unload && !prevUnload && motion == MOTION_NONE)
    setMotion(MOTION_UNLOAD);

  prevLoad = load; prevUnload = unload; prevStop = stop;

  // Safety: no motion can stay active indefinitely
  if (motion != MOTION_NONE && millis() - motionStartMs > MAX_MOTION_MS) {
    Serial.println("Motion TIMEOUT -> automatic stop");
    setMotion(MOTION_NONE);
  }

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