Archivi tag: Compito autentico

Arduino esercizi – Base marziana ELYSIUM – correzione fase 1 – solo pulsante

In riferimento alla lezione: Arduino esercizi – Base marziana ELYSIUM, riporto di seguito tre possibili soluzioni, nei commenti di ogni sketch la spiegazione sul funzionamento.

Fase 1 – solo pulsante

// Prof. Maffucci Michele
// data 12.11.25
// Base marziana ELYSIUM - fase 1 - solo pulsante

const int PIN_LED = 9;
const int PIN_PULSANTE = 2;  // pull-down esterno: HIGH quando premuto

void setup() {
  pinMode(PIN_LED, OUTPUT);
  pinMode(PIN_PULSANTE, INPUT);  // nessun pull-up interno
  digitalWrite(PIN_LED, LOW);
}

void loop() {
  int statoPulsante = digitalRead(PIN_PULSANTE);

  if (statoPulsante == HIGH) {    // pulsante premuto
    digitalWrite(PIN_LED, HIGH);  // accendo la luce di cortesia
    delay(1500);                  // 1,5 s
    digitalWrite(PIN_LED, LOW);  // spengo
    delay(50);                   // piccolo anti-rimbalzo
  }
}

Con questa soluzione alla pressione del pulsante il LED si accende e se rilasciate si spegne, però se mantenete premuto il pulsante notare un veloce spegnimento ed una riaccensione del LED ovvero ciò che stiamo facendo e riaccendere immediatamente il LED.

Per evitare ciò bisogna implementare la versione che evita il retrigger.

Evitare il retrigger significa impedire che, tenendo il pulsante premuto, il ciclo riparta subito dopo lo spegnimento del LED e lo riaccenda di nuovo. Per evitarlo, dopo la sequenza (LED acceso per 1,5 s > LED spento) si controlla se il pulsante è ancora premuto: finché lo è, si rimane dentro un ciclo while bloccante che attende il rilascio. Solo quando il pulsante torna allo stato di riposo si esce dal while, si applica un breve anti-rimbalzo (es. 50 ms) e il programma riprende il loop normale.

ATTENZIONE

il while è bloccante ciò vuol dire che blocca l’intera esecuzione del programma. Va benissimo per questo esercizio semplice; in progetti più complessi è preferibile preferisce rilevare il fronte di salita (variabile di stato) o un approccio non bloccante con millis() che ancora non conoscete (mi sto rivolgendo ai ragazzi di 3′) e che vedremo più avanti.

Fase 1 – solo pulsante – evita il retrigger con while bloccante

// Prof. Maffucci Michele
// data 12.11.25
// Base marziana ELYSIUM - fase 1B - solo pulsante
// evitare il retrigger

const int PIN_LED = 9;
const int PIN_PULSANTE = 2;  // pull-down esterno: HIGH quando premuto

void setup() {
  pinMode(PIN_LED, OUTPUT);
  pinMode(PIN_PULSANTE, INPUT);  // nessun pull-up interno
  digitalWrite(PIN_LED, LOW);
}

void loop() {
  int statoPulsante = digitalRead(PIN_PULSANTE);

  if (statoPulsante == HIGH) {    // pulsante premuto
    digitalWrite(PIN_LED, HIGH);  // accendo la luce di cortesia
    delay(1500);                  // 1,5 s
    digitalWrite(PIN_LED, LOW);   // spengo

    // attendo il rilascio per evitare retrigger continui
    while (digitalRead(PIN_PULSANTE) == HIGH) {
      delay(10);
    }
    delay(50);                    // piccolo anti-rimbalzo
  }
}

Attenzione alla parte di codice:

...
while (digitalRead(PIN_PULSANTE) == HIGH) {
      delay(10);
    }
...

potreste essere tentati di scrivere:

...
while (statoPulsante == HIGH) {
      delay(10);
    }
...

se agite in questo modo, dopo la prima accensione e il successivo spegnimento non riuscirete più ad accendere il LED con successive pressioni del pulsante.

Considerate statoPulsante come uno “scatto fotografico” fatto ad inizio loop(), pertanto se scrivete:

while (statoPulsante == HIGH) { ... }

la condizione resta sempre vera (perché non non viene mai aggiornata).
Risultato: si resta bloccati per sempre in quel while dopo la prima attivazione > il LED si accende una volta e poi il programma non torna più al loop().

Fase 1 – solo pulsante – evita il retrigger senza while bloccante

Fornisco un’altra soluzione in cui non si fa uso del while bloccante.

Invece di “restare fermi” dentro un while finché il pulsante non viene rilasciato, leggiamo il pulsante ad ogni giro del loop e facciamo scattare l’azione solo quando cambia da NON premuto a premuto. Questo momento si chiama fronte di salita.

// Prof. Maffucci Michele
// data 12.11.25
// Base marziana ELYSIUM - fase 1C - solo pulsante
// evitare il retrigger senza while bloccante
// con variabile di stato

const int PIN_LED      = 9;
const int PIN_PULSANTE = 2;   // pull-down esterno: HIGH = premuto

bool premutoPrima = false;

void setup() {
  pinMode(PIN_LED, OUTPUT);
  pinMode(PIN_PULSANTE, INPUT);   // nessun pull-up interno
}

void loop() {
  // Snapshot della lettura
  int statoPulsante = digitalRead(PIN_PULSANTE);

  // Converto HIGH/LOW in booleano
  bool premuto;
  if (statoPulsante == HIGH) {
    premuto = true;    // pulsante premuto
  } else {
    premuto = false;   // pulsante rilasciato
  }

  // Fronte di salita: ora premuto, prima no
  if (premuto && !premutoPrima) {
    digitalWrite(PIN_LED, HIGH);
    delay(1500);
    digitalWrite(PIN_LED, LOW);
    delay(50); // anti-rimbalzo semplice
  }

  // Aggiorna lo stato per il prossimo giro
  premutoPrima = premuto;
}

Come funziona il programma

  • premuto = stato attuale del pulsante (TRUE se è premuto ora, FALSE altrimenti).
  • premutoPrima = stato del pulsante al giro precedente del loop.
  • Condizione di innesco: premuto == true e premutoPrima == false > significa “hai appena iniziato a premere”.

Quando la condizione è vera:

  1. esegui l’azione (es. LED acceso 1,5 s, poi spento),
  2. non restate bloccato: il loop continua a girare,
  3. finché tenete premuto, la condizione non si ripete (perché ora premutoPrima è anch’esso TRUE),
  4. quando rilasciate, premuto torna FALSE; alla prossima pressione avrete di nuovo il fronte di salita.

Questa soluzione offre i seguenti vantaggi:

  • Niente blocchi: il programma continua a leggere ingressi/aggiornare uscite mentre il LED è stato gestito (utile in progetti più grandi).
  • No retrigger con pressione prolungata: scatta una sola volta all’inizio della pressione.
  • Struttura “a eventi”: reagisce ai cambiamenti, non al livello costante del pulsante.

Di seguito la tabella “fronte di salita” (versione con pull-down: HIGH = premuto)

Fase Descrizione Lettura pin premuto (ora) premutoPrima (prima) Condizione premuto && !premutoPrima Azione
T0 Riposo prima della pressione LOW FALSE FALSE FALSE Nessuna
T1 Inizio pressione (fronte salita) HIGH TRUE FALSE TRUE Esegui sequenza LED
T2 Tenuto premuto HIGH TRUE TRUE FALSE Nessuna
T3 Rilascio LOW FALSE TRUE FALSE Nessuna (solo aggiornamento stato)
T4 Nuova pressione (nuovo fronte) HIGH TRUE FALSE TRUE Esegui sequenza LED

Buon Coding a tutti 🙂

Arduino esercizi – Base marziana ELYSIUM

Quest’anno sto supportando, con attività di sperimentazione pratica, anche classi non mie, proponendo laboratori motivanti per riaccendere curiosità e partecipazione. La prossima settimana lavorerò con una terza elettronica numerosa ed eterogenea, non semplice da gestire nei laboratori tradizionali. Per questo, insieme ai colleghi, abbiamo scelto di spostare la lezione nel Laboratorio Territoriale (LTO), uno spazio ricco di attrezzature “inusuali” per un normale laboratorio scolastico: il contesto giusto per stuzzicare l’attenzione e rendere concreti gli apprendimenti su Arduino.

Stato iniziale della classe:

  • hanno svolto le primissime prove con Arduino (blink e poco altro);
  • conoscono le variabili e hanno un’idea dei tipi di dato;
  • sanno riconoscere e usare pulsanti, interruttori, deviatori e LED.

L’obiettivo della lezione è mettere insieme questi elementi in un compito pratico, semplice ma significativo: progettare e realizzare un piccolo controller di luce che usa pulsante, interruttore/deviatore e LED, approfondendo al tempo stesso nozioni base di programmazione (lettura ingressi, gestione del tempo con millis() o delay(), piccola logica a stati AUTO/MANUALE).

Desidero che gli studenti vedano subito un risultato, si divertano a farlo funzionare e, passo dopo passo, consolidino lessico, metodo e fiducia.

Questa lezione sarà suddivisa in tre parti, due introduttive (ed ognuna con attività aggiuntive facoltative) che condurranno alla terza parte conclusiva in cui gli studenti dovranno realizzare il sistema completo.

In ogni fase viene mostrato:

  • diagramma di flusso;
  • pseudocodice;
  • schema di collegamento;

Lo studente deve realizzare lo sketch Arduino di ogni fase.

Come sempre amo introdurre il problema usando una narrazione coinvolgente e visto che mi piace la fantascienza andremo con i ragazzi su Marte. 🙂

Base marziana ELYSIUM

Siete il tecnico elettronico della base marziana. È stato inaugurato un nuovo modulo abitativo e, durante lo spostamento di carichi nel tunnel pressurizzato che collega la serra alla cupola, un carrello radiocomandato ha urtato la parete, provocando una micro-frattura con inizio di depressurizzazione. L’intervento rapido di un manutentore ha evitato il peggio. Dalle analisi emergono due cause principali: affaticamento del personale in turno e illuminazione insufficiente nel corridoio. Per prevenire incidenti e ridurre i consumi, il comando vi incarica di realizzare un controller luce “low-power”: in AUTO la luce si accende per pochi secondi quando viene rilevato il passaggio (lo simulerete con un pulsante); in MANUALE rimane attiva per la durata delle ispezioni EVA (Extra-Vehicular Activity). Il progetto deve essere affidabile, parsimonioso nei consumi e conforme agli standard di sicurezza della base, così da superare senza riserve la verifica dei consumi energetici imminente.

Per evitare che un bug in un solo componente comprometta l’intero sistema, decidete di scomporre il problema e validare separatamente i due comportamenti critici, prima di integrarli.

  1. Prima prova – “Solo PULSANTE” (sensore di passaggio)
    Nel banco di test allestito accanto al tunnel, il tecnico simula l’evento di passaggio con un pulsante. Alla pressione del pulsante la luce si accende un un determinato tempo e poi si spegne.
    (Facoltativo) Sperimentate anche la variante in cui la luce reagisca con un ping di cortesia temporizzato e che non riparta finché il pulsante resta premuto (niente retrigger). Questo serve a scongiurare illuminazioni troppo lunghe dovute a rimbalzi o pressioni involontarie: energia salva, rischio ridotto.
  2. Seconda prova – “Solo INTERRUTTORE” (modalità MANUALE)
    Il tecnico realizza il comando manuale: ON = luce stabile, OFF = buio. Qui controlla la priorità operativa.
    (Facoltativo) Sperimentate anche il feedback all’inserimento, due lampeggi rapidi. Quando si passa a ON: due lampeggi veloci e poi resta acceso.

Superate queste due verifiche, il tecnico procede alla versione finale: unendo AUTO (pulsante) e MANUALE (interruttore) nello stesso controller, con la regola d’oro: MANUALE ha sempre priorità. È così che il progetto rispetta il protocollo Zero-Disturb e arriva pronto alla verifica dei consumi energetici.


Prima prova – “Solo PULSANTE” (sensore di passaggio)

Esercizio: realizzare lo sketch Arduino che permette di realizzare questa prima prova.

Diagramma di flusso

Pseudocodice

INIZIO
  imposta PIN_LED come USCITA
  imposta PIN_PULSANTE come INGRESSO
  scrivi PIN_LED = LOW

  RIPETI PER SEMPRE
    statoPulsante ← leggi(PIN_PULSANTE)   // HIGH = premuto (pull-down esterno)

    SE statoPulsante è HIGH ALLORA
      scrivi PIN_LED = HIGH
      attesa 1500 ms
      scrivi PIN_LED = LOW
      attesa 50 ms
    FINE SE
  FINE RIPETI
FINE

Schema di collegamento

 


Prima prova – “Solo PULSANTE” (sensore di passaggio) – variante che evita il retrigger

Esercizio: realizzare lo sketch Arduino che permette di realizzare la variante della prima prova.

    • Premo > LED acceso ~1,5 s > poi spento.
    • Tenendo premuto non riparte; riparte solo dopo il rilascio.

Diagramma di flusso – versione che evita il retrigger

Pseudocodice – versione che evita il retrigger

INIZIO
  // Setup
  imposta PIN_LED come USCITA
  imposta PIN_PULSANTE come INGRESSO
  scrivi PIN_LED = LOW

  RIPETI PER SEMPRE   // loop
    statoPulsante ← leggi(PIN_PULSANTE)

    SE statoPulsante è HIGH ALLORA           // pulsante premuto
      scrivi PIN_LED = HIGH                  // accendi luce di cortesia
      attesa 1500 ms                         // delay 1,5 s
      scrivi PIN_LED = LOW                   // spegni

      // attesa rilascio per evitare retrigger continui
      MENTRE leggi(PIN_PULSANTE) è HIGH FAI
        attesa 10 ms
      FINE MENTRE

      attesa 50 ms                           // piccolo anti-rimbalzo
    FINE SE
  FINE RIPETI
FINE

Seconda prova – “Solo INTERRUTTORE” (modalità MANUALE)

Esercizio: realizzare lo sketch Arduino che permette di realizzare questa seconda prova.

  • Interruttore ON > LED acceso fisso. (1500 ms)
  • Interruttore OFF > LED spento.

Prevedere un anti-rimbalzo realizzato con un delay di 50 ms.

Diagramma di flusso

Pseudocodice

INIZIO
  imposta PIN_LED come USCITA
  imposta PIN_PULSANTE come INGRESSO
  scrivi PIN_LED = LOW

  RIPETI PER SEMPRE
    statoPulsante ← leggi(PIN_PULSANTE)   // HIGH = premuto (pull-down esterno)

    SE statoPulsante è HIGH ALLORA
      scrivi PIN_LED = HIGH
      attesa 1500 ms
      scrivi PIN_LED = LOW
      attesa 50 ms
    FINE SE
  FINE RIPETI
FINE

Diagramma di flusso

Pseudocodice

INIZIO
  // Setup
  imposta PIN_LED come USCITA
  imposta PIN_INTER come INGRESSO
  scrivi PIN_LED = LOW

  RIPETI PER SEMPRE    // loop
    statoInterruttore ← leggi(PIN_INTER)   // HIGH = MANUALE ON (con pull-down esterno)

    SE statoInterruttore è HIGH ALLORA
      scrivi PIN_LED = HIGH               // LED acceso
    ALTRIMENTI
      scrivi PIN_LED = LOW                // LED spento
    FINE SE
  FINE RIPETI
FINE

Schema di collegamento


Seconda prova (facoltativo) – “Solo INTERRUTTORE” (modalità MANUALE) – variante con feedback all’inserimento

Per il feedback prevedere un accensione e spegnimento del LED per 3 cicli da 80 ms

Diagramma di flusso

Pseudocodice – variante con feedback all’inserimento

INIZIO
  // Setup
  imposta PIN_LED come USCITA
  imposta PIN_INTER come INGRESSO    // pull-down esterno
  scrivi PIN_LED = LOW
  statoPrec ← LOW

  RIPETI PER SEMPRE
    stato ← leggi(PIN_INTER)          // HIGH = MANUALE ON

    // Rilevazione fronte di salita (OFF -> ON)
    SE (stato = HIGH) AND (statoPrec = LOW) ALLORA
      PER i da 0 a 1 FAI               // due lampeggi rapidi
        scrivi PIN_LED = HIGH
        attesa 80 ms
        scrivi PIN_LED = LOW
        attesa 80 ms
      FINE PER
    FINE SE

    // Stato stabile della modalita MANUALE
    SE (stato = HIGH) ALLORA
      scrivi PIN_LED = HIGH
    ALTRIMENTI
      scrivi PIN_LED = LOW
    FINE SE

    statoPrec ← stato
  FINE RIPETI
FINE

Realizzazione del sistema completa

Esercizio 03: realizzare lo sketch Arduino che permette di realizzare l’intero sistema.

  • manuale ON? = interruttore HIGH
  • pulsante premuto? = pulsante HIGH
  • timer attivo? = millis() prima di tScadenza (luce ancora entro i 5 s)

Diagramma di flusso

Pseudocodice

INIZIO
  // Setup
  imposta PIN_LED come USCITA
  imposta PIN_PULSANTE come INGRESSO
  imposta PIN_INTER come INGRESSO
  scrivi PIN_LED = LOW
  tScadenza ← 0
  DURATA_MS ← 5000

  RIPETI PER SEMPRE   // loop
    // Lettura ingressi
    statoInterruttore ← leggi(PIN_INTER)      // HIGH = MANUALE ON (pull-down esterno)
    statoPulsante     ← leggi(PIN_PULSANTE)   // HIGH = pulsante premuto

    // Significato applicativo
    manuale ← (statoInterruttore è HIGH)
    premuto ← (statoPulsante è HIGH)

    SE manuale ALLORA
      scrivi PIN_LED = HIGH                   // LED acceso fisso in MANUALE
    ALTRIMENTI
      SE premuto ALLORA
        tScadenza ← tempoCorrenteMs() + DURATA_MS
      FINE SE

      SE tempoCorrenteMs() < tScadenza ALLORA // timer attivo?
        scrivi PIN_LED = HIGH                 // LED acceso (luce di cortesia)
      ALTRIMENTI
        scrivi PIN_LED = LOW                  // LED spento
      FINE SE
    FINE SE
  FINE RIPETI
FINE

Schema di collegamento

 

Buon Coding a tutti 🙂