Progetto #138 • Debug e diagnostica

Sistema di debug Arduino con LED e display OLED

Crea una diagnostica autonoma con tre livelli di stato, codici di errore, DHT22, fotoresistenza e due schermate OLED.

Difficoltà★★★☆☆ Intermedio
Tempo60–90 min
ConcettiDebug • OLED • Stati

🚀 Introduzione

Quando un progetto Arduino diventa più complesso, capire cosa non funziona collegandolo ogni volta al computer può diventare scomodo. In questo progetto realizzerai un vero sistema di diagnostica locale: tre LED comunicano immediatamente lo stato generale, mentre un display OLED mostra valori, stato del sensore e codice dell’eventuale problema.

🟢 OK
Sistema nei limiti.
🟡 Attenzione
Un parametro si avvicina a una soglia critica.
🔴 Errore
Sensore non valido o soglia critica superata.
🎯 Cosa imparerai
  • creare livelli di stato con enum;
  • assegnare priorità agli errori;
  • usare LED come indicatori diagnostici;
  • mostrare codici di debug su OLED;
  • controllare DHT22 e LDR;
  • gestire due schermate con un pulsante;
  • realizzare un test automatico all’avvio;
  • aggiornare il sistema tramite millis().

🧰 Materiale necessario

1× Arduino UNO
1× OLED 0,96″ I2C SSD1306
1× sensore DHT22
1× fotoresistenza LDR
3× LED: verde, giallo, rosso
3× resistenze 220 Ω
2× resistenze 10 kΩ*
1× pulsante
Breadboard + jumper
Cavo USB

* Una da 10 kΩ è usata nel partitore della LDR; l’altra serve come pull-up se il DHT22 non è montato su un modulo che la integra.

🛒 Non hai ancora i componenti?

Un kit Arduino per principianti contiene molti dei componenti utilizzati in questo e negli altri progetti.

Kit Arduino consigliato →Link di affiliazione Amazon: in qualità di Affiliato Amazon ricevo un guadagno dagli acquisti idonei, senza alcun costo aggiuntivo per te.

📘 Vuoi imparare Arduino passo dopo passo?

Nei miei libri trovi spiegazioni, schemi e progetti pratici pensati anche per chi parte da zero.

Scopri i miei libri →Link di affiliazione Amazon: in qualità di Affiliato Amazon ricevo un guadagno dagli acquisti idonei, senza alcun costo aggiuntivo per te.

📚 Librerie necessarie

Adafruit SSD1306
Gestione del display OLED.
Adafruit GFX Library
Funzioni grafiche e testo.
DHT sensor library
Lettura del DHT22.
Adafruit Unified Sensor
Dipendenza della libreria DHT.

La libreria Wire, usata per il bus I2C, è già inclusa nell’Arduino IDE.

🔌 Schema di collegamento

ComponenteCollegamento
OLED SSD1306VCC → 5V, GND → GND, SDA → A4, SCL → A5
DHT22VCC → 5V, DATA → D2, GND → GND
LDR5V → LDR → A0; resistenza 10 kΩ tra A0 e GND
LED verdeAnodo → D8 tramite 220 Ω; catodo → GND
LED gialloAnodo → D9 tramite 220 Ω; catodo → GND
LED rossoAnodo → D10 tramite 220 Ω; catodo → GND
PulsanteD3 ↔ pulsante ↔ GND
OLED: lo sketch utilizza l’indirizzo I2C 0x3C. Il pulsante usa INPUT_PULLUP, quindi non richiede una resistenza esterna.
Schema sistema debug Arduino con OLED DHT22 LDR e tre LED

💻 Codice Arduino completo

Il programma divide la diagnostica in tre livelli — OK, ATTENZIONE ed ERRORE — e assegna codici specifici alle anomalie.

Progetto #138 — Sistema debug LED + OLED
/*
  ============================================================
  Progetto 138 - Sistema debug LED e display
  Mostra stato, avvisi e codici di errore del sistema
  ============================================================
*/

#include 
#include 
#include 
#include 

// Dimensioni e indirizzo del display OLED
#define LARGHEZZA_DISPLAY 128
#define ALTEZZA_DISPLAY 64
#define RESET_OLED -1
#define INDIRIZZO_OLED 0x3C

// Configurazione del sensore DHT22
#define PIN_DHT 2
#define TIPO_DHT DHT22

// Collegamenti degli altri componenti
#define PIN_PULSANTE 3
#define PIN_LED_VERDE 8
#define PIN_LED_GIALLO 9
#define PIN_LED_ROSSO 10
#define PIN_LUCE A0

// Soglie di attenzione
const float TEMP_ATTENZIONE = 28.0;
const float UMID_ATTENZIONE = 65.0;
const int LUCE_ATTENZIONE = 25;

// Soglie di errore
const float TEMP_ERRORE = 35.0;
const float UMID_ERRORE = 80.0;
const int LUCE_ERRORE = 10;

// Tempi di aggiornamento
const unsigned long INTERVALLO_LETTURA = 2000;
const unsigned long TEMPO_DEBOUNCE = 180;

// Oggetti utilizzati per display e sensore
Adafruit_SSD1306 display(
  LARGHEZZA_DISPLAY,
  ALTEZZA_DISPLAY,
  &Wire,
  RESET_OLED
);

DHT dht(PIN_DHT, TIPO_DHT);

// Livelli generali del sistema
enum LivelloSistema {
  STATO_OK,
  STATO_ATTENZIONE,
  STATO_ERRORE
};

LivelloSistema livelloAttuale = STATO_OK;

// Codici di debug disponibili
enum CodiceDebug {
  DEBUG_OK,
  DEBUG_DHT,
  DEBUG_TEMPERATURA,
  DEBUG_UMIDITA,
  DEBUG_LUMINOSITA
};

CodiceDebug codiceAttuale = DEBUG_OK;

// Valori letti dai sensori
float temperatura = 0.0;
float umidita = 0.0;
int luminositaPercentuale = 0;

// Indica se il DHT22 ha restituito dati validi
bool sensoreDhtValido = false;

// Schermata attualmente visualizzata
byte schermataAttuale = 0;
const byte NUMERO_SCHERMATE = 2;

// Variabili temporali
unsigned long ultimaLettura = 0;
unsigned long ultimaPressione = 0;
unsigned long ultimoAggiornamentoValido = 0;

// Indica quando il display deve essere ridisegnato
bool aggiornamentoDisplayRichiesto = true;

void setup() {
  // Il pulsante è collegato tra il pin e GND
  pinMode(PIN_PULSANTE, INPUT_PULLUP);

  // Configura i tre LED come uscite
  pinMode(PIN_LED_VERDE, OUTPUT);
  pinMode(PIN_LED_GIALLO, OUTPUT);
  pinMode(PIN_LED_ROSSO, OUTPUT);

  // Spegne tutti i LED durante l'avvio
  spegniTuttiLed();

  // Avvia il sensore DHT22
  dht.begin();

  // Inizializza il display OLED
  if (!display.begin(
        SSD1306_SWITCHCAPVCC,
        INDIRIZZO_OLED
      )) {
    // Se il display non viene rilevato,
    // il programma rimane bloccato
    while (true) {
    }
  }

  display.clearDisplay();
  display.setTextColor(SSD1306_WHITE);
  display.setTextWrap(false);

  mostraAvvio();

  // Esegue un test rapido dei LED
  testLed();

  // Esegue subito una prima lettura
  leggiSensori();
  valutaSistema();
  aggiornaLed();
  mostraSchermata();

  ultimaLettura = millis();
  aggiornamentoDisplayRichiesto = false;
}

void loop() {
  // Controlla il pulsante per cambiare schermata
  gestisciPulsante();

  // Legge periodicamente i sensori
  if (millis() - ultimaLettura >= INTERVALLO_LETTURA) {
    ultimaLettura = millis();

    leggiSensori();
    valutaSistema();
    aggiornaLed();

    aggiornamentoDisplayRichiesto = true;
  }

  // Ridisegna il display soltanto quando necessario
  if (aggiornamentoDisplayRichiesto) {
    mostraSchermata();
    aggiornamentoDisplayRichiesto = false;
  }
}

void leggiSensori() {
  // Legge temperatura e umidità dal DHT22
  float nuovaTemperatura = dht.readTemperature();
  float nuovaUmidita = dht.readHumidity();

  // Aggiorna i valori soltanto
  // se entrambe le letture sono valide
  if (!isnan(nuovaTemperatura) &&
      !isnan(nuovaUmidita)) {
    temperatura = nuovaTemperatura;
    umidita = nuovaUmidita;
    sensoreDhtValido = true;

    // Memorizza il momento dell'ultima lettura valida
    ultimoAggiornamentoValido = millis();
  } else {
    sensoreDhtValido = false;
  }

  // Legge la fotoresistenza
  int valoreLuce = analogRead(PIN_LUCE);

  // Converte il valore analogico in percentuale
  luminositaPercentuale = map(
    valoreLuce,
    0,
    1023,
    0,
    100
  );

  luminositaPercentuale = constrain(
    luminositaPercentuale,
    0,
    100
  );
}

void valutaSistema() {
  /*
    Gli errori hanno priorità sulle condizioni
    di attenzione. Il primo errore trovato
    determina il codice mostrato sul display.
  */

  // Errore di comunicazione con il DHT22
  if (!sensoreDhtValido) {
    livelloAttuale = STATO_ERRORE;
    codiceAttuale = DEBUG_DHT;
    return;
  }

  // Temperatura oltre la soglia critica
  if (temperatura >= TEMP_ERRORE) {
    livelloAttuale = STATO_ERRORE;
    codiceAttuale = DEBUG_TEMPERATURA;
    return;
  }

  // Umidità oltre la soglia critica
  if (umidita >= UMID_ERRORE) {
    livelloAttuale = STATO_ERRORE;
    codiceAttuale = DEBUG_UMIDITA;
    return;
  }

  // Luminosità sotto la soglia critica
  if (luminositaPercentuale = TEMP_ATTENZIONE ||
      umidita >= UMID_ATTENZIONE ||
      luminositaPercentuale = TEMPO_DEBOUNCE) {
    ultimaPressione = millis();

    // Passa alla schermata successiva
    schermataAttuale++;

    if (schermataAttuale >= NUMERO_SCHERMATE) {
      schermataAttuale = 0;
    }

    aggiornamentoDisplayRichiesto = true;
  }
}

void mostraSchermata() {
  // Pulisce completamente il display
  display.clearDisplay();
  display.setTextColor(SSD1306_WHITE);

  if (schermataAttuale == 0) {
    mostraRiepilogo();
  } else {
    mostraDebug();
  }

  // Invia al display tutti gli elementi disegnati
  display.display();
}

void mostraRiepilogo() {
  display.setTextSize(1);

  // Titolo della schermata
  display.setCursor(0, 0);
  display.print("STATO SISTEMA");

  display.setCursor(103, 0);
  display.print("1/2");

  display.drawLine(
    0,
    10,
    127,
    10,
    SSD1306_WHITE
  );

  // Mostra il livello generale
  display.setCursor(0, 16);
  display.print("Livello: ");

  if (livelloAttuale == STATO_OK) {
    display.print("OK");
  } else if (livelloAttuale == STATO_ATTENZIONE) {
    display.print("ATTENZIONE");
  } else {
    display.print("ERRORE");
  }

  // Mostra la temperatura
  display.setCursor(0, 29);
  display.print("Temp: ");

  if (sensoreDhtValido) {
    display.print(temperatura, 1);
    display.print((char)247);
    display.print("C");
  } else {
    display.print("ERR");
  }

  // Mostra l'umidità
  display.setCursor(0, 42);
  display.print("Umid: ");

  if (sensoreDhtValido) {
    display.print(umidita, 1);
    display.print("%");
  } else {
    display.print("ERR");
  }

  // Mostra la luminosità
  display.setCursor(0, 55);
  display.print("Luce: ");
  display.print(luminositaPercentuale);
  display.print("%");
}

void mostraDebug() {
  display.setTextSize(1);

  display.setCursor(0, 0);
  display.print("DEBUG SISTEMA");

  display.setCursor(103, 0);
  display.print("2/2");

  display.drawLine(
    0,
    10,
    127,
    10,
    SSD1306_WHITE
  );

  // Mostra il codice di debug
  display.setCursor(0, 16);
  display.print("Codice: ");
  display.print(testoCodiceDebug());

  // Mostra lo stato del DHT22
  display.setCursor(0, 29);
  display.print("DHT22: ");

  if (sensoreDhtValido) {
    display.print("ONLINE");
  } else {
    display.print("ERRORE");
  }

  // Mostra il tempo trascorso dall'ultima
  // lettura valida del sensore
  display.setCursor(0, 42);
  display.print("Ultimo OK: ");

  unsigned long secondiTrascorsi =
    (millis() - ultimoAggiornamentoValido) / 1000UL;

  display.print(secondiTrascorsi);
  display.print("s");

  // Mostra il LED che dovrebbe essere acceso
  display.setCursor(0, 55);
  display.print("LED: ");

  if (livelloAttuale == STATO_OK) {
    display.print("VERDE");
  } else if (livelloAttuale == STATO_ATTENZIONE) {
    display.print("GIALLO");
  } else {
    display.print("ROSSO");
  }
}

const char* testoCodiceDebug() {
  // Restituisce il testo corrispondente
  // al codice di errore corrente
  switch (codiceAttuale) {
    case DEBUG_DHT:
      return "D01";

    case DEBUG_TEMPERATURA:
      return "D02";

    case DEBUG_UMIDITA:
      return "D03";

    case DEBUG_LUMINOSITA:
      return "D04";

    case DEBUG_OK:
    default:
      return "D00";
  }
}

void mostraAvvio() {
  display.clearDisplay();
  display.setTextSize(1);

  display.setCursor(19, 14);
  display.print("Sistema debug");

  display.setCursor(19, 30);
  display.print("LED + display");

  display.setCursor(28, 47);
  display.print("Progetto 138");

  display.display();

  delay(1800);
}

⚙️ Come funziona

Ogni due secondi Arduino legge DHT22 e fotoresistenza, valuta i valori rispetto alle soglie configurate, sceglie il livello generale e accende soltanto il LED corrispondente. Il display viene ridisegnato quando arrivano nuovi dati oppure quando premi il pulsante per cambiare schermata.

Struttura logica: lettura sensori → valutazione delle soglie → assegnazione stato/codice → aggiornamento LED → aggiornamento OLED.

🚦 Le soglie del sistema

ParametroAttenzioneErrore
Temperatura≥ 28 °C≥ 35 °C
Umidità≥ 65%≥ 80%
Luminosità≤ 25%≤ 10%
DHT22Lettura non valida

Le soglie sono dichiarate all’inizio dello sketch, quindi puoi adattarle facilmente al tuo progetto.

Importante: queste soglie sono valori dimostrativi per il progetto didattico e non costituiscono soglie di sicurezza universali.

⚠️ Codici di debug

CodiceSignificato
D00Nessun errore
D01DHT22 non disponibile / lettura non valida
D02Temperatura troppo elevata
D03Umidità troppo elevata
D04Luminosità troppo bassa

Gli errori hanno priorità sulle condizioni di attenzione. Inoltre lo sketch controlla gli errori in un ordine preciso: DHT22, temperatura, umidità e infine luminosità. Il primo errore trovato diventa il codice mostrato sul display.

🧪 Test automatico dei LED

All’accensione viene eseguita la funzione testLed(). Arduino accende per circa 350 ms prima il LED verde, poi il giallo e infine il rosso.

Questo semplice autotest permette di verificare immediatamente collegamento, polarità e funzionamento dei tre indicatori prima che inizi la diagnostica vera e propria.

📟 Le due schermate OLED

Schermata 1/2 — Stato sistema

  • livello generale;
  • temperatura;
  • umidità;
  • luminosità.

Schermata 2/2 — Debug sistema

  • codice diagnostico;
  • DHT22 online/errore;
  • secondi dall’ultima lettura valida;
  • LED che dovrebbe essere acceso.

Premendo il pulsante su D3 il programma passa ciclicamente da una schermata all’altra. Un debounce software di 180 ms evita cambi multipli causati dal rimbalzo meccanico.

⏱️ Aggiornamento senza bloccare Arduino

Le letture periodiche sono gestite con millis() e un intervallo di 2000 ms. Questo evita un delay(2000) nel loop principale e lascia il microcontrollore libero di controllare continuamente il pulsante.

I delay() presenti nel progetto vengono usati soltanto durante la sequenza iniziale e il test dei LED, prima del normale funzionamento del sistema.

🧠 Perché questo progetto è importante

Qui Arduino non si limita a leggere sensori: interpreta lo stato del sistema e comunica una diagnosi. È un modello utile per centraline, robot, sistemi domotici e dispositivi installati lontano dal computer.

La separazione in funzioni come lettura, valutazione, LED e visualizzazione rende inoltre lo sketch più facile da mantenere ed estendere.

🔄 Varianti possibili

🔊 Buzzer per gli errori
💾 Ultimo errore in EEPROM
⏰ Timestamp con RTC DS3231
📋 Storico degli eventi
🔘 Pulsante di reset
⚡ Diagnostica di un relè
🔋 Controllo batteria
🚪 Reed switch
🚶 Sensore PIR
📶 Errori inviati via Wi-Fi
🗃️ Log su microSD
🌈 LED RGB al posto dei tre LED

✅ Cosa devi ricordare

  • verde = sistema regolare, giallo = attenzione, rosso = errore;
  • le letture vengono aggiornate ogni 2 secondi;
  • gli errori hanno priorità sulle condizioni di attenzione;
  • il DHT22 non valido genera D01;
  • il pulsante D3 cambia tra le due schermate;
  • il display usa I2C all’indirizzo 0x3C;
  • il test iniziale verifica i tre LED;
  • il display viene ridisegnato soltanto quando necessario;
  • le soglie possono essere personalizzate all’inizio dello sketch.