Arduino – while: ripetere finché la condizione è vera (controllo in ingresso)

while esegue un blocco finché la condizione è vera, ma controlla prima di entrare. È perfetto per attese (pulsante premuto, dato disponibile), conteggi con condizione di uscita, e loop che possono saltare del tutto se la condizione è già falsa.

Sintassi

while (condizione) {
  // esegue se (e finché) condizione è vera
}
  • se la condizione è falsa all’inizio, il corpo non la esegue nemmeno una volta;
  • molto usato per polling di eventi e attese non bloccanti (con accortezza sui ritardi).

I primi tre esempi che seguono, propongono funzionalità molto simili a quelle realizzate nella lezione precedente sull’uso del do..while. Come sempre nei commenti le spiegazioni di approfondimento.

Esempio 01 – Attendere la pressione di un pulsante

Utilizziamo un pulsante connesso al pin 2 ed abilitiamo la resistenza di bull-up.

/*
  Prof. Maffucci Michele
  data: 28.10.25

  Premere il pulsante su D2 per proseguire;
  LED lampeggia durante l’attesa.
*/

const int PIN_BTN = 2;  // collegato a GND con INPUT_PULLUP

void setup() {
  pinMode(LED_BUILTIN, OUTPUT);
  pinMode(PIN_BTN, INPUT_PULLUP);
  Serial.begin(9600);
  Serial.println("Premi il pulsante per continuare...");
}
void loop() {
  // Attesa attiva: finché il pulsante NON è premuto
  while (digitalRead(PIN_BTN) == HIGH) {  // HIGH = non premuto (pull-up)
    digitalWrite(LED_BUILTIN, HIGH);
    delay(150);
    digitalWrite(LED_BUILTIN, LOW);
    delay(150);
  }
  Serial.println("Pulsante premuto: procedo!");
  while (true) {}
}

Esempio 02 – Countdown finché t > 0

Utilizziamo un buzzer connesso al pin 5.

/*
  Prof. Maffucci Michele
  data: 28.10.25

  Countdown da 10 a 0; beep a fine conteggio (buzzer su D5)
*/

const int PIN_BUZ = 5;
void setup() {
  Serial.begin(9600);
  pinMode(PIN_BUZ, OUTPUT);
}
void loop() {
  int t = 10;
  while (t > 0) {
    Serial.print("T-");
    Serial.println(t);
    delay(500);
    t--;
  }
  tone(PIN_BUZ, 880, 300);  // beep
  Serial.println("Decollo!");
  while (true) {}
}

Esempio 03 – Leggere finché c’è un dato sulla seriale (svuotare buffer)

Ogni volta che scriviamo un testo e premiamo invio, questo viene mostrato come output sulla Serial Monitor.

/*
  Prof. Maffucci Michele
  data: 28.10.25

  Svuota il buffer leggendo tutti i caratteri arrivati finché disponibili
*/

void setup() {
  Serial.begin(9600);
  Serial.println("Scrivi qualcosa e premi invio");
}
void loop() {
  if (Serial.available() > 0) {
    Serial.print("Ricevuto: ");
    while (Serial.available() > 0) {
      char c = Serial.read();
      Serial.write(c);  // eco del testo
    }
    Serial.println();
  }
}

Esempio 04 – Conta impulsi in 5 secondi (sensore su D2)

Contiamo quante volte un sensore digitale (fotointerruttore, reed, finecorsa) o un pulsante, cambia stato in una finestra temporale di 5 s. Abilitiamo anche in questo caso la resistenza di pull-up si D2.

/*
/*
  Prof. Maffucci Michele
  data: 28.10.25

  Conta impulsi in 5 secondi (D2)
  - Collega un sensore digitale su D2 (INPUT_PULLUP, attivo-basso).
  - Conta quante transizioni LOW->HIGH avvengono in 5 s.
*/

const int PIN_SENSORE = 2;

void setup() {
  Serial.begin(9600);
  pinMode(PIN_SENSORE, INPUT_PULLUP);
  Serial.println("Pronto. Avvio finestra di misura di 5 secondi...");
}

void loop() {
  // finestra temporale di 5 s (5000 ms) usata con millis() per la misura
  const unsigned long finestra = 5000;
  unsigned long t0 = millis();
  int impulsi = 0;

  int statoPrecedente = digitalRead(PIN_SENSORE);

  // Esegue finché non scadono i 5 secondi
  while (millis() - t0 < finestra) { int stato = digitalRead(PIN_SENSORE); // conta il fronte di salita (LOW -> HIGH con pull-up)
    if (statoPrecedente == LOW && stato == HIGH) {
      impulsi++;
    }
    statoPrecedente = stato;
  }

  Serial.print("Impulsi contati in 5 s: ");
  Serial.println(impulsi);

  // Pausa informativa e ripeti
  delay(1000);
}

Esempio 05 – Leggi una stringa fino al terminatore ‘#’

Vengono raccolti tutti i caratteri inseriti sulla serial Monitor fino al carattere # e successivamente all’invio, viene stampata la frase.

/*
  Prof. Maffucci Michele
  data: 28.10.25

  Lettura stringa con terminatore '#'
  - Scrivi nel Serial Monitor una frase e termina con '#'
  - Il programma raccoglie i caratteri fino a '#', poi stampa la frase.
  - Imposta 9600 baud. "No line ending" consigliato.
*/

void setup() {
  Serial.begin(9600);
  Serial.println("Digita una frase e termina con '#':");
}

void loop() {
  // Attende che arrivi almeno un carattere per partire
  // Nessun dato in arrivo: esci da loop() e riprova al prossimo ciclo (evita di eseguire il resto del codice)
  if (Serial.available() == 0)
    return;

  String frase = "";
  char c = '\0';

  // Leggi finché non arriva il terminatore '#'
  while (c != '#') {
    
    // Se non c'è ancora nulla, continua ad attendere, ricontrolla il buffer al prossimo ciclo di while
    // Con continue si passa subito alla prossima iterazione del while
    // (cioè al prossimo controllo della condizione c != '#'),
    // senza eseguire le istruzioni che seguono nel corpo del ciclo.
    if (Serial.available() == 0)
      continue;

    c = Serial.read();
    if (c == '\r' || c == '\n')
      continue;                // ignora a capo
                               // salta il resto e riparte il ciclo, così non aggiungi \r/\n alla stringa raccolta
    if (c != '#') frase += c;  // accumula solo se non è il terminatore
  }

  Serial.print("Hai scritto: ");
  Serial.println(frase);

  // Pulisci eventuali residui e proponi una nuova acquisizione
  while (Serial.available() > 0)
    Serial.read();
  Serial.println("Digita una nuova frase terminata da '#':");
}

Ricordare che:

  • return in loop(): termina l’intera iterazione di loop() (si ricomincia dal prossimo giro della funzione loop());
  • continue: termina solo l’iterazione corrente del ciclo in cui si trova (es. il while interno), poi il ciclo riparte al prossimo ciclo del while;
  • alternative senza continue: si può usare una struttura con else { ... }, ma continue mantiene il corpo più lineare quando si vogliono saltare casi particolari.

Esempio 06 – “Dado” mentre il pulsante è premuto (animazione live)

Tenendo premuto un pulsante, si “fa girare” un numero casuale 1–6; finché il pulsante è premuto l’animazione continua, quando si rilascia il numero si blocca (come lanciare un dado).

/*
  Prof. Maffucci Michele
  data: 28.10.25
  
  Dado con pulsante (D2) e animazione in attesa
  - INPUT_PULLUP su D2 (premuto = LOW)
  - Finché il pulsante è PREMUTO, mostra numeri 1..6 che scorrono.
  - Al rilascio, stampa il risultato finale.
*/

const int PIN_BTN = 2;  // collegare pulsante a GND (INPUT_PULLUP)

void setup() {
  Serial.begin(9600);
  pinMode(PIN_BTN, INPUT_PULLUP);
  pinMode(LED_BUILTIN, OUTPUT);
  randomSeed(analogRead(A0));  // inizializza generatore
  Serial.println("Tieni premuto il pulsante per 'far girare' il dado, poi rilascia.");
}

void loop() {
  // Attendi pressione (attivo-basso)
  if (digitalRead(PIN_BTN) == HIGH)
    return;

  int ultimoNumero = 1;

  // Finché il pulsante rimane premuto, scorrono i numeri
  while (digitalRead(PIN_BTN) == LOW) {
    ultimoNumero = random(1, 7);  // 1..6
    Serial.print("Dado: ");
    Serial.println(ultimoNumero);

    // piccolo effetto visivo sul LED
    digitalWrite(LED_BUILTIN, HIGH);
    delay(60);
    digitalWrite(LED_BUILTIN, LOW);
    delay(60);
  }

  // Debounce semplice sul rilascio
  delay(30);
  if (digitalRead(PIN_BTN) == HIGH) {
    Serial.print("Risultato finale: ");
    Serial.println(ultimoNumero);
    Serial.println("---");
    delay(300);
  }
}

Esercizi

Esercizio 01 – Validazione di input numerico (range 1..10)

Chiedere all’utente un numero intero tra 1 e 10. Finché l’input non è valido, ripetere la richiesta (usare while). Quando è valido, stampare “Valore accettato: X”.

Esercizio 02 – Algoritmo di Euclide (MCD) con while

Leggere due interi positivi a e b dal Serial Monitor e calcolare il Massimo Comun Divisore usando il metodo di Euclide:
ripetere finché b != 0 la sostituzione a, b = b, a % b. Alla fine stampare MCD = a.

Esercizio 03 – Servo: scansione fino al finecorsa (stato controllato con while)

Collegare un servo (pin D9) e un finecorsa su D2 (con INPUT_PULLUP). Far ruotare il servo dal minimo verso il massimo (per passi di 2–3 gradi) finché il finecorsa NON viene premuto (LOW). Quando il finecorsa si attiva, fermarsi e stampare l’angolo raggiunto.

Buon lavoro 🙂

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.