Archivi tag: progettazione del software

Progettare bene, programmare meglio: pseudocodice e diagrammi per sistemi elettronici – lezione 5/5


Ripasso di inizio anno – appunti per la classe.

Di seguito un mini vocabolario, come sempre stampatelo e mettetelo nel tuo quadernone (alcune cose le abbiamo viste anche nella lezione precedente):

Useremo un dialetto semplice.

  • Una istruzione per riga.
  • Parole chiave in MAIUSCOLO e con i due punti : quando aprono un blocco:
    • SE … ALLORA: … ALTRIMENTI:
    • MENTRE (condizione):
    • PER i da A a B:
    • FUNZIONE nome(parametri): RITORNA valore
  • Indentazione (rientro) di 2–4 spazi per il contenuto dei blocchi.
  • Commenti: usa // all’inizio della riga.
  • Nomi chiari per variabili e costanti: sogliaLuce, tempoGiallo, pinLed.

Mini-vocabolario

  • IMPOSTA x a 10: assegna un valore
  • LEGGI x: prendi un input (da Serial o da sensore)
  • SCRIVI …: stampa (su Serial o su un display)
  • ATTENDI 500 ms: pausa
  • ESCI DAL CICLO: interrompi MENTRE o PER
  • OperatorI: ==, !=, <, >, >=, <=, AND, OR, NOT

Mappa mentale

Pseudocodice Arduino (C/C++)
IMPOSTA x a 10 int x = 10; oppure x = 10;
LEGGI da Serial parseInt()/readStringUntil('\n')
LEGGI digitale pin digitalRead(pin)
LEGGI analogico pin analogRead(pin)
SCRIVI su Serial Serial.print()/println()
ACCENDI LED digitalWrite(pin, HIGH)
SPEGNI LED digitalWrite(pin, LOW)
ATTENDI t ms delay(t)
PER i da 1 a N: for (int i=1; i<=N; i++) { ... }
MENTRE (condizione): while (condizione) { ... }
SE / ALTRIMENTI if (...) { ... } else { ... }
FUNZIONE tipo nome(params){...}
RITORNA return

Funzioni di aiuto per leggere dal Monitor Seriale

Blocchi riutilizzabili

// ---------------------------
// Aiuti per I/O seriale
// ---------------------------

// Legge un intero dalla Serial (es.: 42, -17).
// Attende che ci siano dati disponibili, usa parseInt()
// e poi "pulisce" il buffer fino al newline '\n' per preparare
// la prossima lettura.
int leggiInt() {
  // Attende finché il buffer seriale è vuoto.
  // Serial.available() restituisce quanti byte sono pronti da leggere.
  while (!Serial.available()) {
    // ciclo di attesa attivo: resta qui finché non arriva almeno 1 byte
  }

  // parseInt():
  //  - salta automaticamente spazi e caratteri non numerici iniziali;
  //  - legge opzionalmente il segno (-);
  //  - si ferma quando incontra un separatore (es. spazio, '\n', ecc.)
  //  - rispetta Serial.setTimeout(): se i numeri arrivano "a pezzi", attende fino al timeout.
  int v = Serial.parseInt();

  // Dopo parseInt possono essere rimasti caratteri nel buffer
  // (ad es. l'utente ha premuto Invio, quindi c'è '\n' o anche "\r\n").
  // Questo while consuma tutto ciò che c'è fino a trovare '\n' e poi esce,
  // in modo da "allineare" la prossima lettura all'inizio della riga seguente.
  while (Serial.available()) {
    // Legge un carattere dal buffer
    if (Serial.read() == '\n') break; // esce quando trova il newline
    // Nota: se volessi trattare anche '\r' come fine riga su sistemi Windows,
    // potresti controllare anche '\r' (carriage return).
  }

  // Restituisce il valore intero letto.
  return v;
}

// Legge una riga di testo fino al newline '\n' e la restituisce come String.
// Esempio di input: "ciao mondo\n" -> "ciao mondo" (senza newline né spazi finali).
String leggiLinea() {
  // Attende che arrivi almeno un byte.
  while (!Serial.available()) {
    // attesa attiva
  }

  // Legge i caratteri fino al delimitatore '\n' (newline).
  // Il newline non viene incluso nella String risultante.
  String s = Serial.readStringUntil('\n');

  // trim():
  //  - rimuove spazi iniziali/finali, tab e ritorni a capo residui.
  //  - Utile se su alcune piattaforme l'invio produce "\r\n" (Windows):
  //    readStringUntil('\n') rimuove '\n', ma può restare '\r' in coda; trim() lo elimina.
  s.trim();

  // Restituisce la riga "pulita".
  return s;
}

Codice senza commenti da copiare ed incollare:

// ——— Aiuti per I/O seriale ———
int leggiInt() {
  while (!Serial.available()) {}
  int v = Serial.parseInt();
  while (Serial.available()) {
    if (Serial.read() == '\n') break;
  }
  return v;
}

String leggiLinea() {
  while (!Serial.available()) {}
  String s = Serial.readStringUntil('\n');
  s.trim();
  return s;
}

Esempi guidati pseudocodice > sketch Arduino

Esempio 01 – Saluto con nome (solo Serial)

Scopo: input/output base, variabili stringa.

Pseudocodice – esempio 01

SCRIVI "Come ti chiami?"
LEGGI nome
SCRIVI "Ciao, " + nome + "!"

Arduino – esempio 01 – con commenti

void setup() {
  Serial.begin(9600);          // Inizializza la seriale a 9600 baud (Monitor Seriale deve avere lo stesso valore).

  while (!Serial) { ; }        // Attende che la porta seriale sia pronta (utile su schede con USB "native", es. UNO R4).
                               // Su UNO R3 spesso non serve, ma non fa danni.

  Serial.println("Come ti chiami?"); // Messaggio iniziale: l’utente vede la richiesta nel Monitor Seriale.

  Serial.setTimeout(60000);    // Imposta il "tempo massimo di attesa" a 60 s per funzioni come readStringUntil/parseInt.
                               // Se l’utente impiega tempo a digitare, la lettura aspetta fino a 60 s prima di rinunciare.
}

void loop() {
  String nome = leggiLinea();  // Legge una riga di testo inserita dall’utente fino al tasto Invio (newline '\n').
                               // Esempio: se scrivo "Michele" e premo Invio, nome = "Michele".

  Serial.print("Ciao, ");      // Stampa senza andare a capo...
  Serial.print(nome);          // ...stampa il nome letto...
  Serial.println("!");         // ...e chiude la riga con il punto esclamativo + newline.

  while (true) {}              // Ferma il programma qui (loop infinito).
                               // Serve per NON chiedere nuovamente il nome in un ciclo senza fine.
                               // Se vuoi che ripeta la domanda, rimuovi questa riga.
}

Arduino – esempio 01 – senza commenti

void setup() {
  Serial.begin(9600);
  while (!Serial) {;}
  Serial.println("Come ti chiami?");
  Serial.setTimeout(60000);
}

void loop() {
  String nome = leggiLinea();
  Serial.print("Ciao, ");
  Serial.print(nome);
  Serial.println("!");
  while (true) {}  // fine
}

Esercizio aggiuntivo: chiedi anche l’età e rispondi “Sei maggiorenne/minorenne”.

Esempio 02 – Blink (LED lampeggiante)

Collegamenti: LED con resistenza su pin 13 (o usa quello onboard).

Pseudocodice – esempio 02

IMPOSTA pinLed a 13
IMPOSTA periodo a 500 ms
MENTRE (vero):
    ACCENDI LED
    ATTENDI periodo
    SPEGNI LED
    ATTENDI periodo

Arduino – esempio 02

const int pinLed = 13;
const int periodo = 500;

void setup() {
  pinMode(pinLed, OUTPUT);
}

void loop() {
  digitalWrite(pinLed, HIGH);
  delay(periodo);
  digitalWrite(pinLed, LOW);
  delay(periodo);
}

Esercizio aggiuntivo: leggi periodo da Serial.

Esempio 03 – Pulsante accende/spegne LED

Collegamenti: pulsante su pin 2, modalità INPUT_PULLUP; LED su pin 8.
Nota: il pulsante chiude a GND (premuto = LOW).

Pseudocodice – esempio 03

IMPOSTA statoLed a SPENTO
MENTRE (vero):
    LEGGI pulsante
    SE (pulsante premuto) ALLORA:
        ATTENDI 20 ms  // anti-rimbalzo semplice
        SE (ancora premuto) ALLORA:
            inverti statoLed
            applica stato al LED
            ATTENDI rilascio

Arduino – esempio 03

const int pinBtn = 2;
const int pinLed = 8;
bool statoLed = false;

void setup() {
  Serial.begin(9600);
  pinMode(pinBtn, INPUT_PULLUP);
  pinMode(pinLed, OUTPUT);
}

void loop() {
  if (digitalRead(pinBtn) == LOW) {  // premuto
    delay(20);                       // debounce base
    if (digitalRead(pinBtn) == LOW) {
      statoLed = !statoLed;  // toggle
      digitalWrite(pinLed, statoLed ? HIGH : LOW);
      // Attendi rilascio
      while (digitalRead(pinBtn) == LOW) {}
      delay(20);
    }
  }
}

Esercizio aggiuntivo: Estensione: stampa su Serial “ON/OFF” ad ogni pressione.

Esercizi

Esercizio 01 – Potenziometro > luminosità (PWM)

Obiettivo: Regolare mediante potenziometro l’intensità luminosa del LED.
Collegamenti: potenziometro su A0; LED su pin PWM 9.

Esercizio 02 – LED ON per 3 secondi quando premo il pulsante

Obiettivo: premo il pulsante > il LED rimane acceso per 3 secondi > poi si spegne.
Evitare ripetizioni mentre si tiene premuto (debounce base).

Componenti & Collegamenti

  • 1 × LED + 1 × resistenza (220–330 Ω) su pin 8 → GND
  • 1 × pulsante su pin 2 con INPUT_PULLUP (l’altro capo del pulsante a GND)

Esercizio 03 — LDR: accendi il LED quando è buio

Obiettivo: leggo la luce con una LDR. Se il valore è sotto una soglia (buio), accendo il LED; altrimenti lo spengo. Stampo i valori su Serial.

Componenti & Collegamenti

  • LDR in partitore su A0 (esempio: 5V — LDR — A0 — resistenza 10 kΩ — GND)
  • LED + resistenza su pin 9 → GND

Esercizio 04 – Potenziometro > luminosità LED (PWM)

Obiettivo: con il potenziometro regolo la luminosità del LED usando analogWrite (PWM).

Componenti & Collegamenti

  • Potenziometro 10 kΩ su A0 (estremi a 5V e GND, cursore ad A0)
  • LED + resistenza su pin ~9 (pin PWM) > GND

Buon Coding a tutti 🙂

Progettare bene, programmare meglio: pseudocodice e diagrammi per sistemi elettronici – lezione 4/5


Ripasso di inizio anno – appunti per la classe.

Nella lezione precedente abbiamo capito che cos’è lo pseudocodice e perché ci aiuta a trasformare problemi della vita quotidiana in passi ordinati, fatti di input, decisioni e azioni. Lo abbiamo usato per pianificare una routine del mattino, un “pomodoro” di studio, uno “zaino intelligente”: esempi senza hardware, ma già con la testa da progettisti.

Oggi facciamo un passo in più: useremo lo stesso modo di pensare per progettare sistemi elettronici con Arduino. Tradurre “ciò che deve accadere” in uno pseudocodice chiaro e verificabile ci farà risparmiare tempo quando passeremo alla codifica in C/C++.

Vedremo in questa lezione come:

  • descrivere il comportamento di un sistema (sensori, attuatori, tempi, soglie) prima di scrivere codice;
  • organizzare lo pseudocodice in sezioni: costanti e pin, variabili di stato, inizializzazione, loop principale, funzioni;
  • riconoscere e usare pattern ricorrenti da laboratorio: lettura sensori, debounce, timer con millis(), macchina a stati semplici;
  • migliorare la qualità del vostro pseudocodice: nomi significativi, commenti utili, blocchi brevi, casi limite previsti;

L’obiettivo pratico è quello di fornire uno schema eseguibile del vostro sistema, uno pseudocodice che, riga per riga, si traduce in istruzioni Arduino.

Vediamo come fare.

Vi ricordo che in laboratorio non “giochiamo con led e fili”: impariamo a progettare sistemi.
Ogni sistema ha ingressi (sensori), uscite (attuatori), stati, soglie, tempi e condizioni di errore, pertanto mettere tutto in ordine prima di codificare significa:

  • sapere cosa misurare e quando;
  • chiarire quando intervenire (condizioni);
  • evitare loop confusi e delay() ovunque (inizio a dirvi che il delay è il male assoluto 🙂 );
  • testare in modo mirato (so quali valori provo e che output mi aspetto);

Quindi il risultato quale sarà?

  • Meno frustrazione;
  • meno “perché non va?”;
  • più tempo per capire.

Le fasi di lavoro saranno le seguenti:

  • progettazione: partiremo dal comportamento desiderato e lo scriveremo in pseudocodice, a blocchi.
  • traduzione: mapperemo ogni blocco in istruzioni Arduino (Serial, pinMode, digitalRead/Write, analogRead, map, millis, ecc.);
  • verifica: controlleremo che i casi limite siano previsti (pulsante che rimbalza, soglia ballerina, time-out, errori di misura);
  • codifica: solo alla fine andremo sull’IDE Arduino.

Per semplificare la fase di progettazione di seguito trovate alcune regole di base molto semplici che consiglio di trasformare in un foglio di riferimento da aggiungere all’inizio del quadernone.

Regole di base

  • scrivi una istruzione per riga;
  • usa i due punti dopo le parole chiave (SE:, PER:, MENTRE:, FUNZIONE:);
  • indenta (vai a capo e rientra) quello che sta “dentro” ad un blocco;
  • metti commenti con // per spiegare.

Esempio di forma di scrittura codice:

SE (condizione) ALLORA:
    fai questa cosa
ALTRIMENTI:
    fai quest’altra

Negli anni passati avete già programmato, ma poiché ho notato qualche disordine e dimenticanza di seguito vi elenco le strutture di base in pseudocodice che useremo come base di partenza, le scrivo io, le analizzeremo e poi userete questi blocchi come mattoncini lego per scrivere lo pseudocodice di un sistema.

Input / Output

LEGGI nome
SCRIVI "Ciao, " + nome

Variabili

imposta eta a 13
imposta temperatura a 21.5

Scelte (IF)

SE (eta >= 18) ALLORA:
    SCRIVI "Maggiorenne"
ALTRIMENTI:
    SCRIVI "Minorenne"

Ripetizioni (LOOP)
Per numero di volte:

PER i da 1 a 5:
    SCRIVI i

Finché una condizione è vera

imposta numero a 1
MENTRE (numero <= 10):
    SCRIVI numero
    numero = numero + 1

Funzioni (blocchi riutilizzabili)

FUNZIONE somma(a, b):
    RITORNA a + b

SCRIVI somma(3, 4)  // stampa 7

Liste (array) piccole

imposta voti a [7, 8, 6, 9]
per ogni v in voti:
    SCRIVI v

Nota sullo stile dei commenti

E’ importante commentare e saper commentare, ne abbiamo già parlato, ma credo sia meglio ribadirlo:

usare nomi chiari: “contaStudenti” è meglio di “c”, ricorda di usare la forma camelcase;
commenta le parti importanti:

// aggiorno il punteggio
punteggio = punteggio + 10

Usa un’idea per riga: corto e leggibile.

Errori comuni

3 errori che ritrovo sempre nelle correzioni delle esercitazioni, sia nello scrivere lo pseudocodice che il codice:

  • dimenticare di aggiornare le variabili nei cicli > il ciclo non finisce mai.
  • usare = invece di == nelle condizioni (in pseudocodice teneteli distinti);
  • non indentare: diventa confuso capire cosa sta dentro un IF o un ciclo.

Qualche esempio pratico

Pari o dispari

LEGGI n
SE (n % 2 == 0) ALLORA:
    SCRIVI "Pari"
ALTRIMENTI:
    SCRIVI "Dispari"

Massimo tra 3 numeri

LEGGI a, b, c
imposta max a a
SE (b > max) ALLORA: max = b
SE (c > max) ALLORA: max = c
SCRIVI "Massimo = " + max

Conta quanti voti ≥ 6

LEGGI N
imposta cont a 0

PER i da 1 a N:
    LEGGI voto
    SE (voto >= 6) ALLORA:
        cont = cont + 1

SCRIVI "Promossi: " + cont

Nella prossima lezione vedremo come passare dallo pseudocodice allo sketch Arduino.

Buon pseudocodice a tutti 🙂

Progettare bene, programmare meglio: pseudocodice e diagrammi di flusso per sistemi elettronici – lezione 3/5


Ripasso di inizio anno – appunti per la classe.

Lo pseudocodice è un modo semplice e strutturato di descrivere un algoritmo in lingua naturale (italiano+parole chiave) senza la rigidità della sintassi di un linguaggio di programmazione.
È come scrivere una ricetta: elenchi ingredienti (dati), spieghi i passaggi (istruzioni) e le condizioni (“se… allora…”). Non lo “esegue” il computer, ma lo capiscono persone (docenti, compagni, te stesso domani) e ti guida a tradurre poi tutto in codice (es. Arduino/C++).

Cosa rende utile lo pseudocodice

Chiedere agli studenti di scrivere pseudocodice non è un esercizio di progettazione, ma neanche un modo per semplificare la progettazione del nostro sistema, è un modo che permette di decidere prima che cosa deve accadere, poi si penserà a come scriverlo in un linguaggio di programmazione, nel nostro caso in C/C++ per Arduino.

Possiamo definire lo pseudocodice come ad una lingua ponte: viene compreso sia da chi programma ma anche da chi ancora non programma; detto in altro modo possiamo dire che “mette in fila le idee”, riduce gli errori di distrazione, rende veloce il debug e lascia una traccia chiara e leggibile del progetto.

E’ sicuramente uno strumento inclusivo: abbassa la soglia d’ingresso per chi fatica con la sintassi ed è più abile nel ragionamento.

Nella pratica se so raccontare bene l’algoritmo con verbi chiari (LEGGI, SE, MENTRE, RITORNA), tradurlo in codice diventa un’operazione quasi meccanica.

Avrete intuito che saper scrivere pseudocodice non è solo un’attività di progettazione del software, ma anche un modo per comprendere sistemi complessi che interessano non solo la programmazione ma la nostra vita quotidiana: organizzare lo studio, pianificare un viaggio, andare a scuola, ecc… tutto può essere reso pseudocodice, se vi allenerete a scrivere pseudocodice vi accorgerete di avere maggior percezione di un problema e lo comprenderete meglio.

Sintetizziamo quanto sopra detto con una lista puntata che vi servirà nello studio.

Vantaggi dello pseudocodice

  • Chiarezza di idee: separate il cosa fare dal come scriverlo in C/C++.
  • Comunicazione: è una lingua comune tra chi sa e chi non sa ancora programmare, oppure una lingua comune tra persone che serve per comprendere un sistema.
  • Progettazione top-down: partite dal problema, lo scomponete in sotto-problemi, definite funzioni e responsabilità.
  • Riduzione errori: se l’algoritmo è corretto in pseudocodice, gli errori in codice molto probabilmente si ridurranno a dettagli sintattici.
  • Debug più rapido: quando il programma non funziona, si verifica prima la logica (lo pseudocodice), poi la sintassi.
  • Documentazione: lasciate tracce intelligibili del progetto, quindi ottimo per la relazione di laboratorio.
  • Valutazione: mostra il processo e non solo il risultato. Un buon pseudocodice rivela le vostre competenze di analisi, decomposizione, gestione dei casi limite (pensate a quanto diventa utile anche durante la prova scritta dell’esame di maturità… ne parlo più avanti)
  • Inclusione: aiuta chi ha poca dimestichezza con la sintassi a concentrarsi sui concetti fondamentali (input, output, decisioni, cicli, dati).

Perché è importante usarlo nel laboratorio di sistemi elettronici

In laboratorio non scriviamo solo righe di codice: progettiamo sistemi con sensori, attuatori, tempi, soglie e stati.
Lo pseudocodice costringe a dichiarare pin, costanti e variabili di stato, a prevedere debounce, time-out, condizioni di errore, cioè chiarisce il flusso:

inizializzazione > letture > decisioni > azioni

e rivolgendomi agli studenti, vedrete che renderà i test al banco di lavoro più rapidi, nel senso che saprete già quali valori provare e che risposta aspettarmi su ad esempio un LED, buzzer o seriale.

Ritengo che tra i vantaggi più importanti nella realizzazione dello pseudocodice ci sia quella di facilitare il lavoro di gruppo:

ognuno implementa una funzione sapendo dove si inserisce nel flusso generale. Risultato: meno tentativi a vuoto, più tempo speso a capire cosa fa davvero il nostro sistema.

Nelle esercitazioni che svilupperete con Arduino ma in generale con qualsiasi scheda a microcontrollore, c’è sempre un “sistema” da far funzionare: sensori, attuatori, logica, tempi, soglie, stati.

Se scriverete prima lo pseudocodice:

  • sarete obbligati a dichiarare ingressi (sensori), uscite (attuatori), costanti (soglie, pin), variabili di stato;
  • sarà più chiaro il flusso: inizializzazione > ciclo principale > gestione eventi > funzioni di servizio;
  • vi aiuterà a ragionare su casi limite (esempio: debounce, errori di misura, time-out);
  • diventerete più rapidi nel passaggio alla codifica e nella verifica sperimentale al banco.

In pratica: pseudocodice = “schema funzionale” del vostro impianto in forma testuale.

Pensiamo ora ad un evento che vi coinvolgerà: l’esame di maturità

Sarebbe bello ottimizzare il tempo della prova scritta di sistemi (se questa sarà la materia della seconda prova) ma l’uso dello pseudocodice va bene anche per la progettazione di qualsiasi tipo di prova, anche per strutturare un tema di italiano.
All’orale la commissione potrebbe valutare anche come progettate, quindi non solo se il codice funziona. Saper scrivere su un foglio:

Requisiti > Pseudocodice > Schema I/O > Stralcio di codice > Piano di test

sicuramente comunica metodo, ordine e padronanza… e quindi fate una bella figura 😉

Lo pseudocodice vi aiuta a spiegare le scelte: perché una soglia? perché una macchina a stati? come gestisci i casi limite?
E vi mette al sicuro quando vi chiedono una variazione durante l’orale: se la logica è chiara, sapete subito dove intervenire. È un modo semplice per far vedere che sapete passare dall’idea all’implementazione in modo professionale.

Immaginate poi ad un insegnante che dovrà correggere il vostro compito, avere un buon pseudocodice vi assicuro che lo aiuta 😉

Quindi sintetizzando è molto importante ricordare:

  • esporre prima lo pseudocodice mette in luce le vostre capacità progettuali;
  • mostra che sapete astrarre dal codice e motivare le scelte;
  • facilita domande e risposte: il docente può chiedervi di modificare una parte, ad esempio aggiungere un sensore e voi sapete intervenire nel flusso.

e non ultimo farà pensare: “questa persona è professionale”.

Ora andiamo al nocciolo della questione, vediamo come si fa lo pseudocodice, in realtà vi darò una linea guida, qualche esempio ed esercizi semplici che coinvolgono la vostra vita quotidiana, imparerete in brevissimo tempo.

Quello che scrivo da questo momento in poi dovrebbe essere inserito nelle prime pagine del vostro quaderno, dove andrete ad inserire i riferimenti delle schede che utilizziamo, della sintassi di programmazione ecc…

Nota i miei studenti (da recuperare)

Ricordo che ogni attività di progettazione che farete e consegnerete dovrà includere:

    • diagramma di flusso
    • pseudocodice
    • sketch Arduino commentato in ogni parte
    • breve relazione di funzionamento
    • eventuale:
      • schema elettrico
      • schema topografico di collegamenti
      • tabella misure
      • grafici
    • Sitografia
    • Bibliografia

A tal proposito vi mostrerò un format di foglio di lavoro che potrete poi modificare secondo necessità.

Ogni progetto deve essere esposto anche oralmente.

In alcune occasioni vi sarà azione di debate, ovvero un confronto tra gruppi su specifici problemi tecnici da risolvere.

Regole di base

  • Una istruzione per riga; rientra (indenta) i blocchi.
  • Parole chiave in MAIUSCOLO: SE, ALTRIMENTI, MENTRE, PER, FUNZIONE, RITORNA, ATTENDI.
  • Date nomi chiari a variabili e costanti: sogliaLuce, tempoGiallo, pinLedRosso, cioè usiamo la convenzione camelcase che combina più parole in un’unica stringa, scrivendo la prima parola in minuscolo e le parole successive con la loro iniziale maiuscola ad esempio: nomeUtente.
  • In testa: Pin, Costanti, Variabili. Poi: Inizializzazione, Loop, Funzioni.
  • Commentate perché fate qualcosa, non scrivete l’ovvio: “sommo 1 al contatore perché ogni impulso accende il led…”

Di seguito un template da copiare ed incollare:

/* Requisito sintetico: cosa deve fare il sistema */

COSTANTI:
    pinLed = ...
    pinBtn = ...
    soglia = ...

VARIABILI:
    stato = ...
    conteggio = ...

INIZIALIZZA:
    configura pin
    azzera conteggi

LOOP PRINCIPALE:
    leggi sensori
    SE (condizione) ALLORA:
        azione
    ALTRIMENTI SE (...) ALLORA:
        altra azione
    ALTRIMENTI:
        default
    aggiorna attuatori
    ATTENDI t ms

FUNZIONI:
    FUNZIONE nome(parametri):
        passi...
        RITORNA valore

La checklist da seguire ASSOLUTAMENTE è questa:

  1. Input/Output identificati? (pin, range, unità)
  2. Costanti definite? (soglie, tempi, limiti)
  3. Stati chiari? (idle, misura, allarme, reset…)
  4. Casi limite previsti? (debounce, isteresi, time-out, valori anomali)
  5. Test plan minimo? (quali valori proverai e cosa ti aspetti di vedere)

Ora facciamo qualche esempio che coinvolge la nostra vita

01 – Sveglia e alzarsi

Diagramma di flusso Mermaid

graph TD
    A[Inizio] --> B[Suona sveglia]
    B --> C{Ancora sonno?}
    C -- Si --> D[Attendi 5 minuti]
    D --> B
    C -- No --> E[Alzati dal letto]
    E --> Z[Fine]

Diagramma di flusso

Pseudocodice

RIPETI
  SUONA_SVEGLIA()
  LEGGI risposta // "si" se hai ancora sonno, "no" altrimenti
  SE risposta == "si" ALLORA
     ATTENDI 5 minuti
  ALTRIMENTI
     ESCI DAL CICLO
  FINE SE
FINCHÉ VERO
ALZATI_DAL_LETTO()
SCRIVI "Pronto per iniziare la giornata"

02 – Colazione semplice

Si pone che la scelta sia tra due tipologie di colazione, latte o te, in alternativa bisogna bere acqua.

Diagramma di flusso Mermaid

graph TD
    A[Inizio] --> B[Apri cucina]
    B --> C{Hai fame?}
    C -- Si --> D[Scegli bevanda]
    D --> E{Bevanda scelta latte?}
    E -- Si --> F[Prepara latte]
    E -- No --> G[Prepara te]
    F --> H[Mangia colazione]
    G --> H
    C -- No --> I[Bevi acqua]
    H --> Z[Fine]
    I --> Z

Diagramma di flusso

Pseudocodice

APRI_CUCINA()
LEGGI fame // "si" oppure "no"

SE fame == "si" ALLORA
   SCRIVI "Scegli una bevanda"
   LEGGI bevanda // "latte" oppure "te"
   SE bevanda == "latte" ALLORA
      PREPARA_LATTE()
   ALTRIMENTI
      PREPARA_TE()
   FINE SE
   MANGIA_COLAZIONE()
ALTRIMENTI
   BEVI_ACQUA()
FINE SE

SCRIVI "Colazione terminata"

03 – Prepara lo zaino

Diagramma di flusso Mermaid

APRI_DIARIO()
LEGGI listaLibriRichiesti
IMPOSTA zaino = lista_vuota
PER ciascun libro IN listaLibriRichiesti:
   AGGIUNGI libro A zaino
FINE PER

CONTROLLA_ASTUCCIO()

LEGGI mancaQualcosa // "si" oppure "no"
MENTRE mancaQualcosa == "si" FAI
   LEGGI cosaManca
   AGGIUNGI cosaManca A zaino
   LEGGI mancaQualcosa // ricontrolla
FINE MENTRE

SCRIVI "Zaino pronto"

Diagramma di flusso

Pseudocodice

APRI_DIARIO()
LEGGI listaLibriRichiesti
IMPOSTA zaino = lista_vuota
PER ciascun libro IN listaLibriRichiesti:
   AGGIUNGI libro A zaino
FINE PER

CONTROLLA_ASTUCCIO()

LEGGI mancaQualcosa // "si" oppure "no"
MENTRE mancaQualcosa == "si" FAI
   LEGGI cosaManca
   AGGIUNGI cosaManca A zaino
   LEGGI mancaQualcosa // ricontrolla
FINE MENTRE

SCRIVI "Zaino pronto"

04 – Uscire di casa in base al meteo

Si pone che, in funzione del tempo, la scelta sia tra due oggetti alternativi: ombrello o cappellino.

Diagramma di flusso Mermaid

graph TD
    A[Inizio] --> B[Leggi meteo]
    B --> C{Pioggia?}
    C -- Si --> D[Prendi ombrello]
    C -- No --> E[Prendi cappellino]
    D --> F[Esci di casa]
    E --> F
    F --> Z[Fine]

Diagramma di flusso

Pseudocodice

LEGGI meteo // "pioggia" oppure "sereno"

SE meteo == "pioggia" ALLORA
   PRENDI_OMBRELLO()
ALTRIMENTI
   PRENDI_CAPPELLINO()
FINE SE

ESCI_DI_CASA()
SCRIVI "Buona giornata"

05 – Zaino intelligente (liste + loop)

Diagramma di flusso Mermaid

graph TD
    A[Inizio] --> B[Leggi orarioDelGiorno come elenco di materie]
    B --> C[Inizializza libriNecessari come lista vuota]
    C --> D[Imposta i = 0]
    D --> E[Calcola n uguale a numero di materie]
    E --> F{i minore di n?}

    F -- Si --> G[Prendi materia in posizione i]
    G --> H[Aggiungi materia a libriNecessari]
    H --> I[Incrementa i di 1]
    I --> F

    F -- No --> L[Stampa Metti nello zaino elenco libriNecessari]
    L --> Z[Fine]

Diagramma di flusso

Pseudocodice

LEGGI orarioDelGiorno   // lista, es: ["Mate","Storia","Inglese","Sistemi"]
IMPOSTA libriNecessari a lista vuota

PER ogni materia in orarioDelGiorno:
    AGGIUNGI materia a libriNecessari

SCRIVI "Metti nello zaino: " + libriNecessari

… e magari fate anche la versione per il quaderno e i materiali da portare con voi.

06 – Pomodoro di studio (ciclo + timer)

Visto che adotto questo metodo nella mia vita lavorativa, non potevo non propinare lo pseudocodice della tecnica del pomodoro.

Studiare a blocchi da 25’ con pause da 5’, per 4 cicli.

Diagramma di flusso Mermaid

graph TD
    A[Inizio] --> B[Imposta pomodoro = 1]
    B --> C{pomodoro <= 4} C -->|Si| D[Stampa Studia 25 minuti Pomodoro pomodoro]
    D --> E[Attendi 25 minuti]
    E --> F{pomodoro < 4} F -->|Si| G[Stampa Pausa 5 minuti]
    G --> H[Attendi 5 minuti]
    H --> J[Incrementa pomodoro di 1]
    F -->|No| I[Salta pausa]
    I --> J
    J --> C
    C -->|No| K[Stampa Sessione completata]
    K --> Z[Fine]

Diagramma di flusso

Pseudocodice

PER pomodoro da 1 a 4:
    SCRIVI "Studia 25 minuti (Pomodoro " + pomodoro + ")"
    ATTENDI 25 minuti
    SE (pomodoro < 4) ALLORA:
        SCRIVI "Pausa 5 minuti"
        ATTENDI 5 minuti
SCRIVI "Sessione completata!"

Per i miei studenti

Lista degli esercizi che dovrete fare come compito (vi dirò quando):

    1. Lavarsi i denti (tempo minimo per lavaggio 2 min).
    2. Merenda e soldi (se soldi maggiore di 2€ compro panino, altrimenti porto merenda da casa).
    3. Smartphone e batteria (se livello della batteria è inferiore al 20% ricaricare).
    4. Spegnere la luce uscendo di casa (tenere conto anche della chiusura con chiavi della porta di casa).
    5. Priorità compiti (ordinamento concettuale, ordinare le attività per scadenza e importanza).
    6. Vestiti in base al meteo (vestirsi in base al meteo (IF multiplo)).
    7. Abitudine acqua (promemoria ciclico, bere 1 bicchiere ogni ora tra le 9 e le 13).
    8. Media dei voti e situazione (input + aritmetica. Calcolare media e capire se sei sopra la soglia 6).

Seguiranno altri esercizi.

Nella prossima lezione vedremo come passare dallo pseudocodice ad uno sketch Arduino.

Buon pseudocodice a tutti 😉

Progettare bene, programmare meglio: diagrammi di flusso – cos’è il formato Mermaid? – Lezione 2/5

Ripasso di inizio anno – appunti per la classe.

In elettronica e automazione, un errore concettuale spesso costa più tempo di un errore di cablaggio. I diagrammi di flusso aiutano a scomporre il problema in passi elementari, chiarire condizioni e cicli, progettare la logica prima di scrivere il codice. Questo riduce la probabilità di “scrivere e sperare” e mette gli studenti nella condizione di ragionare per stati, condizioni e transizioni: esattamente ciò che serve per gestire sensori (LDR, potenziometri), attuatori (LED, buzzer) e sequenze temporizzate su Arduino.

In classe, partire dal diagramma rende trasparente il legame tra:

  • Analisi del problema > (diagramma);
  • Progettazione > (pseudocodice);
  • Implementazione > (sketch Arduino).

Questa filiera abitua a un metodo di lavoro replicabile, valutabile e condivisibile.

Che cos’è Mermaid

Mermaid è uno strumento open-source che trasforma descrizioni testuali (uno specifico linguaggio “simile al Markdown”) in diagrammi resi automaticamente nel browser. È scritto in JavaScript ed è pensato proprio per “diagrammare come si scrive”: poche righe leggibili, risultato grafico immediato.

Nato come progetto open-source nel 2014 per semplificare la creazione di diagrammi nelle documentazioni tecniche, Mermaid è sviluppato dalla comunità (MIT license) e supporta diversi tipi di diagramma: flowchart, sequence diagram, state diagram, Gantt, ER, class diagram e altri.

Dove funziona (integrazioni utili a scuola)

Mermaid è integrato o supportato nativamente in molte piattaforme usate anche in ambito didattico e progettuale (editor Markdown, wiki, ambienti di sviluppo, appunti digitali). Questo significa che studenti e docenti possono scrivere il diagramma nello stesso file in cui documentano, e vederlo renderizzato senza strumenti pesanti.

Un vantaggio pratico importante: GitHub permette di includere i diagrammi Mermaid direttamente dentro i file Markdown del repository. Per noi significa versionare codice e diagrammi nello stesso posto.

Perché Mermaid è più interessante rispetto ai tool grafici tradizionali

Molti software di disegno (Visio, draw.io, ecc.) producono file binari o complessi da confrontare e unire. Mermaid, invece, produce testo:

  • che viene integrato nella versione con Git insieme allo sketch (storia delle modifiche, differenze riga-per-riga, revisioni);
  • si integra nei flussi “docs-as-code”, cioè il trattare la versione e gli aggiornamenti della  documentazione di progetto come si fa per il codice (documentazione e progetto nello stesso repository);
  • è più veloce da modificare: cambiare una logica significa aggiornare due righe, non ridisegnare frecce e box;
  • è adatto all’automazione (generare diagrammi da script o dati).

Inoltre, per gli studenti è inclusivo: chi fatica con strumenti grafici complessi oppure non è particolarmente allenato nello scrivere codice, può concentrarsi sulla logica invece che sulla formattazione.

Tipi di diagrammi utili nel laboratorio di sistemi con Arduino

  • Flowchart (diagrammi di flusso): progettano il comportamento dello sketch (lettura sensore > confronto con soglia > azione). Perfetti per attività didattiche laboratoriali, come ad esempio con la gestione di: LDR, potenziometri, PWM su LED/buzzer.
  • State diagram (diagrammi di stati): modellano macchine a stati finiti, utili per sistemi reattivi (allarmi luminosi/acustici, sequenze a tempo e molto altro).
  • Sequence diagram: descrivono interazioni nel tempo (Utente > Arduino > Sensore >  Attuatore), utili per chiarire responsabilità e tempi (debounce, ritardi, feedback).
  • Gantt: pianificano attività di laboratorio (ricerca componenti, prototipazione, test, consegna), favorendo un’organizzazione realistica del progetto.
  • ER diagram: modellano dati (es. datalogger con tabelle misure, sensori), utile quando il progetto prevede salvataggi su SD/PC e successiva analisi.

Un flusso di lavoro consigliato (didattico e “versionabile”)

Di seguito trovate il flusso di lavoro che bisognerebbe adottare nello sviluppo di un sistema con Arduino e non solo, ovviamente è suscettibile di modifiche, ma percorrendo i 6 punti molto probabilmente il vostro progetto funzionerà, o come diceva un mio caro amico probabilmente “funzionicchierà” 🙂

  1. Definisci il comportamento atteso del sistema (requisiti minimi e soglie).
  2. Scrivi il flowchart in Mermaid (anche direttamente nel README del progetto).
  3. Aggiungi lo state diagram se il comportamento è meglio descritto per stati.
  4. Deriva lo pseudocodice riga-per-riga dal diagramma.
  5. Implementa lo sketch Arduino e committa insieme a diagrammi e note.
  6. Versiona su GitHub e usa pull request per rivedere sia codice che diagrammi (il diff testuale evidenzia le modifiche di logica).

Esempio pratico

Vediamo ora un esempio minimale pratico che conduce dal diagramma di flusso allo sketch

flowchart TD
A[Start] --> B[Leggi LDR A0]
B --> C{v < soglia?}
C -- Si --> D[LED ON]
C -- No  --> E[LED OFF]
D --> B
E --> B

Lettura della LDR, confronto a soglia, attivazione LED: lo schema diventa facilmente uno sketch con analogRead(), confronto, digitalWrite(). Questo ponte chiaro tra diagramma e codice rende la progettazione più rigorosa e la correzione più rapida.

Strumenti gratuiti per generare il diagramma di flusso

E’ possibile utilizzare diversi software gratuiti o semi-gratuiti che vi consentono di scrivere la descrizione del diagramma e lo traducono immediatamente in un grafico, vi segnalo due software

Mermaid Live Editor

Mermaid Live Editor (browser, nessuna installazione). Accedendo all’applicativo web scriverete sulla sinistra della pagina e se la descrizione del grafico è ben scritta e formatta, vedrete il diagramma a destra della pagina. Sarà possibile esporta in PNG/SVG. Ottimo per le prime esercitazioni.
Per la documentazione ufficiale di Mermaid Live Editor seguite il link.

Drawio

Un altro software credo già molto impiegato nella scuola è draw.io che può essere integrato all’intero degli applicativi Google come estensione oppure potete utilizzare direttamente collegandovi al sito di riferimento drawio.com.
Utilizzare l’applicativo è estremamente semplice e l’importazione di un grafico Mermaid potete farlo seguendo il percorso: Organizza > Inserisci > Mermaid… si aprirà un pannello in cui inserire il testo Mermaid.
L’uso di drawio facilita maggiormente l’editing, in quanto le modifiche avvengono su un editor grafico, pertanto l’orientamento delle frecce di collegamento tra i blocchi, spessori di linee, aggiunte di blocchi ed altro sono probabilmente più semplici, quindi probabilmente potrebbe essere utile insegnare a scrivere il testo Mermaid e poi rielaborarlo in drawio.

Nella prossima lezione vedremo come passare dal diagramma di flusso allo pseudocodice su problemi della vita comune.

Buona progettazione a tutti 🙂

Progettare bene, programmare meglio: diagrammi di flusso – Lezione 1/5

Ripasso di inizio anno – appunti per la classe.

Perché bisogna imparare a realizzare i diagrammi di flusso (anche se “programmiamo poco”)?

Quando progetti un programma per Arduino, il problema più grande non è scrivere le parentesi giuste: è decidere l’ordine delle azioni e quando prendere decisioni. Un diagramma di flusso è un disegno semplice che mostra i passi da compiere, le scelte “sì/no” e l’ordine in cui tutto accade. È usato in informatica da decenni proprio per rappresentare, passo-passo, il comportamento di un algoritmo o di un processo.

Un flowchart ti aiuta a vedere il programma prima di scriverlo: rettangoli per le azioni (es. “accendi LED”), rombi per le domande (es. “pulsante premuto?”), ovali per inizio/fine, parallelogrammi per ingresso/uscita di dati, frecce per la direzione. L’idea è sempre quella: dall’alto verso il basso, una freccia alla volta, fino all’uscita. Questa notazione è diventata uno standard di fatto e, nelle versioni “complete”, include molte altre forme utili (ne esistono decine); noi useremo solo quelle essenziali.

Dove si usano e perché ci interessano in laboratorio di sistemi

I diagrammi di flusso non servono solo a chi programma: si usano per documentare, spiegare e migliorare processi in tanti contesti (scuola, aziende, sanità, logistica). Nel nostro laboratorio li usiamo per tradurre un problema reale (una luce che si accende, un sensore che decide) in una sequenza chiara. Questo approccio è lo stesso che trovi nel project management: rappresentare un processo rende più facile pianificare, allineare il team e trovare i colli di bottiglia.

Esistono poi varianti “cugine” dei flowchart che potresti incontrare:

  • Workflow (flusso di lavoro), molto usato per capire chi fa cosa e quando;
  • Swimlane (corsie), utile quando più persone o sottosistemi collaborano;
  • Data Flow Diagram / DFD (flusso di dati), focalizzato su come circolano i dati tra parti di un sistema.

Noi partiamo dal flowchart di base (azioni/decisioni) perché è il ponte più diretto verso il codice Arduino

Buone pratiche “da prima riga di codice”

  • Definisci il problema in una frase (“Cosa voglio ottenere?”).
  • Elenca i passi e le decisioni (domande “sì/no”).
  • Disegna il flusso con poche forme standard (Inizio > Azioni > Decisioni > Fine).
  • Cerca le inefficienze: passaggi inutili, decisioni doppie, attese esagerate.
  • Condividi e rivedi: il diagramma è un documento vivo; aggiornatelo quando cambi idea.

Questa routine è identica a quella usata nei team professionali quando costruiscono o migliorano un processo.

Dalla carta al digitale (e al testo)

Puoi disegnare su carta, usare strumenti visuali come Lucidchart o Miro (trascini le forme e colleghi con frecce), oppure scrivere i diagrammi come testo con Mermaid (“diagram as code”), che si integra bene nei siti e nelle note tecniche. In questa lezione useremo Mermaid proprio per abituarci a ragionare prima in blocchi, poi in pseudocodice, poi in C/C++ per Arduino.

Mappa veloce “flowchart > Arduino”

Inizio / Setup > setup(): qui imposti i pin come INPUT/OUTPUT.
Azione → istruzioni come digitalWrite(), analogWrite(), tone().
Decisione (rombo) > if (...) { ... } else { ... }, spesso con letture da sensori: digitalRead(), analogRead().
Ciclo > loop() che ripete le azioni in sequenza.
Questa corrispondenza 1:1 rende naturale “tradurre” il disegno in codice, riducendo gli errori e il tempo di debug. (Rivedremo questa mappa in ogni esempio pratico.)

Cosa evitare all’inizio

  • Frecce che si incrociano: rendono il percorso confuso.
  • Domande ambigue: un rombo = una domanda con risposta sì/no chiara.
  • Simboli inventati: resta su 4–5 forme standard; andrai veloce e capirai tutto al volo.
  • Salti di logica: se ti perdi, torna ai passi del processo (definisci > elenca > disegna > verifica).

Un buon diagramma di flusso è come una ricetta: indica ingredienti (sensori/attuatori), passaggi (azioni), domande al cuoco (“la pasta è al dente?” > sì/no). Se la ricetta è chiara, il codice funziona e tutti in team capiscono cosa fare.

Nota per i lettori (studenti e non): nei paragrafi successivi troverai la pipeline completa che useremo sempre: Problema > Diagramma (Mermaid) > Pseudocodice > Sketch Arduino, con esempi concreti (LED, pulsante, LDR, buzzer). Questa struttura è pensata per classi che iniziano: potete seguirla anche se non hai mai scritto una riga di codice.

Simboli nei diagrammi di flusso: poche forme bastano

L’elenco delle forme può sembrare infinito, ma non serve conoscerle tutte. Ogni simbolo indica un tipo di passaggio preciso e ha un contesto d’uso ben definito. Quando disegni, se ti senti perso, torna all’essenziale: per la grande maggioranza dei diagrammi bastano davvero alcune forme base; le altre servono in casi specifici. Qui sotto trovi quelle più ricorrenti.

Forme comuni del flowchart

Simbolo del diagramma di flusso Nome Descrizione
Inizio/Fine Segna il punto di avvio o la conclusione del flusso; delimita i confini del processo.
Processo / Azione Indica un passo operativo: un’attività, una funzione o un’elaborazione che “fa qualcosa”.
Decisione Rappresenta una domanda binaria (sì/no, vero/falso) che dirama il percorso su esiti diversi.
Input/Output (Dati) Mostra un ingresso (dato in arrivo, misura, comando) o un’uscita(risultato, messaggio, documento).
Linea di flusso Definisce la direzione della sequenza tra le forme; chiarisce l’ordine dei passi.
Sottoprocesso / Processo predefinito Collega a una procedura già definita altrove o a un gruppo di azioni consolidate.
Connettore in pagina Unisce parti lontane dello stesso schema senza incrociare frecce; migliora la leggibilità.
Connettore fuori pagina Collega a un continua su un’altra pagina; spesso include un riferimento o un codice.
Documento Indica la produzione o l’uso di un documento (ordine, report, lettera, promemoria).
Documenti multipli Come sopra, ma per più documenti generati/gestiti nello stesso passaggio.
Input manuale L’utente digita o inserisce dati a mano (es. login, compilazione di un campo).
Operazione manuale Passo che richiede intervento umano (non automatizzato) per proseguire.
Database / Archivio dati Dati archiviati in modo strutturato e interrogabili (lettura/scrittura/filtri).
Memoria interna Dati conservati all’interno del sistema/dispositivo durante l’elaborazione.
Attesa / Ritardo Indica una pausa temporale o un ritardo prima del passo successivo.
Commento / Nota Aggiunge chiarimenti al lettore; si collega con linea tratteggiata alla parte pertinente.

Alcune varianti di forma e naming possono cambiare leggermente a seconda dello strumento o dello standard adottato; l’insieme di base rimane comunque coerente tra le principali piattaforme.

Nella prossima lezione vedremo quali tool utilizzare per disegnare diagrammi di flusso.

Buon Coding a tutti 🙂