Arduino – istruzione while – soluzione esercizi proposti

In riferimento alla lezione: “Arduino – while: ripetere finché la condizione è vera (controllo in ingresso)“, pubblico una possibile soluzione agli esercizi proposti.

Ho utilizzato come finecorsa un pulsante.

Soluzione 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”.

/*
  Prof. Maffucci Michele
  data: 03.11.25

  Esercizio 1 — Validazione input (1..10) con while
  - Chiede un intero all'utente
  - Finché il valore NON è nel range [1..10], lo richiede
*/

void setup() {
  Serial.begin(9600);
  Serial.setTimeout(5000); // tempo max attesa lettura riga
  Serial.println("Inserisci un numero intero tra 1 e 10:");
}

void loop() {
  bool valido = false;
  int numero = 0;

  // Continua finché non ottieni un valore valido
  while (!valido) {
    if (Serial.available() > 0) {
      // leggi una riga intera e converti
      String riga = Serial.readStringUntil('\n');

      // rimuove spazi/a-capo all’inizio e alla fine (es. '\r', '\n', ' ')
      riga.trim();

      if (riga.length() > 0) {  // verifica che l’utente abbia scritto qualcosaa
        numero = riga.toInt();  // converte in intero; '12abc' -> 12, 'abc'/'': 0
        if (numero >= 1 && numero <= 10) {
          valido = true; // uso del valore
        } else {
          Serial.println("Valore non valido. Reinserisci (1..10):");
        }
      }
    }
  }

  Serial.print("Valore accettato: ");
  Serial.println(numero);

  while (true) {}  // fine dimostrazione
}

Soluzione 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.

Ripasso:

Cos’é il MCD (Massimo Comun Divisore)

Il MCD tra due interi positivi a e b è il più grande intero che divide entrambi senza resto.

Esempi:

  • MCD(8, 12) = 4
  • MCD(18, 24) = 6

Algoritmo di Eulide

Ripetere finché b != 0;

  1. calcola resto r = a mod b
  2. sposta i valori: a <- b, b <- r
    Quando b = 0, il MCD è a
/*
  Prof. Maffucci Michele
  data: 03.11.25

  Esercizio 2 — MCD con algoritmo di Euclide usando while
  - Legge due interi positivi a e b
  - Esegue: mentre (b != 0) { resto = a % b; a = b; b = resto; }
  - Stampa il MCD = a
*/

void setup() {
  Serial.begin(9600);
  Serial.setTimeout(20000);
  Serial.println("Calcolo MCD (Euclide). Inserisci due interi positivi separati da invio:");
  Serial.println("Valore a:");
}

void loop() {
  long a = 0, b = 0;

  // Leggi 'a'
  while (a <= 0) { if (Serial.available() > 0) {

      // Legge dal Serial Monitor il secondo intero (a).
      // Attende l’arrivo di cifre, ignora spazi/CR/LF iniziali,
      // Se non trova numeri, restituisce 0 (entro il Timeout).
      a = Serial.parseInt();
      while (Serial.available() > 0)
        Serial.read();  // pulizia CR/LF
      if (a <= 0) Serial.println("Valore non valido. Reinserisci a (>0):");
    }
  }

  Serial.println("Valore b:");
  // Leggi 'b'
  while (b <= 0) { if (Serial.available() > 0) {

      // Legge dal Serial Monitor il secondo intero (b).
      // Attende l’arrivo di cifre, ignora spazi/CR/LF iniziali,
      // Se non trova numeri, restituisce 0 (entro il Timeout).
      b = Serial.parseInt();
      while (Serial.available() > 0)
        Serial.read();
      if (b <= 0) Serial.println("Valore non valido. Reinserisci b (>0):");
    }
  }

  // Algoritmo di Euclide con while
  long resto = 0;
  while (b != 0) {
    resto = a % b;  // resto della divisione
    a = b;          // shift dei valori
    b = resto;
  }

  Serial.print("MCD = ");
  Serial.println(a);  // quando b==0, a è il MCD

  while (true) {}  // fine dimostrazione
}

Soluzione 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.

/*
  Prof. Maffucci Michele
  data: 03.11.25

  Esercizio 3 — Servo: scansione finché NON scatta il finecorsa
  - Servo su D9
  - Finecorsa su D2 (INPUT_PULLUP): NON premuto = HIGH, premuto = LOW
  - All'avvio di Arduino il servo aumenta l'angolo
    finché il finecorsa non diventa LOW (premuto)
  - Sulla Serial Monitor viene mostrato l'angolo percorso
*/

#include <Servo.h> 

const int PIN_SERVO = 9;
const int PIN_FINECORSA = 2;  // collegato a GND, usare INPUT_PULLUP

Servo servoBraccio;

void setup() {
  Serial.begin(9600);
  pinMode(PIN_FINECORSA, INPUT_PULLUP);
  servoBraccio.attach(PIN_SERVO);

  // Porta il servo all'angolo di partenza (0°)
  servoBraccio.write(0);
  delay(500);
  Serial.println("Inizio scansione servo: attendo finecorsa...");
}

void loop() {
  int angolo = 0;

  // Scansione: finché il finecorsa NON è premuto (HIGH), prosegui
  while (digitalRead(PIN_FINECORSA) == HIGH && angolo <= 180) {
    servoBraccio.write(angolo);
    delay(15);         // piccolo tempo per muovere il servo
    angolo += 2;       // passo di scansione
  }

  // Se siamo usciti perché premuto, stampiamo l'angolo
  Serial.print("Finecorsa attivato a ~");
  Serial.print(angolo);
  Serial.println(" gradi (valore approssimativo).");

  // Ferma la dimostrazione: lascia il servo dove si è fermato
  while (true) {}
}

Variante all’esercizio 03

Aggiungo una variante all’esercizio 3 in cui alla pressione di un secondo pulsante, il servo torna a 0° e riparte la scansione.

  • Pulsante finecorsa su D2 (INPUT_PULLUP): quando viene premuto (LOW) la scansione si ferma e si mostra l’angolo raggiunto.
  • Pulsante reset su D3 (INPUT_PULLUP): se premuto in qualunque momento:
    • il servo torna a 0°,
    • la scansione riparte da capo.
/*
  Prof. Maffucci Michele
  data: 03.11.25

  Variante — Servo: scansione fino al finecorsa con pulsante di reset
  - Servo su D9
  - Finecorsa su D2 (INPUT_PULLUP): NON premuto = HIGH, premuto = LOW
  - Pulsante RESET su D3 (INPUT_PULLUP): premuto = LOW
  - Comportamento:
      * Aumenta l'angolo 0 -> 180 a passi di 2° finche' il finecorsa NON è premuto.
      * In QUALSIASI momento, se si preme RESET: il servo torna a 0° e la scansione riparte.
      * Se il finecorsa scatta: stampa l'angolo e attende RESET per ricominciare.

  Note:
  - Debounce semplice con piccoli delay.
  - while(...) usato come "controllo in ingresso" su eventi esterni (finecorsa/reset).
*/

#include <Servo.h>

const int PIN_SERVO = 9;
const int PIN_FINECORSA = 2;  // a GND, usare INPUT_PULLUP
const int PIN_RESET = 3;      // a GND, usare INPUT_PULLUP
const int PASSO_GRADI = 2;

Servo servoBraccio;

void tornaAZeroERiparti() {
  // Porta il servo a 0° e attende il rilascio del pulsante RESET
  servoBraccio.write(0);
  delay(200);
  // attesa rilascio per evitare ri-trigger immediati
  while (digitalRead(PIN_RESET) == LOW) { /* aspetta rilascio */
  }
  delay(30);  // debounce
  Serial.println("RESET: servo a 0° — riparte la scansione.");
}

void setup() {
  Serial.begin(9600);
  pinMode(PIN_FINECORSA, INPUT_PULLUP);
  pinMode(PIN_RESET, INPUT_PULLUP);

  servoBraccio.attach(PIN_SERVO);
  servoBraccio.write(0);
  delay(400);

  Serial.println("Scansione servo: finecorsa su D2, RESET su D3.");
  Serial.println("Premi RESET per tornare a 0° e ripartire; premi il finecorsa per fermare.");
}

void loop() {
  // 01. Posizione iniziale
  int angolo = 0;
  servoBraccio.write(angolo);
  delay(150);

  // 02. Ciclo di scansione: continua FINCHE' il finecorsa NON è premuto
  while (digitalRead(PIN_FINECORSA) == HIGH && angolo <= 180) {
    // Se in qualunque momento premo RESET: torna a 0° e riparte da capo
    if (digitalRead(PIN_RESET) == LOW) {
      delay(30);                            // debounce
      if (digitalRead(PIN_RESET) == LOW) {  // ancora premuto? conferma
        tornaAZeroERiparti();               // porta a zero e gestisci rilascio
        angolo = 0;                         // riparte da 0°
        continue;                           // salta al prossimo giro del while
      }
    }

    // Avanza l'angolo e muove il servo
    servoBraccio.write(angolo);
    delay(15);  // tempo per il movimento
    angolo += PASSO_GRADI;
  }

  // 03. Se esco dal while perche' il finecorsa è premuto (LOW), stampo l'angolo
  if (digitalRead(PIN_FINECORSA) == LOW) {
    // attendo che il pulsante finecorsa venga rilasciato prima di procedere
    delay(30);  // debounce
    Serial.print("Finecorsa attivato a ~");
    Serial.print(angolo);
    Serial.println(" gradi. Premi RESET per ricominciare.");

    // Attendo RESET per ripartire
    while (digitalRead(PIN_RESET) == HIGH) {
      // attesa "passiva": qui potreste far lampeggiare un LED o mostrare stato
      // (teniamo il servo dove si è fermato)
    }
    // debounce e rilascio
    delay(30);
    while (digitalRead(PIN_RESET) == LOW) {
      /* aspetta rilascio */
    }
    delay(30);

    // Riporta a zero e riparte automaticamente al prossimo loop()
    servoBraccio.write(0);
    delay(200);
    Serial.println("Ripartenza da 0°...");
  }

  // Se si è arrivati oltre 180° senza finecorsa, chiedi RESET per ripartire
  if (angolo > 180 && digitalRead(PIN_FINECORSA) == HIGH) {
    Serial.println("Limite 180° raggiunto senza finecorsa. Premi RESET per ripartire.");
    while (digitalRead(PIN_RESET) == HIGH) {
      /* attesa */
    }
    delay(30);
    while (digitalRead(PIN_RESET) == LOW) {
      /* rilascio */
    }
    servoBraccio.write(0);
    delay(200);
  }

  // Il loop ricomincia: nuova scansione partirà da 0°
}

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.