Esercitazione 4 – Macchina a stati per un ciclo automatico con start, pausa, allarme e reset

Allenamento per l’esame di maturità
Percorso di laboratorio con Arduino per studenti di quinta ITIS

Obiettivo didattico

Modellare un ciclo automatico come macchina a stati: attesa, marcia, pausa, allarme e reset. L’attività avvicina gli studenti al modo in cui si progetta un processo tecnico da esame.

Materiali suggeriti

  • Arduino UNO R3 o UNO R4,
  • 3 pulsanti (START, PAUSA, RESET);
  • 2 LED;
  • 2 Resistori da 220 Ohm (per i LED);
  • jumper.

Schema di collegamento

Richiamo teorico

Una macchina a stati finiti rappresenta un processo come un insieme di stati mutuamente esclusivi. In ogni stato il sistema esegue azioni ben definite e attende eventi che causano il passaggio allo stato successivo. Questo metodo riduce gli errori logici nei programmi complessi.

Schema logico dell’attività

  • All’avvio il sistema è in ATTESA;
  • se arriva START passa a MARCIA;
  • in MARCIA può ricevere PAUSA oppure entrare in ALLARME se scade il tempo massimo;
  • in PAUSA attende una nuova pressione di START;
  • da ALLARME si esce solo con RESET, che riporta il sistema in ATTESA.

Diagramma a stati

Per rappresentare in modo corretto il comportamento di questo esercizio è molto utile affiancare al codice un diagramma a stati. In questo caso, infatti, il sistema non si limita a eseguire istruzioni una dopo l’altra, ma cambia comportamento in funzione della condizione operativa in cui si trova.

Il programma può trovarsi in un solo stato per volta, e ogni stato descrive una precisa fase di funzionamento del sistema. Nel nostro sketch gli stati sono quattro:

  • STATO_ATTESA
  • STATO_MARCIA
  • STATO_PAUSA
  • STATO_ALLARME

Il diagramma a stati è particolarmente adatto a questa situazione perché mostra in modo immediato tre aspetti fondamentali:

  • quali sono gli stati possibili del sistema;
  • quali eventi provocano il passaggio da uno stato all’altro;
  • quale logica di funzionamento è stata implementata nel codice.

In altre parole, mentre il diagramma di flusso descrive bene la sequenza dei controlli svolti nel loop(), il diagramma a stati descrive meglio la struttura logica del processo.

Stato iniziale del sistema

Nel diagramma compare il simbolo iniziale che punta verso STATO_ATTESA. Questo significa che, all’accensione di Arduino o dopo un reset, il sistema parte nello stato di attesa.

In questa fase il ciclo automatico non è attivo. Il LED di marcia è spento, il LED di allarme è spento e il programma controlla continuamente i pulsanti in attesa di un comando di avvio.

Dal punto di vista didattico, questo è il comportamento tipico di molti sistemi automatici: il processo non parte in modo autonomo, ma richiede un comando esplicito dell’operatore.

Transizione da ATTESA a MARCIA

Dal nodo STATO_ATTESA parte una freccia verso STATO_MARCIA con l’etichetta:

START premuto / istanteInizioMarcia = millis()

Questa notazione va letta così: se il sistema si trova in attesa e viene rilevata la pressione del pulsante START, allora il programma passa allo stato di marcia. Durante questa transizione viene anche eseguita un’azione importante, cioè il salvataggio dell’istante iniziale della marcia tramite millis().

Questo passaggio è fondamentale perché permette al sistema di iniziare a contare il tempo trascorso in marcia senza bloccare il programma. In pratica, nel momento in cui parte la marcia, viene memorizzato il riferimento temporale da cui inizierà il controllo del timeout.

Significato dello stato MARCIA

Lo stato STATO_MARCIA rappresenta la fase in cui il sistema è attivo.

In questa condizione il LED di marcia viene acceso, il LED di allarme resta spento e il programma continua a controllare due possibili situazioni:

    • la richiesta di pausa;
    • il superamento del tempo massimo consentito.

Importante: nello stato di marcia il sistema non esegue una sola azione, ma resta in una condizione operativa in cui il programma continua a verificare gli eventi che possono modificare il comportamento complessivo del processo.

Transizione da MARCIA a PAUSA

Se durante la marcia viene premuto il pulsante PAUSA, il sistema passa a STATO_PAUSA.

Questa transizione rappresenta una sospensione del ciclo. Dal punto di vista logico, il processo non è terminato, ma è momentaneamente fermo in attesa di un nuovo comando.

Nel diagramma questa freccia mostra che la pausa può essere richiesta solo quando il sistema si trova effettivamente in marcia. Questo rende molto chiaro un concetto fondamentale: non tutti i comandi hanno senso in tutti gli stati. Il significato di un ingresso dipende dallo stato corrente del sistema.

Transizione da MARCIA a ALLARME

La seconda uscita possibile da STATO_MARCIA conduce a STATO_ALLARME ed è attivata dal superamento del tempo massimo di marcia.

Nel codice questa condizione è realizzata confrontando il tempo attuale, ottenuto con millis(), con l’istante iniziale salvato all’ingresso nello stato di marcia. Quando la differenza raggiunge o supera il valore impostato in TEMPO_MASSIMO_MARCIA, il sistema genera l’allarme.

Questo passaggio è interessante perché mostra come una macchina a stati possa cambiare stato non solo in risposta a un pulsante, ma anche in risposta a una condizione temporale. In molti sistemi automatici reali, infatti, il tempo costituisce un vincolo di sicurezza o di controllo del processo.

Significato dello stato PAUSA

Lo stato STATO_PAUSA rappresenta una sospensione controllata del ciclo.

In questa fase il LED di marcia è spento e il LED di allarme è spento. Il programma non torna allo stato iniziale, ma resta in una condizione intermedia da cui il processo può riprendere.

Dal diagramma si vede che da questo stato esiste una sola transizione utile: la pressione di START, che riporta il sistema in STATO_MARCIA.

È importante però osservare un dettaglio del codice: quando si torna in marcia dalla pausa, il programma esegue di nuovo l’istruzione che salva istanteInizioMarcia = millis(). Questo significa che il conteggio del tempo massimo non viene congelato e poi ripreso, ma riparte da zero.

Questo aspetto è importante, perché aiuta a capire che il diagramma descrive la struttura generale del comportamento, mentre le variabili e le azioni associate alle transizioni determinano il comportamento concreto del sistema.

Significato dello stato ALLARME

Lo stato STATO_ALLARME rappresenta una condizione anomala o di sicurezza.

Quando il sistema entra in allarme, il LED di marcia viene spento e il LED di allarme viene acceso. In questo modo l’operatore può riconoscere immediatamente che il ciclo si è interrotto per il superamento del limite previsto.

Dal diagramma si vede che da STATO_ALLARME non si può tornare direttamente in marcia. L’unica uscita prevista è verso STATO_ATTESA, e questa transizione è attivata dal pulsante RESET.

Anche questa è una scelta molto importante dal punto di vista progettuale: in presenza di un allarme il sistema non riparte automaticamente, ma richiede un intervento esplicito da parte dell’operatore. È una logica tipica dei sistemi in cui la sicurezza o il controllo delle anomalie hanno priorità sulla continuità del funzionamento.

IMPORTANTE

Quando si studiano le macchine a stati è utile distinguere tra:

      • azioni di stato, cioè ciò che il sistema fa mentre si trova in un determinato stato;
      • azioni di transizione, cioè ciò che il sistema esegue nel momento in cui passa da uno stato a un altro.

Nell’esercizio proposto, l’accensione o lo spegnimento dei LED, è un’azione associata allo stato, perché avviene nel blocco di codice relativo a ciascun case.

Il salvataggio di istanteInizioMarcia, invece, è un’azione di transizione, perché viene eseguito nel momento in cui il sistema entra nello stato di marcia.
Questa distinzione è molto utile per comprendere meglio sia il diagramma sia il codice.

Programma

/*
  Prof. Maffucci Michele
  Esercizio 4: Macchina a stati per un ciclo automatico con start, pausa, allarme e reset
*/

const int PIN_START = 2;
const int PIN_PAUSA = 3;
const int PIN_RESET = 4;
const int PIN_LED_MARCIA = 8;
const int PIN_LED_ALLARME = 9;

// ---------------------------
// Enumerazione degli stati
// ---------------------------
enum StatoSistema {
  STATO_ATTESA,
  STATO_MARCIA,
  STATO_PAUSA,
  STATO_ALLARME
};

StatoSistema statoCorrente = STATO_ATTESA;

// Tempo massimo di marcia prima dell'allarme.
const unsigned long TEMPO_MASSIMO_MARCIA = 7000;
unsigned long istanteInizioMarcia = 0;

void setup() {
  pinMode(PIN_START, INPUT_PULLUP);
  pinMode(PIN_PAUSA, INPUT_PULLUP);
  pinMode(PIN_RESET, INPUT_PULLUP);
  pinMode(PIN_LED_MARCIA, OUTPUT);
  pinMode(PIN_LED_ALLARME, OUTPUT);
  Serial.begin(9600);
}

void loop() {
  bool startPremuto = (digitalRead(PIN_START) == LOW);
  bool pausaPremuto = (digitalRead(PIN_PAUSA) == LOW);
  bool resetPremuto = (digitalRead(PIN_RESET) == LOW);

  switch (statoCorrente) {

    case STATO_ATTESA:
      digitalWrite(PIN_LED_MARCIA, LOW);
      digitalWrite(PIN_LED_ALLARME, LOW);

      if (startPremuto == true) {
        statoCorrente = STATO_MARCIA;
        istanteInizioMarcia = millis();
        Serial.println("Passaggio a MARCIA");
      }
      break;

    case STATO_MARCIA:
      digitalWrite(PIN_LED_MARCIA, HIGH);
      digitalWrite(PIN_LED_ALLARME, LOW);

      if (pausaPremuto == true) {
        statoCorrente = STATO_PAUSA;
        Serial.println("Passaggio a PAUSA");
      }
      else if ((millis() - istanteInizioMarcia) >= TEMPO_MASSIMO_MARCIA) {
        statoCorrente = STATO_ALLARME;
        Serial.println("Passaggio a ALLARME");
      }
      break;

    case STATO_PAUSA:
      digitalWrite(PIN_LED_MARCIA, LOW);
      digitalWrite(PIN_LED_ALLARME, LOW);

      if (startPremuto == true) {
        statoCorrente = STATO_MARCIA;
        istanteInizioMarcia = millis();
        Serial.println("Ripresa della MARCIA");
      }
      break;

    case STATO_ALLARME:
      digitalWrite(PIN_LED_MARCIA, LOW);
      digitalWrite(PIN_LED_ALLARME, HIGH);

      if (resetPremuto == true) {
        statoCorrente = STATO_ATTESA;
        Serial.println("Reset: ritorno ad ATTESA");
      }
      break;
  }
}

Come funziona il codice

Questo sketch mostra un modo molto importante di progettare i sistemi automatici: invece di scrivere un programma come una semplice sequenza di istruzioni, si descrive il comportamento del sistema attraverso stati distinti.

Nel nostro caso gli stati sono quattro:

  • ATTESA
  • MARCIA
  • PAUSA
  • ALLARME

In ogni istante il sistema si trova in uno solo di questi stati.
Il loop() legge continuamente ingressi e tempo trascorso, poi decide se restare nello stato attuale oppure passare a quello successivo.

Questa è esattamente la logica che si usa spesso anche nei temi di maturità: non si pensa solo al codice, ma al processo.

01. Dichiarazione dei pin

const int PIN_START = 2;
const int PIN_PAUSA = 3;
const int PIN_RESET = 4;
const int PIN_LED_MARCIA = 8;
const int PIN_LED_ALLARME = 9;

Qui vengono assegnati i pin di Arduino ai dispositivi esterni:

  • il pulsante START sul pin 2
  • il pulsante PAUSA sul pin 3
  • il pulsante RESET sul pin 4
  • il LED di MARCIA sul pin 8
  • il LED di ALLARME sul pin 9

Come ripeto ogni volta l’uso delle costanti dal nome autoesplicativo rende il codice più leggibile: invece di trovare nel programma numeri “sparsi”, si capisce subito quale componente è collegato a ogni pin.

02. Enumerazione degli stati

enum StatoSistema {
  STATO_ATTESA,
  STATO_MARCIA,
  STATO_PAUSA,
  STATO_ALLARME
};

Questa parte è centrale.

L’istruzione enum serve a creare un tipo di dato enumerato, cioè un insieme di valori simbolici predefiniti.
In pratica, invece di rappresentare gli stati con numeri poco chiari come 0, 1, 2, 3, si usano nomi significativi.

Quindi:

  • STATO_ATTESA
  • STATO_MARCIA
  • STATO_PAUSA
  • STATO_ALLARME

sono etichette leggibili che rendono il programma molto più comprensibile.

Dal punto di vista interno, Arduino li gestisce come valori interi, ma per chi legge il codice è molto meglio usare i nomi.

03. Variabile che memorizza lo stato attuale

StatoSistema statoCorrente = STATO_ATTESA;

Qui viene dichiarata la variabile statoCorrente, che contiene lo stato in cui si trova il sistema in questo momento.

All’avvio il sistema parte in:

STATO_ATTESA

quindi il ciclo automatico è fermo e in attesa del comando di START.

Questa variabile è la “memoria logica” del sistema: tutto il comportamento del programma dipende dal suo valore.

04. Tempo massimo di marcia

const unsigned long TEMPO_MASSIMO_MARCIA = 7000;
unsigned long istanteInizioMarcia = 0;

Qui vengono introdotti due elementi importanti.

TEMPO_MASSIMO_MARCIA

È il tempo massimo consentito nello stato di marcia, espresso in millisecondi.

7000

significa 7 secondi.

istanteInizioMarcia

È una variabile che memorizza il valore di millis() nel momento in cui il sistema entra in marcia.

In altre parole:

  • quando parte la marcia, si salva il tempo iniziale
  • durante la marcia si confronta il tempo attuale con quel valore
  • se la differenza supera 7000 ms, si entra in allarme

Questa tecnica è molto importante perché permette di gestire il tempo senza bloccare il programma con delay().

05. Funzione setup()

void setup() {
  pinMode(PIN_START, INPUT_PULLUP);
  pinMode(PIN_PAUSA, INPUT_PULLUP);
  pinMode(PIN_RESET, INPUT_PULLUP);
  pinMode(PIN_LED_MARCIA, OUTPUT);
  pinMode(PIN_LED_ALLARME, OUTPUT);
  Serial.begin(9600);
}

La funzione setup(), come sappiamo, viene eseguita una sola volta all’accensione o al reset della scheda.

Configurazione dei pulsanti

pinMode(PIN_START, INPUT_PULLUP);
pinMode(PIN_PAUSA, INPUT_PULLUP);
pinMode(PIN_RESET, INPUT_PULLUP);

I pulsanti sono configurati come INPUT_PULLUP.

Questo significa che Arduino attiva una resistenza interna di pull-up, che mantiene normalmente il pin a livello logico alto (HIGH).

Di conseguenza:

  • pulsante non premuto > lettura HIGH
  • pulsante premuto > lettura LOW

Questa logica, come sappiamo dalle precedenti lezioni, è detta attiva bassa.

È un dettaglio molto importante, perché spesso quando si inizia ad usare Arduino ci si aspetta che “premuto” significhi HIGH, mentre qui avviene il contrario.

Configurazione delle uscite

pinMode(PIN_LED_MARCIA, OUTPUT);
pinMode(PIN_LED_ALLARME, OUTPUT);

I due LED sono usati come attuatori di segnalazione.

Avvio della comunicazione seriale

Serial.begin(9600);

Serve per inviare messaggi al Monitor Seriale e osservare i passaggi di stato,  ovviamente utile in fase di prova e collaudo.

06. Lettura dei pulsanti nel loop()

bool startPremuto = (digitalRead(PIN_START) == LOW);
bool pausaPremuto = (digitalRead(PIN_PAUSA) == LOW);
bool resetPremuto = (digitalRead(PIN_RESET) == LOW);

All’inizio di ogni ciclo del loop() vengono letti i tre pulsanti.
Qui il programma non salva direttamente HIGH o LOW, ma costruisce tre variabili booleane:

  • startPremuto
  • pausaPremuto
  • resetPremuto

ognuna vale:

  • true se il pulsante è premuto
  • false se il pulsante non è premuto

Poiché i pulsanti sono configurati in INPUT_PULLUP, la condizione di pressione è:

digitalRead(...) == LOW

Questa scelta migliora la leggibilità del programma: dopo, nel codice, si può scrivere semplicemente:

if (startPremuto == true)

anziché ripetere ogni volta digitalRead(...) == LOW.

07. Il cuore del programma: switch (statoCorrente)

switch (statoCorrente) {
   ...
}

Questa struttura seleziona il blocco di istruzioni da eseguire in base allo stato attuale del sistema.

È la forma più naturale per realizzare una macchina a stati:

  • ogni case corrisponde a uno stato
  • in ogni stato si definiscono:
    • le uscite attive
    • le condizioni di transizione

In pratica il loop() si comporta come un supervisore:

  1. legge ingressi e tempo
  2. guarda in che stato si trova il sistema
  3. esegue le azioni previste per quello stato
  4. valuta se deve cambiare stato

Analisi dettagliata dei singoli stati

case STATO_ATTESA:
  digitalWrite(PIN_LED_MARCIA, LOW);
  digitalWrite(PIN_LED_ALLARME, LOW);

  if (startPremuto == true) {
    statoCorrente = STATO_MARCIA;
    istanteInizioMarcia = millis();
    Serial.println("Passaggio a MARCIA");
  }
  break;

Cosa fa questo stato

Il sistema è fermo e non sta eseguendo il ciclo automatico.

Per questo motivo:

  • LED marcia spento
  • LED allarme spento
digitalWrite(PIN_LED_MARCIA, LOW);
digitalWrite(PIN_LED_ALLARME, LOW);

Condizione di uscita

Se viene premuto START:

if (startPremuto == true)

allora il sistema passa a STATO_MARCIA.

Azioni eseguite nel passaggio

Quando si entra in marcia, oltre a cambiare stato, il codice salva l’istante iniziale:

istanteInizioMarcia = millis();

Questa istruzione è fondamentale, perché da questo momento partirà il conteggio del tempo massimo di funzionamento.

Infine viene stampato un messaggio seriale:

Serial.println("Passaggio a MARCIA");

09. Stato di MARCIA

case STATO_MARCIA:
  digitalWrite(PIN_LED_MARCIA, HIGH);
  digitalWrite(PIN_LED_ALLARME, LOW);

  if (pausaPremuto == true) {
    statoCorrente = STATO_PAUSA;
    Serial.println("Passaggio a PAUSA");
  }
  else if ((millis() - istanteInizioMarcia) >= TEMPO_MASSIMO_MARCIA) {
    statoCorrente = STATO_ALLARME;
    Serial.println("Passaggio a ALLARME");
  }
  break;

Cosa fa questo stato

Qui il sistema è in funzione.

Per segnalarlo:

  • LED marcia acceso
  • LED allarme spento

Prima possibilità: passaggio a PAUSA

Se l’utente preme il pulsante PAUSA:

if (pausaPremuto == true)

il sistema entra in STATO_PAUSA.

Questa transizione ha priorità rispetto al controllo del tempo, perché compare come prima condizione dell’if.

Seconda possibilità: passaggio a ALLARME

Se non è stato premuto PAUSA, il codice controlla il tempo trascorso:

(millis() - istanteInizioMarcia) >= TEMPO_MASSIMO_MARCIA

Questa espressione significa:

  • prendi il tempo attuale con millis()
  • sottrai l’istante in cui la marcia è iniziata
  • verifica se il tempo trascorso è maggiore o uguale a 7000 ms
  • Se la condizione è vera, il sistema passa in STATO_ALLARME.

Perché si usa la differenza tra tempi

Come già ripetuto nelle lezioni precedenti, questo è il modo corretto per gestire intervalli temporali in Arduino senza bloccare il programma.

Non si scrive:

delay(7000);

perché così il microcontrollore resterebbe fermo e non potrebbe leggere i pulsanti durante l’attesa.
Con millis() invece il programma continua a ciclare rapidamente e resta sempre reattivo.

10. Stato di PAUSA

case STATO_PAUSA:
  digitalWrite(PIN_LED_MARCIA, LOW);
  digitalWrite(PIN_LED_ALLARME, LOW);

  if (startPremuto == true) {
    statoCorrente = STATO_MARCIA;
    istanteInizioMarcia = millis();
    Serial.println("Ripresa della MARCIA");
  }
  break;

Cosa fa questo stato

Il ciclo è sospeso.

In questa versione del programma:

  • LED marcia spento
  • LED allarme spento

Quindi visivamente la pausa viene rappresentata come uno stato neutro.

Come si esce dalla pausa

Se si preme nuovamente START, il sistema torna in STATO_MARCIA.

Quando il sistema riparte, il codice esegue di nuovo:

istanteInizioMarcia = millis();

Questo significa che il conteggio del tempo massimo riparte da zero.

Quindi il programma non sta memorizzando il tempo già trascorso prima della pausa.

In altre parole:

  • la pausa non congela il conteggio
  • la nuova marcia viene trattata come una nuova partenza

Questo è un punto molto interessante, perché fa capire che una macchina a stati non dipende solo dal diagramma, ma anche da come sono implementate le variabili di memoria.

Se si volesse realizzare una pausa “vera”, che sospende e poi riprende il conteggio dal punto in cui era stato interrotto, servirebbe una logica aggiuntiva.

11. Stato di ALLARME

case STATO_ALLARME:
  digitalWrite(PIN_LED_MARCIA, LOW);
  digitalWrite(PIN_LED_ALLARME, HIGH);

  if (resetPremuto == true) {
    statoCorrente = STATO_ATTESA;
    Serial.println("Reset: ritorno ad ATTESA");
  }
  break;

Cosa fa questo stato

Quando il sistema entra in allarme:

  • LED marcia spento
  • LED allarme acceso

Il processo non riparte da solo.
Questa è una scelta progettuale corretta, perché in molti impianti un allarme richiede un intervento esplicito dell’operatore.

Come si esce dall’allarme

L’unico modo è premere RESET:

if (resetPremuto == true)

A quel punto il sistema torna nello stato iniziale di attesa.

Questa scelta rende il comportamento chiaro e sicuro:

  • da allarme non si va direttamente in marcia
  • bisogna prima riconoscere l’anomalia e riportare il sistema a uno stato noto

12. Perché il break è indispensabile

In ogni case compare alla fine:

break;

Il break serve a interrompere il blocco corrente dello switch.

Se mancasse, il programma proseguirebbe nel case successivo, causando un comportamento errato chiamato fall-through.

In una macchina a stati il break è quindi essenziale per garantire che in ogni ciclo venga eseguito solo il codice relativo allo stato corrente.

13. Come si comporta il loop() nella pratica

Anche se il programma sembra diviso in blocchi, il loop() continua a essere eseguito migliaia di volte al secondo.

Ogni volta avviene questa sequenza:

  • lettura dei pulsanti;
  • verifica dello stato corrente;
  • aggiornamento delle uscite;
  • eventuale cambio di stato.

Questo significa che il sistema è sempre pronto a reagire rapidamente agli eventi, senza rallentamenti artificiali.

È proprio questa ripetizione continua del loop() a rendere possibile il funzionamento della macchina a stati.

14. Logica complessiva del ciclo automatico

Il comportamento del sistema può essere letto così:

  • all’accensione il sistema è fermo in ATTESA
  • con START entra in MARCIA
  • in MARCIA:
    • se arriva PAUSA va in PAUSA
    • se il tempo supera il limite va in ALLARME
  • in PAUSA attende una nuova pressione di START
  • in ALLARME può uscire solo con RESET

Questa struttura riproduce bene il comportamento di molti semplici cicli automatici industriali.

15. Aspetti importanti da evidenziare

a) Separazione tra stati

Ogni stato ha compiti ben precisi.
Questo evita programmi confusi con molte condizioni sparse.

b) Uscite dipendenti dallo stato

I LED non vengono comandati “a caso”, ma in modo coerente con lo stato attuale del sistema.

c) Eventi e transizioni

I pulsanti e il tempo non fanno direttamente “qualcosa”: causano il passaggio da uno stato a un altro.

d) Uso di millis()

Il controllo del tempo è non bloccante, quindi il sistema continua a leggere gli ingressi.

16. Limiti voluti di questo sketch

Per una prima attività didattica il codice è corretto, ma è utile far notare alcune semplificazioni.

Nessun antirimbalzo dei pulsanti

I pulsanti meccanici possono generare rimbalzi.
In questo sketch non è presente una gestione software del debounce.

Nessun riconoscimento del fronte

Il programma controlla se il pulsante è premuto in quell’istante, non se c’è stata la transizione da non premuto a premuto.

Pausa con riavvio del timer

Come detto prima, la pausa non conserva il tempo accumulato in marcia.
Questi limiti non sono difetti da nascondere: al contrario, sono ottimi spunti per sperimentazioni successive.

Esercizio aggiuntivo da svolgere in autonomia

Questo esercizio è basato sull’attività proposta nella lezione, ma richiede l’aggiunta di nuove funzionalità da sviluppare in autonomia. La soluzione verrà pubblicata in un post successivo, così da favorire il lavoro personale di analisi, progettazione e sperimentazione.

Consegna per lo studente

Estendete il ciclo automatico aggiungendo uno stato di MANUTENZIONE e un consenso di sicurezza proveniente da un sensore digitale. Il ciclo può partire solo se il consenso è attivo.
Se il consenso viene a mancare durante la marcia, il sistema entra in ALLARME.
Con il pulsante RESET si esce da ALLARME, mentre con una pressione lunga del pulsante PAUSA
si entra o si esce dalla modalità MANUTENZIONE.

Di seguito la sequenza logica utile per la realizzazione del diagramma di flusso:

  • inizializzazione degli stati e degli ingressi di comando;
  • verifica continua del consenso di sicurezza;
  • transizione tra ATTESA, MARCIA, PAUSA, ALLARME e MANUTENZIONE in base agli eventi;
  • comando delle uscite in funzione dello stato corrente;
  • uso di una macchina a stati esplicita per rendere chiaro il comportamento del processo.

Buon Coding a tutti 🙂

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *

Questo sito utilizza Akismet per ridurre lo spam. Scopri come vengono elaborati i dati derivati dai commenti.