PROGETTI ARDUINO

  • HOME
  • 200 Progetti
  • Progetti e Tutorial
  • Reti
    • Impara le reti
    • internet fibra
    • wifi mesh
    • modem router
    • diagnostica reti
    • ethernet lan
    • sicurezza configurazione
  • Elettronica
  • Recensioni
  • Manuale
  • Contatti
  • HOME
  • 200 Progetti
  • Progetti e Tutorial
  • Reti
    • Impara le reti
    • internet fibra
    • wifi mesh
    • modem router
    • diagnostica reti
    • ethernet lan
    • sicurezza configurazione
  • Elettronica
  • Recensioni
  • Manuale
  • Contatti

Progetto 130
​ Monitor ambiente con storico delle ultime 24 ore

🚀 Introduzione
​

Vuoi controllare temperatura e umidità e vedere come sono cambiate durante la giornata? 🌡️📊
In questo progetto realizzerai un monitor ambientale con storico delle ultime 24 ore, utilizzando Arduino, un sensore DHT22, un display OLED e il modulo RTC DS3231.
​
Arduino registrerà automaticamente una lettura ogni ora e conserverà i dati nella memoria EEPROM.
Tramite un pulsante potrai visualizzare:
  • valori ambientali attuali;
  • temperatura minima e massima;
  • umidità minima e massima;
  • singole registrazioni orarie.
👉 I dati rimarranno disponibili anche dopo lo spegnimento di Arduino.

🎯 Cosa realizzerai
​

​Con Arduino creerai un sistema che:
  • 🌡️ misura la temperatura ambientale;
  • 💧 misura l’umidità relativa;
  • ⏰ legge data e ora dal modulo DS3231;
  • 🗂️ conserva fino a 24 registrazioni;
  • 💾 salva lo storico nella EEPROM;
  • 📉 calcola i valori minimi;
  • 📈 calcola i valori massimi;
  • 📟 mostra i dati su display OLED;
  • 🔘 permette di cambiare schermata;
  • ⚠️ segnala gli errori del sensore.

🧰 Materiale necessario
​

  • 1x Arduino UNO;
  • 1x sensore DHT22;
  • 1x resistenza da 10 kΩ, se utilizzi il sensore senza modulo;
  • 1x modulo RTC DS3231;
  • 1x batteria CR2032;
  • 1x display OLED 0,96 pollici I2C SSD1306;
  • 1x pulsante;
  • cavetti jumper;
  • breadboard;
  • cavo USB.
Il pulsante utilizza la resistenza interna INPUT_PULLUP di Arduino e non richiede una resistenza esterna.

🛒 Non hai ancora i componenti?

Molti dei progetti presenti su progettiarduino.com utilizzano componenti elettronici di base come LED, resistenze, sensori e breadboard.
Se stai iniziando con Arduino, il modo più semplice è utilizzare un kit completo per principianti, che include quasi tutti i componenti necessari per realizzare molti dei progetti presenti sul sito.

👉 Kit Arduino consigliato:
ℹ️ Link di affiliazione Amazon: in qualità di Affiliato Amazon ricevo un guadagno dagli acquisti idonei, senza alcun costo aggiuntivo per te.
https://amzn.to/4b3dxjW

📘 Vuoi imparare Arduino passo dopo passo?
Se vuoi approfondire e realizzare progetti più completi, puoi dare un'occhiata anche ai miei libri dedicati ad Arduino.
All'interno troverai spiegazioni semplici, schemi chiari e molti progetti pratici pensati per chi parte da zero.

👉 Scopri i miei libri su Arduino:
ℹ️ Link di affiliazione Amazon: in qualità di Affiliato Amazon ricevo un guadagno dagli acquisti idonei, senza alcun costo aggiuntivo per te.
https://amzn.to/4rfzjXE
​

📚 Librerie necessarie
​

Per realizzare il progetto devi installare:
  • Adafruit SSD1306;
  • Adafruit GFX Library;
  • DHT sensor library;
  • Adafruit Unified Sensor;
  • RTClib.
​
Il programma utilizza inoltre:
  • Wire;
  • EEPROM.
Queste ultime sono già incluse nell’Arduino IDE.

🔌 Schema di collegamento

Display OLED SSD1306
  • VCC → 5V;
  • GND → GND;
  • SDA → A4;
  • SCL → A5.
L’indirizzo I2C utilizzato nel codice è 0x3C.

Modulo RTC DS3231
  • VCC → 5V;
  • GND → GND;
  • SDA → A4;
  • SCL → A5.
Il display OLED e il modulo RTC condividono il bus I2C.

Sensore DHT22
Se utilizzi un modulo già assemblato:
  • VCC → 5V;
  • GND → GND;
  • DATA → pin digitale 2.
Se utilizzi il sensore senza modulo, collega una resistenza da 10 kΩ tra DATA e 5V.

Pulsante
  • un terminale → pin digitale 3;
  • terminale opposto → GND.
Con INPUT_PULLUP, il pulsante premuto viene letto come LOW.
Foto

💻 Codice Arduino
​

Il programma registra una nuova lettura quando cambia l’ora indicata dal modulo RTC.
Ogni registrazione contiene:
  • temperatura;
  • umidità;
  • ora della misurazione.
Lo storico utilizza una struttura circolare: dopo la ventiquattresima registrazione, il nuovo dato sostituisce quello più vecchio.
​/*
  ============================================================
  Progetto 130 - Monitor ambiente con storico
  Registra temperatura e umidita delle ultime 24 ore
  nella memoria EEPROM
  ============================================================
*/

#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <DHT.h>
#include <RTClib.h>
#include <EEPROM.h>

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

// Collegamenti del sensore e del pulsante
#define PIN_DHT 2
#define TIPO_DHT DHT22
#define PIN_PULSANTE 3

// Numero massimo di registrazioni conservate
const byte NUMERO_REGISTRAZIONI = 24;

// Intervallo di lettura del sensore
const unsigned long INTERVALLO_LETTURA = 2000;

// Tempo antirimbalzo del pulsante
const unsigned long TEMPO_DEBOUNCE = 180;

// Firma utilizzata per verificare
// se la EEPROM contiene dati validi
const uint16_t FIRMA_EEPROM = 13024;

// Indirizzi iniziali della memoria EEPROM
const int EEPROM_FIRMA = 0;
const int EEPROM_NUMERO_DATI = 2;
const int EEPROM_PROSSIMA_POSIZIONE = 3;
const int EEPROM_ULTIMA_ORA = 4;
const int EEPROM_STORICO = 5;

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

DHT dht(PIN_DHT, TIPO_DHT);
RTC_DS3231 rtc;

// Ogni registrazione contiene temperatura,
// umidità e ora della misurazione
struct Registrazione {
  int16_t temperaturaDecimi;
  byte umidita;
  byte ora;
};

// Array che contiene lo storico in memoria RAM
Registrazione storico[NUMERO_REGISTRAZIONI];

// Valori ambientali correnti
float temperatura = 0.0;
float umidita = 0.0;

// Indica se l'ultima lettura è valida
bool sensoreValido = false;

// Numero di registrazioni realmente disponibili
byte numeroDati = 0;

// Posizione in cui verrà scritto il prossimo campione
byte prossimaPosizione = 0;

// Ultima ora già registrata
byte ultimaOraRegistrata = 255;

// Schermate disponibili
enum Schermata {
  SCHERMATA_ATTUALE,
  SCHERMATA_RIEPILOGO,
  SCHERMATA_STORICO
};

Schermata schermataAttuale = SCHERMATA_ATTUALE;

// Indice della registrazione visualizzata
byte indiceStoricoVisualizzato = 0;

// Variabili temporali utilizzate da millis()
unsigned long ultimaLettura = 0;
unsigned long ultimaPressione = 0;

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

  // Avvia sensore e comunicazione I2C
  dht.begin();
  Wire.begin();

  // Inizializza il display OLED
  if (!display.begin(
        SSD1306_SWITCHCAPVCC,
        INDIRIZZO_OLED
      )) {
    while (true) {
    }
  }

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

  mostraAvvio();

  // Controlla che il modulo RTC sia collegato
  if (!rtc.begin()) {
    mostraErroreRtc();

    while (true) {
    }
  }

  // Se il DS3231 ha perso l'alimentazione,
  // imposta data e ora di compilazione
  if (rtc.lostPower()) {
    rtc.adjust(
      DateTime(
        F(__DATE__),
        F(__TIME__)
      )
    );
  }

  // Recupera lo storico dalla memoria EEPROM
  caricaStorico();

  // Esegue subito una prima lettura
  leggiSensore();

  DateTime adesso = rtc.now();

  // Registra immediatamente un primo dato
  // se non è già presente una lettura per l'ora corrente
  controllaRegistrazioneOraria(adesso);

  mostraSchermata(adesso);

  ultimaLettura = millis();
}

void loop() {
  DateTime adesso = rtc.now();

  // Gestisce il cambio delle schermate
  gestisciPulsante();

  // Legge il sensore DHT22 ogni due secondi
  if (millis() - ultimaLettura >= INTERVALLO_LETTURA) {
    ultimaLettura = millis();

    leggiSensore();
    controllaRegistrazioneOraria(adesso);
    mostraSchermata(adesso);
  }
}

void leggiSensore() {
  // Acquisisce temperatura e umidità
  float nuovaTemperatura = dht.readTemperature();
  float nuovaUmidita = dht.readHumidity();

  // Ignora letture non valide
  if (isnan(nuovaTemperatura) ||
      isnan(nuovaUmidita)) {
    sensoreValido = false;
    return;
  }

  sensoreValido = true;
  temperatura = nuovaTemperatura;
  umidita = nuovaUmidita;
}

void controllaRegistrazioneOraria(
  const DateTime& adesso
) {
  // Non salva dati se il sensore
  // non ha restituito valori validi
  if (!sensoreValido) {
    return;
  }

  byte oraCorrente = adesso.hour();

  // Registra un nuovo campione soltanto
  // quando cambia l'ora
  if (oraCorrente == ultimaOraRegistrata) {
    return;
  }

  salvaNuovaRegistrazione(
    temperatura,
    umidita,
    oraCorrente
  );

  ultimaOraRegistrata = oraCorrente;

  // Salva anche l'ultima ora nella EEPROM
  EEPROM.update(
    EEPROM_ULTIMA_ORA,
    ultimaOraRegistrata
  );
}

void salvaNuovaRegistrazione(
  float nuovaTemperatura,
  float nuovaUmidita,
  byte ora
) {
  // Converte la temperatura in decimi di grado
  storico[prossimaPosizione].temperaturaDecimi =
    (int16_t)(nuovaTemperatura * 10.0);

  // Limita e salva l'umidità come numero intero
  storico[prossimaPosizione].umidita =
    constrain((int)nuovaUmidita, 0, 100);

  storico[prossimaPosizione].ora = ora;

  // Salva nella EEPROM soltanto
  // la registrazione appena modificata
  int indirizzo =
    EEPROM_STORICO +
    prossimaPosizione * sizeof(Registrazione);

  EEPROM.put(
    indirizzo,
    storico[prossimaPosizione]
  );

  // Aumenta il numero dei dati disponibili
  // fino al limite massimo di 24
  if (numeroDati < NUMERO_REGISTRAZIONI) {
    numeroDati++;
  }

  // Passa alla posizione successiva
  prossimaPosizione++;

  // Dopo l'ultima posizione riparte dalla prima
  if (prossimaPosizione >= NUMERO_REGISTRAZIONI) {
    prossimaPosizione = 0;
  }

  // Aggiorna i dati di controllo nella EEPROM
  EEPROM.update(
    EEPROM_NUMERO_DATI,
    numeroDati
  );

  EEPROM.update(
    EEPROM_PROSSIMA_POSIZIONE,
    prossimaPosizione
  );
}

void caricaStorico() {
  uint16_t firmaSalvata;

  // Legge la firma dalla EEPROM
  EEPROM.get(
    EEPROM_FIRMA,
    firmaSalvata
  );

  // Se la firma non è valida,
  // inizializza uno storico vuoto
  if (firmaSalvata != FIRMA_EEPROM) {
    inizializzaEeprom();
    return;
  }

  // Recupera le informazioni principali
  numeroDati = EEPROM.read(
    EEPROM_NUMERO_DATI
  );

  prossimaPosizione = EEPROM.read(
    EEPROM_PROSSIMA_POSIZIONE
  );

  ultimaOraRegistrata = EEPROM.read(
    EEPROM_ULTIMA_ORA
  );

  // Controlla che i valori siano nei limiti
  if (numeroDati > NUMERO_REGISTRAZIONI ||
      prossimaPosizione >= NUMERO_REGISTRAZIONI) {
    inizializzaEeprom();
    return;
  }

  // Carica tutte le registrazioni dalla EEPROM
  for (byte i = 0; i < NUMERO_REGISTRAZIONI; i++) {
    int indirizzo =
      EEPROM_STORICO +
      i * sizeof(Registrazione);

    EEPROM.get(
      indirizzo,
      storico[i]
    );
  }
}

void inizializzaEeprom() {
  // Azzera lo stato dello storico
  numeroDati = 0;
  prossimaPosizione = 0;
  ultimaOraRegistrata = 255;

  // Salva la firma e i valori iniziali
  EEPROM.put(
    EEPROM_FIRMA,
    FIRMA_EEPROM
  );

  EEPROM.update(
    EEPROM_NUMERO_DATI,
    numeroDati
  );

  EEPROM.update(
    EEPROM_PROSSIMA_POSIZIONE,
    prossimaPosizione
  );

  EEPROM.update(
    EEPROM_ULTIMA_ORA,
    ultimaOraRegistrata
  );

  // Inizializza anche l'array in RAM
  for (byte i = 0; i < NUMERO_REGISTRAZIONI; i++) {
    storico[i].temperaturaDecimi = 0;
    storico[i].umidita = 0;
    storico[i].ora = 0;
  }
}

void gestisciPulsante() {
  // Con INPUT_PULLUP il pulsante premuto
  // viene letto come LOW
  if (digitalRead(PIN_PULSANTE) == LOW &&
      millis() - ultimaPressione >= TEMPO_DEBOUNCE) {
    ultimaPressione = millis();

    // Dalla schermata principale passa al riepilogo
    if (schermataAttuale == SCHERMATA_ATTUALE) {
      schermataAttuale = SCHERMATA_RIEPILOGO;
    }

    // Dal riepilogo passa allo storico
    else if (schermataAttuale ==
             SCHERMATA_RIEPILOGO) {
      schermataAttuale = SCHERMATA_STORICO;
      indiceStoricoVisualizzato = 0;
    }

    // Nello storico mostra il campione successivo
    else {
      indiceStoricoVisualizzato++;

      // Dopo l'ultima registrazione
      // torna alla schermata principale
      if (indiceStoricoVisualizzato >= numeroDati) {
        indiceStoricoVisualizzato = 0;
        schermataAttuale = SCHERMATA_ATTUALE;
      }
    }

    mostraSchermata(rtc.now());
  }
}

void mostraSchermata(const DateTime& adesso) {
  display.clearDisplay();
  display.setTextColor(SSD1306_WHITE);

  if (schermataAttuale == SCHERMATA_ATTUALE) {
    mostraValoriAttuali(adesso);
  } else if (
    schermataAttuale == SCHERMATA_RIEPILOGO
  ) {
    mostraRiepilogo();
  } else {
    mostraStorico();
  }

  // Mostra un avviso se l'ultima lettura
  // del DHT22 non è valida
  if (!sensoreValido) {
    display.fillRect(
      84,
      54,
      43,
      10,
      SSD1306_BLACK
    );

    display.setTextSize(1);
    display.setCursor(87, 55);
    display.print("DHT ERR");
  }

  display.display();
}

void mostraValoriAttuali(
  const DateTime& adesso
) {
  display.setTextSize(1);

  // Titolo e ora corrente
  display.setCursor(0, 0);
  display.print("MONITOR AMBIENTE");

  display.setCursor(92, 0);
  stampaDueCifre(adesso.hour());
  display.print(":");
  stampaDueCifre(adesso.minute());

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

  // Temperatura attuale
  display.setTextSize(2);
  display.setCursor(0, 18);
  display.print(temperatura, 1);
  display.print((char)247);
  display.print("C");

  // Umidità attuale
  display.setCursor(75, 18);
  display.print(umidita, 0);
  display.print("%");

  display.setTextSize(1);

  // Numero di registrazioni disponibili
  display.setCursor(0, 45);
  display.print("Storico: ");
  display.print(numeroDati);
  display.print("/");
  display.print(NUMERO_REGISTRAZIONI);

  display.setCursor(0, 56);
  display.print("Premi: riepilogo");
}

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

  display.setCursor(0, 0);
  display.print("MINIMI E MASSIMI");

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

  // Se non esistono registrazioni,
  // mostra un messaggio dedicato
  if (numeroDati == 0) {
    display.setCursor(14, 28);
    display.print("Storico vuoto");

    display.setCursor(9, 44);
    display.print("Attendi una lettura");
    return;
  }

  float tempMin;
  float tempMax;
  byte umidMin;
  byte umidMax;

  calcolaMinimiMassimi(
    tempMin,
    tempMax,
    umidMin,
    umidMax
  );

  display.setCursor(0, 16);
  display.print("Temp min: ");
  display.print(tempMin, 1);
  display.print((char)247);
  display.print("C");

  display.setCursor(0, 28);
  display.print("Temp max: ");
  display.print(tempMax, 1);
  display.print((char)247);
  display.print("C");

  display.setCursor(0, 42);
  display.print("Umid min: ");
  display.print(umidMin);
  display.print("%");

  display.setCursor(0, 54);
  display.print("Umid max: ");
  display.print(umidMax);
  display.print("%");
}

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

  display.setCursor(0, 0);
  display.print("STORICO ORARIO");

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

  if (numeroDati == 0) {
    display.setCursor(14, 28);
    display.print("Storico vuoto");

    display.setCursor(8, 44);
    display.print("Premi per tornare");
    return;
  }

  // Recupera la registrazione in ordine cronologico,
  // dalla più vecchia alla più recente
  Registrazione dato =
    leggiRegistrazioneCronologica(
      indiceStoricoVisualizzato
    );

  display.setCursor(0, 16);
  display.print("Campione ");
  display.print(indiceStoricoVisualizzato + 1);
  display.print("/");
  display.print(numeroDati);

  display.setCursor(0, 29);
  display.print("Ora: ");
  stampaDueCifre(dato.ora);
  display.print(":00");

  display.setCursor(0, 42);
  display.print("Temp: ");
  display.print(
    dato.temperaturaDecimi / 10.0,
    1
  );
  display.print((char)247);
  display.print("C");

  display.setCursor(0, 55);
  display.print("Umid: ");
  display.print(dato.umidita);
  display.print("%");
}

Registrazione leggiRegistrazioneCronologica(
  byte indice
) {
  byte posizioneReale;

  // Se il buffer non è ancora pieno,
  // i dati iniziano dalla posizione zero
  if (numeroDati < NUMERO_REGISTRAZIONI) {
    posizioneReale = indice;
  } else {
    // Quando il buffer è pieno,
    // la prossima posizione indica il dato più vecchio
    posizioneReale =
      (prossimaPosizione + indice) %
      NUMERO_REGISTRAZIONI;
  }

  return storico[posizioneReale];
}

void calcolaMinimiMassimi(
  float& tempMin,
  float& tempMax,
  byte& umidMin,
  byte& umidMax
) {
  // Utilizza la prima registrazione
  // per inizializzare i valori
  Registrazione primoDato =
    leggiRegistrazioneCronologica(0);

  tempMin =
    primoDato.temperaturaDecimi / 10.0;

  tempMax = tempMin;
  umidMin = primoDato.umidita;
  umidMax = primoDato.umidita;

  // Analizza tutte le registrazioni successive
  for (byte i = 1; i < numeroDati; i++) {
    Registrazione dato =
      leggiRegistrazioneCronologica(i);

    float temperaturaDato =
      dato.temperaturaDecimi / 10.0;

    if (temperaturaDato < tempMin) {
      tempMin = temperaturaDato;
    }

    if (temperaturaDato > tempMax) {
      tempMax = temperaturaDato;
    }

    if (dato.umidita < umidMin) {
      umidMin = dato.umidita;
    }

    if (dato.umidita > umidMax) {
      umidMax = dato.umidita;
    }
  }
}

void stampaDueCifre(int valore) {
  // Aggiunge lo zero iniziale ai valori
  // inferiori a dieci
  if (valore < 10) {
    display.print("0");
  }

  display.print(valore);
}

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

  display.setCursor(17, 14);
  display.print("Monitor ambiente");

  display.setCursor(18, 30);
  display.print("Storico 24 ore");

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

  display.display();

  delay(1800);
}

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

  display.setCursor(27, 15);
  display.print("ERRORE RTC");

  display.setCursor(9, 31);
  display.print("DS3231 non rilevato");

  display.setCursor(15, 47);
  display.print("Controlla i cavi");

  display.display();
}

⚙️ Come funziona

Arduino legge temperatura e umidità dal sensore DHT22 ogni due secondi.
Le letture correnti vengono mostrate nella schermata principale.
​
Quando l’ora cambia, Arduino registra una nuova misurazione nello storico.
Per esempio:
  • alle 14:00 viene salvata una lettura;
  • alle 15:00 viene salvata quella successiva;
  • dopo 24 registrazioni lo storico contiene circa un giorno completo.
​
👉 Se Arduino viene riavviato, lo storico viene recuperato dalla memoria EEPROM.

🗂️ Struttura dello storico

Ogni registrazione viene conservata in una struttura:
struct Registrazione {
int16_t temperaturaDecimi;
byte umidita; byte ora;
};


La temperatura viene moltiplicata per 10.
Per esempio:
  • 23,4 °C viene memorizzata come 234;
  • 18,7 °C viene memorizzata come 187.
Questa soluzione occupa meno memoria rispetto al salvataggio diretto di un numero float.

🔄 Buffer circolare
​

Lo storico utilizza un buffer circolare di 24 elementi.
Quando lo spazio disponibile termina, il programma ricomincia dalla prima posizione e sostituisce la registrazione più vecchia.
​
In questo modo:
  • la memoria utilizzata rimane sempre la stessa;
  • non è necessario cancellare manualmente i dati;
  • vengono conservate sempre le registrazioni più recenti.

💾 Salvataggio nella EEPROM
​

La EEPROM mantiene i dati anche quando Arduino viene spento.

Il programma salva:
  • numero delle registrazioni disponibili;
  • posizione della prossima scrittura;
  • ultima ora registrata;
  • tutte le misurazioni dello storico.
​
Una firma numerica permette di capire se la EEPROM contiene dati validi.
Se la firma non viene trovata, Arduino crea automaticamente uno storico vuoto.

📟 Schermate disponibili
​

Il monitor utilizza tre modalità di visualizzazione.

Schermata principale
Mostra:
  • ora corrente;
  • temperatura;
  • umidità;
  • numero di registrazioni memorizzate.

Schermata riepilogo
Mostra i valori minimi e massimi presenti nello storico:
  • temperatura minima;
  • temperatura massima;
  • umidità minima;
  • umidità massima.

Schermata storico
Mostra una registrazione alla volta:
  • posizione nello storico;
  • ora della lettura;
  • temperatura;
  • umidità.
Premendo il pulsante puoi scorrere tutte le registrazioni disponibili.

⚠️ Gestione degli errori
​

Se il sensore DHT22 restituisce un valore non valido:
  • gli ultimi dati corretti rimangono visibili;
  • la lettura non viene salvata nello storico;
  • sul display appare l’indicazione DHT ERR;
  • Arduino prova nuovamente dopo due secondi.
​
Se il modulo RTC non viene rilevato, il programma mostra un errore e interrompe il funzionamento.

🧠 Perché è un progetto importante
​

Con questo progetto impari a:
  • realizzare uno storico di misurazioni;
  • utilizzare strutture personalizzate;
  • creare un buffer circolare;
  • salvare dati nella EEPROM;
  • ridurre lo spazio occupato dai valori;
  • utilizzare il modulo RTC DS3231;
  • analizzare valori minimi e massimi;
  • creare più schermate OLED;
  • gestire errori senza perdere i dati;
  • organizzare un progetto Arduino più complesso.
👉 Questa struttura rappresenta una base utile per datalogger, centraline ambientali, serre automatiche e sistemi di monitoraggio.

🔄 Varianti possibili
​

Vuoi migliorare il progetto?
  • 📊 aggiungi un grafico dello storico;
  • 💾 utilizza una scheda microSD;
  • 📅 salva anche giorno e mese;
  • 🔘 aggiungi un secondo pulsante per tornare indietro;
  • 🗑️ crea una funzione per cancellare lo storico;
  • 🔔 aggiungi allarmi per temperatura e umidità;
  • 🌬️ controlla automaticamente una ventola;
  • 💨 attiva un umidificatore;
  • 📶 invia i dati tramite Wi-Fi;
  • 📟 utilizza un display OLED più grande;
  • 🕒 registra un campione ogni 30 minuti;
  • 🔋 aggiungi un indicatore della batteria.
Foto
Foto

© ProgettiArduino.com 2026 - Fancello Salvatore
​ Layout, immagini e testi sono di esclusiva proprietà di www.progettiarduino.com 
Privacy Policy