cycle_machine.ino
The state-machine PLC pattern in Arduino: run → timer → pause → end cycle with no blocking delay and priority stop. Transposable to any industrial sequence (dosing, conveyor, press) by changing the timings.
Hardware
An STMicroelectronics Opta PLC (real-time STM32H747 + secure i.MX RT1052 companion) programmed with the Arduino PLC environment, 24 V DIN-rail supply. NO button on IN1, NC button on IN2, motor contactor on RO1, indicator lamp on RO2.
Wiring
24 V buttons to IN1/IN2 (COM to 0 V); RO1 through a power contactor with thermal protection, RO2 to a 24 V lamp.
How it works
A state machine enumerates the phases; millis() drives timers without blocking the loop; the NC stop forces ARRET every sweep, hence immediate cut-off.
Running it
Install the Arduino PLC boards manager, select “Opta PLC”, wire USB/DFU and upload. The sketch runs on the real-time STM32H747 side.
Variants
Add a cycle counter over MQTT, motor current sampling (AI) to detect jams, or a step-by-step jog mode.
cycle_machine.ino
// Opta PLC : cycle automatique — marche/arrêt, temporisations non bloquantes.
// IN1=Marche (NO), IN2=Arrêt (NF), RO1=moteur, RO2=voyant marche.
#include "PLCContainer.h"
PLCContainer PLC;
enum Etat { ARRET, MOTEUR, ATTENTE, RETOUR };
Etat etat = ARRET;
unsigned long tEtat = 0;
const unsigned long T_MOTEUR = 5000; // moteur tourne 5 s
const unsigned long T_ATTENTE = 2000; // pause 2 s
void setup() {
Serial.begin(115200);
PLC.begin();
PLC.DigitalIn.setMode(OPTA_IN_1, PLCDigitalIn::PULL_UP);
PLC.DigitalIn.setMode(OPTA_IN_2, PLCDigitalIn::PULL_UP);
}
bool marche() { return !PLC.DigitalIn.read(OPTA_IN_1); } // NO -> 0 au clic
bool arret() { return PLC.DigitalIn.read(OPTA_IN_2); } // NF -> 0 si ouvert
void eteint() { PLC.Relay[0].off(); PLC.Relay[1].off(); }
void loop() {
if (arret()) { etat = ARRET; } // l'arrêt prime sur tout
switch (etat) {
case ARRET:
eteint();
if (marche()) { etat = MOTEUR; tEtat = millis();
PLC.Relay[0].on(); PLC.Relay[1].on();
Serial.println("Cycle : MOTEUR"); }
break;
case MOTEUR:
if (millis() - tEtat > T_MOTEUR) {
PLC.Relay[0].off(); etat = ATTENTE; tEtat = millis();
Serial.println("Cycle : ATTENTE"); }
break;
case ATTENTE:
if (millis() - tEtat > T_ATTENTE) {
etat = ARRET; Serial.println("Cycle : FIN"); }
break;
}
delay(2);
}