# Arduino: da zero al progetto solido

Atlante · 16 lezioni · UNO R3 · 15 ottobre 2026

Percorso pratico verso competenze avanzate; non certificazione. Codice controllato con API simulate su host, non compilato AVR né provato su hardware.

## 01 · Il primo programma: dal PC al LED

Caricare un programma e riconoscere le sue due parti.

Uno sketch è il programma di Arduino. setup() viene eseguito una volta dopo accensione o reset; loop() viene richiamato continuamente. Le parentesi graffe delimitano un blocco, il punto e virgola chiude molte istruzioni. Il testo dopo // è un commento. Per cominciare usa soltanto il LED già sulla scheda: non serve costruire un circuito.

1. Su un PC Windows, macOS o Linux installa Arduino IDE 2 dalla pagina ufficiale. Usa un cavo USB che trasmetta anche dati.
2. Nel gestore schede installa Arduino AVR Boards; seleziona Arduino Uno e la porta della tua UNO R3. Conserva nel quaderno la versione del core.
3. Crea uno sketch, sostituisci il contenuto con il programma qui sotto e premi Verifica. Poi premi Carica e osserva il LED L.

**Collegamenti:** UNO R3 collegata al PC via USB; nessun filo esterno.

```cpp
#include <Arduino.h>
// Atlante: esempio originale per UNO R3.
// Verificare core, cablaggio e hardware prima dell’uso.
void setup() {
  pinMode(LED_BUILTIN, OUTPUT); // LED L: uscita
}
void loop() {
  digitalWrite(LED_BUILTIN, HIGH);
  delay(400); // millisecondi acceso
  digitalWrite(LED_BUILTIN, LOW);
  delay(800); // millisecondi spento
}
```

pinMode sceglie il ruolo del pin. digitalWrite imposta HIGH o LOW. delay ferma il normale avanzamento del programma: per questo primo esempio va bene; più avanti lo elimineremo.

**Esercizio:** Cambia 400 in 100 e 800 in 900. Prima prevedi il risultato, poi carica.

**Verifica:** Il LED resta acceso circa 0,1 s e spento circa 0,9 s. Sai distinguere Verifica (compilazione) da Carica (scrittura sulla scheda).

**Errori comuni:** Porta assente: controlla cavo dati e collegamento. Errore di compilazione: leggi il primo messaggio e la riga indicata. Upload fallito: verifica scheda e porta; non cambiare codice a caso.

Fonte: https://docs.arduino.cc/software/ide-v2/tutorials/getting-started/ide-v2-uploading-a-sketch/

## 02 · Variabili, costanti e LED esterno

Dare un nome ai pin e separare configurazione e comportamento.

Una costante descrive qualcosa che non deve cambiare durante il programma, come il numero di un pin. Una variabile conserva un valore che può cambiare. byte è utile per piccoli numeri non negativi; bool contiene true o false. Scegli nomi che spieghino il compito: ledSegnale è più chiaro di x. Una breadboard collega alcuni fori al suo interno: controlla i gruppi di contatti, non affidarti alla sola vicinanza.

1. Scollega USB prima di spostare i fili. Inserisci LED e resistenza in serie.
2. Collega il pin D9 alla resistenza, poi all’anodo del LED. Collega il catodo a GND.
3. Carica lo sketch e modifica soltanto intervalloMs.

**Collegamenti:** D9 → resistenza 330 Ω → anodo LED rosso; catodo → GND. Un LED rosso con caduta indicativa 2 V assorbe circa (5−2)/330 = 9 mA. La caduta reale dipende dal componente.

```cpp
#include <Arduino.h>
// Atlante: esempio originale per UNO R3.
// Verificare core, cablaggio e hardware prima dell’uso.
const byte ledSegnale = 9;
const unsigned long intervalloMs = 500;
bool acceso = false;
void setup() { pinMode(ledSegnale, OUTPUT); }
void loop() {
  acceso = !acceso; // inverte true e false
  digitalWrite(ledSegnale, acceso ? HIGH : LOW);
  delay(intervalloMs);
}
```

const protegge il nome da assegnazioni successive. ! inverte un valore logico. L’espressione condizione ? valore1 : valore2 sceglie il valore da scrivere.

**Esercizio:** Rinomina ledSegnale in luceBanco in ogni punto. Imposta 250 ms.

**Verifica:** La compilazione riesce; il periodo completo è 500 ms, non 250 ms.

**Errori comuni:** LED spento: controlla polarità, resistenza e GND. Non collegare il LED direttamente fra un pin e GND. Due terminali nella stessa fila collegata possono cortocircuitare il componente.

Fonte: https://docs.arduino.cc/built-in-examples/basics/Blink/

## 03 · Pulsante: ingresso e decisioni

Leggere un ingresso e comandare un’uscita con if.

Con INPUT_PULLUP il pin ha uno stato definito quando il pulsante è aperto. Premendo, il collegamento a GND porta la lettura a LOW. La variabile premuto traduce questo livello elettrico in un significato: true vuol dire premuto. In C++, = assegna un valore; == confronta due valori. if esegue un blocco quando la condizione è vera.

1. Collega un contatto del pulsante a D2 e l’altro a GND. Per pulsanti a quattro piedini identifica prima i contatti già uniti.
2. Carica il codice. Premi e rilascia: il LED integrato segue il contatto.
3. Nel simulatore aggiungi un pulsante e un LED, poi osserva i nomi delle variabili nel codice generato.

**Collegamenti:** D2 → pulsante → GND; LED integrato. Nessuna resistenza esterna di pull-up in questo esempio.

```cpp
#include <Arduino.h>
// Atlante: esempio originale per UNO R3.
// Verificare core, cablaggio e hardware prima dell’uso.
const byte pulsante = 2;
void setup() {
  pinMode(pulsante, INPUT_PULLUP);
  pinMode(LED_BUILTIN, OUTPUT);
}
void loop() {
  bool premuto = (digitalRead(pulsante) == LOW);
  if (premuto) digitalWrite(LED_BUILTIN, HIGH);
  else digitalWrite(LED_BUILTIN, LOW);
}
```

Il confronto == LOW produce un bool. Il programma legge e aggiorna continuamente: non conserva l’accensione dopo il rilascio.

**Esercizio:** Inverti il comportamento: LED acceso soltanto con pulsante rilasciato.

**Verifica:** Premuto: LED spento; rilasciato: LED acceso. Sai spiegare perché LOW può significare true.

**Errori comuni:** Ingresso casuale: controlla INPUT_PULLUP e massa. Il rimbalzo meccanico diventa importante quando conti pressioni o cambi stato: verrà gestito nella lezione 8.

Fonte: https://docs.arduino.cc/built-in-examples/digital/InputPullupSerial/

## 04 · Leggere un valore analogico

Osservare misure nel monitor seriale e distinguere numero e unità.

analogRead su UNO R3 restituisce un conteggio a 10 bit, da 0 a 1023. Non è automaticamente una temperatura o una tensione precisa. Per trasformarlo in una grandezza servono riferimento, scala e caratteristiche del sensore. Inizia con un potenziometro da 10 kΩ: il cursore fornisce una tensione regolabile. Serial invia informazioni al PC; monitor e programma devono usare la stessa velocità.

1. Collega i due terminali esterni del potenziometro a 5 V e GND; il cursore centrale va ad A0.
2. Carica e apri Monitor seriale a 115200 baud.
3. Ruota lentamente e annota minimo, centro e massimo.

**Collegamenti:** Potenziometro 10 kΩ: estremi a 5 V/GND, cursore ad A0. Valori riferiti a UNO R3; non trasferire 5 V a una scheda a 3,3 V.

```cpp
#include <Arduino.h>
// Atlante: esempio originale per UNO R3.
// Verificare core, cablaggio e hardware prima dell’uso.
void setup() { Serial.begin(115200); }
void loop() {
  int conteggio = analogRead(A0);
  Serial.print("ADC=");
  Serial.println(conteggio);
  delay(100);
}
```

int contiene il conteggio. print continua sulla stessa riga; println aggiunge un fine riga. Il ritardo rende leggibile l’uscita seriale.

**Esercizio:** Aggiungi una variabile bool sopraSoglia = conteggio >= 600 e stampala dopo il conteggio.

**Verifica:** Intorno a metà corsa il valore è vicino a 512, con tolleranze. Non chiamare la lettura “gradi” senza una conversione verificata.

**Errori comuni:** Valori che saltano: controlla cursore e GND. Testo incomprensibile: controlla i baud. Non superare i limiti elettrici dell’ingresso.

Fonte: https://docs.arduino.cc/built-in-examples/basics/AnalogReadSerial/

## 05 · PWM: regolare la luminosità

Trasformare una lettura in un comando di uscita.

PWM alterna velocemente acceso e spento. Cambia il rapporto fra tempo acceso e periodo, detto duty cycle. Su UNO R3 analogWrite usa normalmente valori da 0 a 255 sui pin PWM: non è un’uscita analogica continua. Qui usiamo D9 e convertiamo il conteggio 0–1023 in 0–255. Non alimentare motori o carichi di potenza direttamente da un pin.

1. Mantieni il potenziometro su A0. Aggiungi il LED esterno con resistenza come nella lezione 2.
2. Carica il codice; ruota il potenziometro e osserva la luce.
3. Confronta valori minimi, centrali e massimi. La percezione della luminosità non è lineare.

**Collegamenti:** Potenziometro su A0; D9 → 330 Ω → LED rosso → GND.

```cpp
#include <Arduino.h>
// Atlante: esempio originale per UNO R3.
// Verificare core, cablaggio e hardware prima dell’uso.
const byte ledPwm = 9;
void setup() { pinMode(ledPwm, OUTPUT); }
void loop() {
  int lettura = analogRead(A0);
  int comando = lettura / 4; // 0..1023 diventa 0..255
  analogWrite(ledPwm, comando);
}
```

La divisione intera scarta la parte frazionaria. analogWrite mantiene il PWM mentre loop continua. D9 è una scelta specifica per UNO R3.

**Esercizio:** Limita il comando massimo a 128. Confronta il risultato con 255.

**Verifica:** Zero spegne; 255 imposta il massimo. Sai distinguere conteggio ADC, comando PWM e tensione misurata.

**Errori comuni:** Un pin non PWM non offre la stessa regolazione. Se aggiungi librerie che usano timer, verifica eventuali conflitti con PWM.

Fonte: https://support.arduino.cc/hc/en-us/articles/9350537961500-Use-PWM-output-with-Arduino

## 06 · Funzioni, cicli e array

Ridurre le ripetizioni senza perdere chiarezza.

Una funzione raccoglie un compito. Un parametro è un valore che le passi; return restituisce il risultato. Un array conserva più elementi dello stesso tipo. Gli indici partono da zero: per tre elementi sono 0, 1 e 2. Un ciclo for è comodo per elaborare una piccola quantità di dati; non deve però bloccare per molto tempo il resto del programma.

1. Usa solo la scheda USB. Leggi la funzione media prima di setup.
2. Prevedi il valore calcolato dai tre numeri nell’array.
3. Apri il monitor a 115200 e confronta previsione e risultato.

**Collegamenti:** Nessun componente esterno: esempio di organizzazione C++.

```cpp
#include <Arduino.h>
// Atlante: esempio originale per UNO R3.
// Verificare core, cablaggio e hardware prima dell’uso.
int media(const int valori[], byte quanti) {
  if (quanti == 0) return 0;
  long somma = 0;
  for (byte i = 0; i < quanti; i++) somma += valori[i];
  return somma / quanti;
}
void setup() {
  Serial.begin(115200);
  const int campioni[] = {100, 200, 300};
  Serial.println(media(campioni, 3));
}
void loop() {}
```

const impedisce alla funzione di modificare i valori ricevuti. long rende la somma più ampia di int su UNO R3. La dimensione passata deve corrispondere agli elementi disponibili.

**Esercizio:** Sostituisci i campioni con 0, 512 e 1023. Spiega l’arrotondamento.

**Verifica:** Il primo risultato è 200; il secondo è 511 per divisione intera. Non accedi mai all’indice 3 di un array da tre elementi.

**Errori comuni:** Dimensioni errate possono leggere memoria estranea senza un errore evidente. Non usare <= quanti nel ciclo.

Fonte: https://docs.arduino.cc/language-reference/

## 07 · Fare due cose insieme con millis

Eliminare le attese bloccanti dal ciclo principale.

Non serve un secondo processore per alternare attività brevi. loop legge un pulsante continuamente e controlla se è passato abbastanza tempo per cambiare il LED. millis fornisce un contatore di millisecondi. Su UNO R3 si riavvolge dopo circa 49,7 giorni: il confronto mediante sottrazione unsigned gestisce il passaggio, purché il controllo sia eseguito regolarmente e l’intervallo sia appropriato.

1. Collega il pulsante D2–GND.
2. Carica: premendo il pulsante il lampeggio diventa più rapido.
3. Cerca nel codice tutte le chiamate a delay: non ce ne sono.

**Collegamenti:** D2 → pulsante → GND; LED integrato.

```cpp
#include <Arduino.h>
// Atlante: esempio originale per UNO R3.
// Verificare core, cablaggio e hardware prima dell’uso.
const byte pulsante = 2;
unsigned long ultimo = 0;
bool acceso = false;
void setup() {
  pinMode(pulsante, INPUT_PULLUP);
  pinMode(LED_BUILTIN, OUTPUT);
}
void loop() {
  unsigned long ora = millis();
  unsigned long periodo = digitalRead(pulsante) == LOW ? 120UL : 700UL;
  if (ora - ultimo >= periodo) {
    ultimo = ora;
    acceso = !acceso;
    digitalWrite(LED_BUILTIN, acceso ? HIGH : LOW);
  }
}
```

ultimo conserva quando è avvenuto l’ultimo cambio. UL indica una costante unsigned long. Ogni passaggio di loop resta breve; questo non è parallelismo hardware.

**Esercizio:** Prevedi quanto impiega il LED a reagire al cambio di periodo. Aggiungi una stampa ogni secondo con un secondo timestamp.

**Verifica:** Il pulsante influenza il ritmo senza attendere un delay. Sai spiegare perché ora >= ultimo + periodo è meno robusto al riavvolgimento.

**Errori comuni:** Non usare int per millis. Una stampa seriale eccessiva o una libreria bloccante possono comunque rallentare loop.

Fonte: https://docs.arduino.cc/built-in-examples/digital/BlinkWithoutDelay/

## 08 · Una pressione, un evento: antirimbalzo

Cambiare stato una sola volta per pressione.

Un pulsante reale può aprire e chiudere il contatto più volte in pochi millisecondi. Il programma mantiene una lettura grezza e uno stato stabile: accetta la nuova lettura solo dopo 30 ms senza variazioni. Il cambio del LED avviene sul fronte che porta lo stato stabile a premuto, non mentre il pulsante rimane tenuto.

1. Riutilizza D2 e il LED integrato.
2. Premi lentamente dieci volte: ogni pressione deve invertire il LED una sola volta.
3. Tieni il pulsante premuto due secondi; il LED non deve continuare a cambiare.

**Collegamenti:** D2 → pulsante → GND con INPUT_PULLUP.

```cpp
#include <Arduino.h>
// Atlante: esempio originale per UNO R3.
// Verificare core, cablaggio e hardware prima dell’uso.
const byte pulsante = 2;
bool grezzo = HIGH, stabile = HIGH, acceso = false;
unsigned long cambiato = 0;
void setup() {
  pinMode(pulsante, INPUT_PULLUP);
  pinMode(LED_BUILTIN, OUTPUT);
}
void loop() {
  unsigned long ora = millis();
  bool lettura = digitalRead(pulsante);
  if (lettura != grezzo) { grezzo = lettura; cambiato = ora; }
  if (ora - cambiato >= 30 && stabile != grezzo) {
    stabile = grezzo;
    if (stabile == LOW) acceso = !acceso;
  }
  digitalWrite(LED_BUILTIN, acceso ? HIGH : LOW);
}
```

!= significa diverso. cambiato viene aggiornato a ogni variazione grezza, facendo ripartire il tempo di stabilizzazione.

**Esercizio:** Confronta 5, 30 e 100 ms. Registra conteggi errati e ritardo percepito; non assumere che lo stesso valore vada bene per ogni interruttore.

**Verifica:** Una pressione mantenuta genera un evento. Una sequenza di rimbalzi più breve di 30 ms non viene accettata come pressioni multiple.

**Errori comuni:** Contare ogni LOW dentro loop produce migliaia di eventi. L’antirimbalzo software non risolve cablaggi errati o disturbi elettrici fuori specifica.

Fonte: https://docs.arduino.cc/built-in-examples/digital/Debounce/

## 09 · Sensori: filtro, isteresi e calibrazione

Evitare che un’uscita oscilli vicino a una soglia.

Un filtro riduce le variazioni rapide ma introduce ritardo. L’isteresi usa due soglie: si accende sopra 650 e si spegne sotto 550; nella fascia intermedia conserva lo stato. Sono compiti diversi. La calibrazione richiede un riferimento noto e più punti: un valore ADC non diventa una misura affidabile soltanto perché è stato mediato.

1. Collega il potenziometro ad A0.
2. Apri Monitor seriale a 115200; osserva valore grezzo, filtrato e stato.
3. Muovi attorno a 600, poi oltre 650 e sotto 550.

**Collegamenti:** Potenziometro 10 kΩ su A0; LED integrato.

```cpp
#include <Arduino.h>
// Atlante: esempio originale per UNO R3.
// Verificare core, cablaggio e hardware prima dell’uso.
float filtrato = 0;
bool acceso = false;
unsigned long ultimo = 0;
void setup() {
  pinMode(LED_BUILTIN, OUTPUT);
  Serial.begin(115200);
  filtrato = analogRead(A0);
}
void loop() {
  unsigned long ora = millis();
  if (ora - ultimo < 100) return;
  ultimo = ora;
  int grezzo = analogRead(A0);
  filtrato += 0.2f * (grezzo - filtrato);
  if (filtrato >= 650) acceso = true;
  else if (filtrato <= 550) acceso = false;
  digitalWrite(LED_BUILTIN, acceso ? HIGH : LOW);
  Serial.print(grezzo); Serial.print(',');
  Serial.print(filtrato); Serial.print(','); Serial.println(acceso);
}
```

Il nuovo valore si avvicina del 20% alla lettura a ogni campione. return interrompe questa chiamata di loop, non ferma Arduino.

**Esercizio:** Confronta coefficiente 0,2 e 0,5 con lo stesso gradino del potenziometro. Registra il tempo prima del cambio di stato.

**Verifica:** Fra 550 e 650 lo stato dipende dalla storia precedente. Il filtro non elimina la necessità di verificare unità e sensore.

**Errori comuni:** Soglie uguali annullano l’isteresi. Una misura piatta può indicare un collegamento interrotto: non considerarla automaticamente valida.

Fonte: https://docs.arduino.cc/built-in-examples/analog/Smoothing/

## 10 · Comandi seriali e gestione degli errori

Definire un piccolo protocollo controllabile e non bloccante.

Un protocollo chiarisce i comandi accettati e le risposte. Questo esempio accetta un carattere alla volta: 1 accende, 0 spegne, ? legge lo stato. Non serve attendere un’intera frase o accumulare testo senza limite. I terminatori di riga vengono ignorati. Ogni altro carattere produce un errore esplicito; l’uscita mantiene il suo stato.

1. Collega solo USB e apri Monitor seriale a 115200.
2. Invia 1, ?, 0 e infine X.
3. Controlla che un comando sconosciuto non cambi il LED.

**Collegamenti:** Solo USB e LED integrato; UART via convertitore USB della UNO R3.

```cpp
#include <Arduino.h>
// Atlante: esempio originale per UNO R3.
// Verificare core, cablaggio e hardware prima dell’uso.
bool acceso = false;
void setup() {
  Serial.begin(115200);
  pinMode(LED_BUILTIN, OUTPUT);
}
void loop() {
  if (Serial.available() <= 0) return;
  char comando = Serial.read();
  if (comando == '\r' || comando == '\n') return;
  if (comando == '1') acceso = true;
  else if (comando == '0') acceso = false;
  else if (comando != '?') { Serial.println("ERR comando"); return; }
  digitalWrite(LED_BUILTIN, acceso ? HIGH : LOW);
  Serial.println(acceso ? "ON" : "OFF");
}
```

Le virgolette singole indicano un carattere; quelle doppie una stringa. available controlla i dati già presenti: loop non aspetta una risposta.

**Esercizio:** Scrivi una tabella richiesta/risposta. Prova righe vuote, sequenze 10? e caratteri non previsti.

**Verifica:** 1? risponde ON due volte; X risponde ERR comando e non cambia lo stato. Il formato è documentato prima di collegare un altro programma.

**Errori comuni:** Inviare parole intere a questo protocollo genera più comandi o errori: non è un parser di frasi. Per messaggi lunghi usa buffer limitati, scadenze e validazione.

Fonte: https://docs.arduino.cc/language-reference/

## 11 · I²C: trovare un dispositivo e usare una libreria

Separare collegamento elettrico, indirizzo e interpretazione dei dati.

I²C usa SDA e SCL con indirizzi. Su UNO R3 SDA corrisponde ad A4 e SCL ad A5. Uno scanner può rilevare una risposta ma non identifica con certezza modello o significato dei registri. Per un sensore serve la libreria corretta per la variante e un esempio del produttore. Pull-up e livelli devono essere compatibili: un chip a 3,3 V non è automaticamente compatibile con il bus a 5 V.

1. Prima prova senza sensori: devono comparire zero risposte.
2. Scegli un breakout esplicitamente compatibile con UNO R3 e controlla alimentazione e pull-up nel suo manuale. Scollega USB durante il montaggio.
3. Collega SDA, SCL e GND; alimenta come da manuale. Poi rileva l’indirizzo e confrontalo con quello documentato.

**Collegamenti:** UNO R3: A4/SDA e A5/SCL; GND comune. Alimentazione e adattamento dei livelli dipendono dal breakout scelto.

```cpp
#include <Arduino.h>
// Atlante: esempio originale per UNO R3.
// Verificare core, cablaggio e hardware prima dell’uso.
#include <Wire.h>
void setup() {
  Serial.begin(115200);
  Wire.begin();
  Wire.setWireTimeout(25000, true); // core AVR con timeout Wire
  byte trovati = 0;
  for (byte indirizzo = 8; indirizzo < 120; indirizzo++) {
    Wire.beginTransmission(indirizzo);
    byte esito = Wire.endTransmission();
    if (esito == 0) {
      Serial.print("Risposta 0x"); Serial.println(indirizzo, HEX);
      trovati++;
    }
    if (Wire.getWireTimeoutFlag()) {
      Serial.println("Timeout bus: controllare i collegamenti");
      Wire.clearWireTimeoutFlag();
      break;
    }
  }
  Serial.print("Totale: "); Serial.println(trovati);
}
void loop() {}
```

La scansione avviene una volta in setup. endTransmission restituisce un codice: zero indica un ACK. Le API di timeout sono specifiche del core: controlla che la tua versione le supporti.

**Esercizio:** Annota indirizzo, codice esito, modello e versione libreria. Aggiungi una lettura solo dopo aver consultato l’esempio ufficiale del sensore.

**Verifica:** Lo scanner senza dispositivi stampa Totale: 0. Un ACK non basta a dichiarare che temperatura o pressione siano corrette.

**Errori comuni:** Due sensori con lo stesso indirizzo possono entrare in conflitto. Un bus bloccato o senza pull-up richiede verifica del cablaggio; ripetere all’infinito non è recupero degli errori.

Fonte: https://docs.arduino.cc/learn/communication/wire/

## 12 · Interrupt e dati condivisi

Contare eventi brevi mantenendo la routine di interrupt minima.

Un interrupt richiama una funzione quando accade un evento. Su UNO R3 D2 e D3 supportano gli interrupt esterni tramite digitalPinToInterrupt. La routine deve durare poco: aggiorna un contatore e torna. volatile indica che il valore può cambiare fuori dal flusso normale, ma non rende atomica una lettura a più byte su un processore a 8 bit.

1. Usa un generatore di impulsi compatibile 0–5 V su D2 con GND comune; non collegare tensioni negative o superiori ai limiti.
2. In alternativa simula impulsi software nei test: un pulsante non filtrato produce conteggi da rimbalzo.
3. Osserva il conteggio a intervalli di un secondo sul monitor.

**Collegamenti:** D2 ingresso impulsi; GND comune. Nessun carico controllato.

```cpp
#include <Arduino.h>
// Atlante: esempio originale per UNO R3.
// Verificare core, cablaggio e hardware prima dell’uso.
volatile unsigned long impulsi = 0;
unsigned long ultimo = 0;
void contaImpulso() { impulsi++; }
void setup() {
  Serial.begin(115200);
  pinMode(2, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(2), contaImpulso, FALLING);
}
void loop() {
  unsigned long ora = millis();
  if (ora - ultimo < 1000) return;
  ultimo = ora;
  noInterrupts();
  unsigned long copia = impulsi;
  interrupts();
  Serial.println(copia);
}
```

La sezione critica copia il contatore in poche istruzioni. La stampa avviene dopo aver riabilitato gli interrupt. Questo schema si usa qui nel normale loop, con interrupt inizialmente abilitati.

**Esercizio:** Fornisci dieci impulsi puliti e verifica l’incremento. Documenta la frequenza provata, senza estendere il risultato a frequenze mai misurate.

**Verifica:** La routine non contiene delay o Serial. Sai spiegare la differenza fra volatile e accesso atomico.

**Errori comuni:** Un contatto meccanico non filtrato non genera un solo impulso per pressione. Disabilitare gli interrupt troppo a lungo può perdere eventi e interferire con altre funzioni.

Fonte: https://github.com/arduino/reference-en/blob/master/Language/Functions/External%20Interrupts/attachInterrupt.adoc

## 13 · Progetto completo: monitor con stati

Integrare ingresso, soglie, stato iniziale e ripristino manuale.

Una macchina a stati assegna significato alle situazioni. Questo monitor didattico parte disarmato. Il pulsante deve essere rilasciato, poi premuto stabilmente per armare. Una lettura almeno 700 porta in allarme; l’allarme resta memorizzato. Una pressione, con lettura non superiore a 600, riconosce l’allarme e torna disarmato. Il LED lampeggia quando armato e resta acceso in allarme. Non è un sistema di protezione.

1. Monta potenziometro A0 e pulsante D2–GND. Usa il LED integrato.
2. Esegui le prove in ordine: avvio, rilascio/pressione, superamento soglia, diminuzione della lettura, riconoscimento.
3. Prova anche a tenere premuto il pulsante mentre riavvii: non deve armarsi da solo.

**Collegamenti:** Potenziometro 10 kΩ: 5 V/GND e cursore A0. Pulsante D2–GND. Uscita LED integrato.

```cpp
#include <Arduino.h>
// Atlante: esempio originale per UNO R3.
// Verificare core, cablaggio e hardware prima dell’uso.
enum Stato { DISARMATO, ARMATO, ALLARME };
Stato stato = DISARMATO;
bool grezzo = HIGH, stabile = HIGH, rilascioVisto = false;
unsigned long cambiato = 0;
void setup() {
  pinMode(2, INPUT_PULLUP);
  pinMode(LED_BUILTIN, OUTPUT);
  digitalWrite(LED_BUILTIN, LOW);
}
void loop() {
  unsigned long ora = millis();
  bool letturaPulsante = digitalRead(2);
  bool pressione = false;
  if (letturaPulsante != grezzo) { grezzo = letturaPulsante; cambiato = ora; }
  if (ora - cambiato >= 30) {
    if (grezzo == HIGH) rilascioVisto = true;
    if (stabile != grezzo) {
      stabile = grezzo;
      pressione = (stabile == LOW && rilascioVisto);
    }
  }
  int misura = analogRead(A0);
  switch (stato) {
    case DISARMATO: if (pressione) stato = ARMATO; break;
    case ARMATO: if (misura >= 700) stato = ALLARME; break;
    case ALLARME: if (pressione && misura <= 600) stato = DISARMATO; break;
  }
  bool led = stato == ALLARME || (stato == ARMATO && (ora / 300) % 2 == 0);
  digitalWrite(LED_BUILTIN, led ? HIGH : LOW);
}
```

enum assegna nomi agli stati. switch rende esplicite le transizioni consentite. Nessun comando deve avere effetti non descritti dalla tabella di stato.

**Esercizio:** Disegna la tabella stato/evento/stato successivo. Verifica 699, 700, 601 e 600 conteggi. Registra il comportamento anche dopo reset.

**Verifica:** La lettura bassa da sola non cancella l’allarme. Il pulsante mantenuto al riavvio non arma; dopo rilascio e nuova pressione può armare.

**Errori comuni:** Il progetto non rileva affidabilmente il distacco di un sensore analogico: una futura funzione diagnostica richiede hardware e criteri specifici. Non usare per comandare impianti o protezioni.

Fonte: https://docs.arduino.cc/language-reference/

## 14 · Test automatici, memoria e struttura del progetto

Dimostrare cosa funziona e conoscere i limiti della verifica.

Prima definisci i requisiti osservabili, poi separa la logica pura dall’hardware. La funzione decide non legge pin: riceve dati e restituisce una scelta. È più facile provarla con valori di confine. Un test che stampa OK non prova alimentazione, cablaggio o comportamento temporale. Su UNO R3 la memoria è limitata: controlla il rapporto di compilazione e evita allocazioni dinamiche ripetute in applicazioni lunghe.

1. Compila ed esegui lo sketch di test: il monitor deve riportare OK.
2. Cambia volontariamente >= in > e verifica che venga segnalato KO. Poi correggi.
3. Nel progetto finale separa configurazione pin, acquisizione, logica e uscita in funzioni; conserva una versione funzionante prima di modificare.

**Collegamenti:** Solo scheda USB; test della logica, non del sensore.

```cpp
#include <Arduino.h>
// Atlante: esempio originale per UNO R3.
// Verificare core, cablaggio e hardware prima dell’uso.
bool decide(bool precedente, int valore) {
  if (valore >= 650) return true;
  if (valore <= 550) return false;
  return precedente;
}
void setup() {
  Serial.begin(115200);
  bool ok = !decide(false, 550) && decide(false, 650)
    && decide(true, 600) && !decide(false, 600);
  Serial.println(ok ? "OK" : "KO");
}
void loop() {}
```

I quattro casi verificano soglia inferiore, superiore e memoria nella fascia intermedia. Il test di mutazione volontaria controlla che la prova sia capace di trovare un errore.

**Esercizio:** Aggiungi casi 0, 549, 551, 649, 651 e 1023. Esporta tabella con ingresso, stato precedente, atteso e osservato.

**Verifica:** Il difetto introdotto deve far fallire almeno una prova. Sai distinguere test logici, compilazione per la scheda e test hardware.

**Errori comuni:** Non chiamare “validato” un progetto perché compila. La memoria libera stimata non dimostra assenza di errori nello stack o negli accessi agli array.

Fonte: https://docs.arduino.cc/learn/programming/memory-guide/

## 15 · Bus, librerie e portabilità: il passo successivo

Portare un progetto su un altro dispositivo senza ipotesi nascoste.

UART, I²C e SPI risolvono esigenze diverse. UART scambia flussi di byte; I²C indirizza periferiche su due segnali; SPI usa clock, dati e selezione del dispositivo. Il protocollo non garantisce compatibilità di tensione. Una libreria nasconde registri e sequenze, ma va scelta per chip e scheda esatti. Il porting da UNO R3 a ESP32 o UNO R4 richiede verifiche: numerazione pin, tensioni, ADC, PWM, timer, dimensioni dei tipi e API possono cambiare.

1. Scegli un solo modulo con datasheet, scheda breakout identificabile e libreria mantenuta. Registra versione, dipendenze e licenza.
2. Compila prima l’esempio minimo del produttore per la scheda esatta. Controlla errori di inizializzazione e assenza del modulo.
3. Integra una funzione alla volta nel progetto. Misura durata delle chiamate e comportamento quando il bus non risponde.

**Collegamenti:** Cablaggio solo dal datasheet della variante scelta. Nessun esempio universale di collegamento valido per tutti i moduli.

Per un driver robusto definisci almeno begin, acquisisci e statoErrore. Non riavviare indefinitamente senza una scadenza e un messaggio diagnostico.

**Esercizio:** Prepara una matrice: scheda, core, libreria, pin, alimentazione, esito compilazione, esito hardware. Lascia “non provato” dove manca una misura.

**Verifica:** Un’altra persona riesce a riprodurre la configurazione senza indovinare il modello del sensore. I moduli non provati restano dichiarati tali.

**Errori comuni:** Non scambiare pin con etichetta simile per equivalenti. Wi-Fi e aggiornamenti remoti richiedono gestione credenziali, autenticazione, errori di rete e aggiornamenti verificabili.

Fonte: https://docs.arduino.cc/learn/communication/spi/

## 16 · Consegna professionale: progetto riproducibile

Trasformare il prototipo in una consegna verificabile.

Un progetto professionale comprende requisiti, codice, schema elettrico, distinta materiali, versioni, piano di prova e limiti. Il fatto che un prototipo funzioni una volta non ne dimostra affidabilità. Definisci comportamento all’avvio, perdita alimentazione, ingresso fuori intervallo, comunicazione assente e ripristino. La breadboard è utile per imparare ma non equivale a un assemblaggio qualificato per esercizio continuo.

1. Usa il monitor della lezione 13 come progetto finale. Scrivi cinque requisiti misurabili e una tabella delle transizioni.
2. Archivia sketch, schema e distinta con revisione. Registra scheda, core, IDE e strumenti di misura. Conserva il progetto in Git o in copie versionate.
3. Esegui il piano di prova con risultati attesi/osservati. Usa il quaderno Academy per relazione e dati; documenta anche gli esiti negativi.
4. Per impiego reale fai valutare alimentazione, driver, protezioni, EMC, ambiente e requisiti applicabili da competenze adeguate al prodotto.

**Collegamenti:** Il percorso usa solo USB e circuiti didattici a bassa tensione. Motori, relè e potenza richiedono driver e verifiche specifiche.

La competenza professionale si dimostra con progetti e prove. La percentuale del corso indica soltanto le tappe che hai segnato come completate; non è una certificazione.

**Esercizio:** Consegna a un’altra persona il progetto completo. Chiedile di riprodurre configurazione, caricamento e prove senza spiegazioni aggiuntive; annota ciò che manca.

**Verifica:** Consegna minima: requisiti, codice versionato, schema, distinta, istruzioni di compilazione, tabella prove, risultati, limiti e procedura di ripristino. Nessun campo critico lasciato implicito.

**Errori comuni:** Una libreria aggiornata può cambiare il comportamento: ripeti i test coinvolti. Non pubblicare chiavi, password o dati personali nel repository.

Fonte: https://docs.arduino.cc/programming/

Foto, illustrazioni e video nella versione web: https://atlante-ai-federico.decent-mole-8597.chatgpt.site/arduino/course
