Arduino – istruzione “do…while”: eseguire almeno una volta, poi verificare

Pubblicherò alcuni approfondimenti che serviranno per lo svolgimento di futuri esercizi che svolgeremo in classe e che sicuramente potranno essere di aiuto per risolvere l’attività di educazione civica: “dirimere i conflitti con il pensiero computazionale”.

Gli approfondimenti saranno su:

  1. istruzione do…while
  2. istruzione while
  3. lettura caratteri da serial monitor (che affronteremo anche in questa lezione)
  4. loop infiniti con for, while, do while

Alla fine troverete esercizi da svolgere, se riuscirò pubblicherò su queste pagine la soluzione, altrimenti lo faremo direttamente in classe.

do…while

L’istruzione do…while è utile quando un blocco di codice deve essere eseguito almeno una volta prima di verificare una condizione. È ideale per interazioni utente-centriche (es. chiedere conferma), letture che vanno fatte comunque almeno una volta (prima misura da sensore), o cicli in cui la condizione si conosce solo dopo aver eseguito un passo (validazione di input).

Spiegazione

Sintassi

do {
  // corpo: eseguito almeno una volta
} while (condizione);
  • Il controllo è a fine ciclo: se condizione è vera, il ciclo ripete; se è falsa, esce.
  • Evita pre-inizializzazioni “finte” solo per entrare nel ciclo.

Esempio 01: conferma utente da Serial (Y/N)

// Prof. Maffucci Michele
// data: 26.10.2025
// Esempio 01 - Ripasso uso dell'istruzione do...while

// Chiede conferma almeno una volta; normalizza input
void setup() {
  Serial.begin(9600);  // inizializza la Serial Monitor
  Serial.println("Conferma operazione? (y/n)");
}
void loop() {
  bool confermato = false;
  char scelta;
  do {
    if (Serial.available()) {
      scelta = Serial.read();
      if (scelta >= 'A' && scelta <= 'Z') {
        scelta = scelta - 'A' + 'a';
      }
      confermato = (scelta == 'y' || scelta == 'n');
    }
  } while (!confermato);

  Serial.print("Hai scelto: ");
  Serial.println(scelta == 'y' ? "SI" : "NO");
  while (true) {}  // fine dimostrazione
}

A cosa serve inserire: “while (true) {}” alla fine dell’esempio?

Evita che il codice prosegua oltre la dimostrazione e che il loop() ricominci, quindi è possibile effettuare un solo inserimento.

Se si commenta while (true) {} è possibile continuare ad inserire “y” o “n”

Come rendiamo case-insensitive (indifferente a maiuscole/minuscole) l’input

if (scelta >= 'A' && scelta <= 'Z') {
  scelta = scelta - 'A' + 'a';
}

Controllo dell’intervallo: scelta >= 'A' && scelta <= 'Z'

  • Verifica se il carattere è una lettera maiuscola ASCII tra A e Z.

Conversione in minuscolo: scelta = scelta - 'A' + 'a';

  • Trasforma quella maiuscola nella corrispondente minuscola.

Perché si usa: “- ‘A’ + ‘a’”

Come indicato anche nelle mie slide: “Alfabeto Arduino”, nel set ASCII, le lettere maiuscole e minuscole sono “a blocchi” distanziati da una differenza costante (32 in decimale).

  • ‘A’ ha codice 65, ‘a’ ha codice 97;
  • qualsiasi lettera: 'C' - 'A' = 2 (offset dentro il blocco maiuscole);
  • sommando questo offset a 'a': 2 + 'a' = 'c'.

Quindi:

  • Esempio concreto:
    scelta = 'C' - 'A' + 'a' che sostituendo i codici ASCII otteniamo 67 – 65 + 97 = 99 che è il codice ASCII di ‘c’.

Scriverlo con ‘A’ e ‘a’ (invece di 65 e 97) è più leggibile e non vi fa ricordare numeri.

Quanto è utile

  • rendere i comandi indifferenti al minuscolo o maiuscolo: l’utente può digitare Y o y e il programma li tratta allo stesso modo;
  • Evitare duplicazioni: non servono due rami separati per maiuscolo/minuscolo.

Limiti

  • funziona per le lettere A-Z dell’ASCII standard;
  • non gestisce caratteri accentati né Unicode (Arduino classico usa byte ASCII);
  • lascia invariati numeri e simboli (non entrano nell’if).

Vedremo in successive lezioni l’uso di altri strumenti per la gestione di stringhe inserite sulla Serial Monitor.

Esempio 02: prima lettura sensore, poi ripeti finché entro soglia

Per simulare un sensore in questo esempio viene utilizzato un trimmer collegato sul reoforo centrale ad A0 ed i due reofori laterali uno a GND e l’altro a Vcc.

// Prof. Maffucci Michele
// data: 26.10.2025
// Esempio 02 - Ripasso uso dell'istruzione do...while
// LED su pin 13: lampeggia finché la lettura NON è entro la fascia [450..550]

void setup() {
  Serial.begin(9600);  // inizializza la Serial Monitor
  pinMode(LED_BUILTIN, OUTPUT);
}
void loop() {
  int valore;
  do {
    valore = analogRead(A0);  // lettura comunque almeno una volta
    Serial.print("Valore: ");
    Serial.println(valore);
    digitalWrite(LED_BUILTIN, HIGH);
    delay(100);
    digitalWrite(LED_BUILTIN, LOW);
    delay(100);
  } while (valore < 450 || valore > 550);  // ripeti finché fuori dalla fascia
  Serial.println("Valore entro soglia: ok");
  // ripete una sola volta l'analisi (non ripete il loop()), se desiderate ripetere eliminare il ciclo infinito
  while (true) {}
}

Esempio 03: menu: mostra almeno una volta, poi ripeti finché la scelta risulta non valida

// Prof. Maffucci Michele
// data: 26.10.2025
// Esempio 03 - Ripasso uso dell'istruzione do...while
// Mostra un piccolo menu e accetta comandi 'a' 'b' 'x'; richiede almeno un giro

void setup() {
  Serial.begin(9600);
}
void loop() {
  char cmd = 0;
  do {
    Serial.println("Menu: a=avvia  b=blocca  x=uscita");
    while (!Serial.available()) {}
    cmd = Serial.read();
  } while (cmd != 'a' && cmd != 'b' && cmd != 'x');

  Serial.print("Comando accettato: ");
  Serial.println(cmd);
  // ripete una sola volta l'analisi (non ripete il loop()), se desiderate ripetere eliminare il ciclo infinito
  while (true) {}
}

In questo caso se commentate while (true) {} potete effettuare nuovi inserimenti ma potrebbe accadere qualcosa di molto simile a ciò che è indicato nell’immagine che segue

Quello che vedete non è un bug misterioso 🙂 è il buffer seriale + newline, ma cosa vuol dire?

Quando togliamo while (true) {}, il loop() ricomincia da capo.

Consideriamo la parte di codice dell’esempio:

do {
  Serial.println("Menu: a=avvia  b=blocca  x=uscita");
  while (!Serial.available()) {}
  cmd = Serial.read();                 // <-- legge SOLO il primo byte
} while (cmd!='a' && cmd!='b' && cmd!='x');

la Serial Monitor di Arduino (a seconda dell’impostazione “Line ending”) invia anche \n e/o \r oltre alla lettera che digitate.
Poiché leggete un solo carattere (cmd = Serial.read()) e non svuotate il buffer, restano in coda \r e/o \n.

Al giro successivo del do...while (o al restart del loop()), Serial.available() è già > 0 (ci sono dei newline in coda) quindi:

  • il menu viene stampato subito;
  • viene letto il carattere successivo (che è \n o \r, quindi non valido);
  • la condizione del do...while fallisce e viene ristampato il menu.

Risultato: la stringa compare più volte di fila.

2 modi per risolvere il problema della ripetizione

01. Leggere il primo carattere utile, saltando CR/LF

Viene ignorato esplicitamente \r e \n:

char leggiCharPulito() {
  while (true) {
    while (!Serial.available()) {}
    char c = Serial.read();
    if (c == '\r' || c == '\n') continue;         // salta newline
    if (c >= 'A' && c <= 'Z') c = c - 'A' + 'a';  // normalizza
    while (Serial.available())
      Serial.read();  // svuota residui
    return c;
  }
}

// uso:
do {
  Serial.println("Menu: a=avvia  b=blocca  x=uscita");
  cmd = leggiCharPulito();
} while (cmd != 'a' && cmd != 'b' && cmd != 'x');

02. Impostare il Serial Monitor su “No line ending”

Soluzione molto più semplice che prevede di impostare nel menù a tendina del Serial Monitor (in basso a destra), la selezione di Nessun fine riga (in inglese: No line ending).
Così non verranno inviati \r o \n e il problema dei “doppioni” si elimina.

Proposta di esercizi

Esercizio 01 –  Attendi pulsante

  • Consegna: attendere che un pulsante su D2 venga premuto; durante l’attesa far lampeggiare il LED integrato.
  • Vincoli: usare while come attesa in ingresso (while(digitalRead(…)==HIGH)).
  • Extra: al termine, stampare “OK” e fermarsi.

Esercizio 02 – Svuota buffer seriale

  • Consegna: quando l’utente invia testo, fare echo e svuotare tutti i caratteri residui.
  • Vincoli: usare while(Serial.available()>0).
  • Extra: contare quanti byte sono stati letti e mostrarli.

Esercizio 03 – Timer regressivo

  • Consegna: da un valore t letto da Serial (es. 5..20), eseguire un countdown finché t>0.
  • Vincoli: usare while(t>0) con t– e stampa del tempo.
  • Extra: beep finale + messaggio “Decollo!”.

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.