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 127
​ Sveglia programmabile
con Arduino

🚀 Introduzione
​

Vuoi trasformare Arduino in una vera sveglia digitale programmabile? ⏰🔔

In questo progetto realizzerai una sveglia con modulo RTC DS3231, display OLED, pulsanti di regolazione e buzzer.
​
Potrai impostare ore e minuti direttamente dai pulsanti, attivare o disattivare la sveglia e interrompere il suono quando l’allarme entra in funzione.
​
👉 L’orario programmato viene salvato nella memoria EEPROM e rimane disponibile anche dopo lo spegnimento di Arduino.

🎯 Cosa realizzerai
​

Con Arduino creerai un sistema che:
  • ⏰ visualizza l’ora corrente
  • 📅 mostra la data
  • 🔔 permette di programmare una sveglia
  • ⬆️ modifica ore e minuti con i pulsanti
  • ✅ attiva o disattiva l’allarme
  • 📟 mostra lo stato della sveglia sul display OLED
  • 🔊 aziona un buzzer all’orario impostato
  • 🛑 interrompe il suono tramite un pulsante
  • 💾 salva le impostazioni nella EEPROM
  • 🔋 mantiene l’ora grazie al modulo RTC DS3231

🧰 Materiale necessario
​
  • 1x Arduino UNO
  • 1x modulo RTC DS3231
  • 1x batteria CR2032
  • 1x display OLED 0,96 pollici I2C SSD1306
  • 1x buzzer passivo
  • 3x pulsanti
  • cavetti jumper
  • breadboard
  • cavo USB
I pulsanti utilizzeranno le resistenze interne INPUT_PULLUP di Arduino, quindi non serviranno resistenze esterne.
🛒 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:
  • RTClib
  • Adafruit SSD1306
  • Adafruit GFX Library
Il programma utilizza inoltre:
  • Wire
  • EEPROM
Queste ultime sono già incluse nell’Arduino IDE e non devono essere installate separatamente.
​
Per installare le altre librerie:
  1. apri Arduino IDE;
  2. vai su Sketch → Include Library → Manage Libraries;
  3. cerca RTClib;
  4. installa la libreria sviluppata da Adafruit;
  5. cerca Adafruit SSD1306;
  6. installa la libreria;
  7. verifica che sia presente anche Adafruit GFX Library.

🔌 Schema di collegamento

Display OLED SSD1306
  • VCC → 5V
  • GND → GND
  • SDA → A4
  • SCL → A5

Modulo RTC DS3231
  • VCC → 5V
  • GND → GND
  • SDA → A4
  • SCL → A5

Il display OLED e il modulo RTC condividono gli stessi pin I2C.
I due dispositivi possono funzionare contemporaneamente perché utilizzano indirizzi differenti:
  • OLED SSD1306 → 0x3C
  • RTC DS3231 → 0x68

Pulsante MODALITÀ
  • un terminale → pin digitale 2
  • terminale opposto → GND
Il pulsante permette di passare dalla schermata dell’orologio alla regolazione delle ore, dei minuti e dello stato della sveglia.


Pulsante AUMENTA
  • un terminale → pin digitale 3
  • terminale opposto → GND
Il pulsante aumenta il valore selezionato.

Pulsante STOP
  • un terminale → pin digitale 4
  • terminale opposto → GND
Il pulsante interrompe il suono della sveglia quando l’allarme è attivo.
Nella schermata di configurazione permette inoltre di attivare o disattivare la sveglia.
​
Buzzer passivo
  • terminale positivo → pin digitale 8
  • terminale negativo → GND
Il buzzer passivo viene controllato tramite la funzione tone().
Foto

💻 Codice Arduino

Il programma utilizza quattro schermate:
  • orologio normale;
  • regolazione dell’ora della sveglia;
  • regolazione dei minuti;
  • attivazione o disattivazione dell’allarme.
​
Premendo più volte il pulsante MODALITÀ si passa da una schermata alla successiva.
Il pulsante AUMENTA modifica il valore selezionato.
Il pulsante STOP interrompe il suono della sveglia oppure cambia lo stato dell’allarme nella schermata dedicata.
​/*
  ============================================================
  Progetto 127 - Sveglia programmabile con Arduino
  RTC DS3231, display OLED, pulsanti, buzzer ed EEPROM
  ============================================================
*/

#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.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 dei pulsanti e del buzzer
#define PIN_MODALITA 2
#define PIN_AUMENTA 3
#define PIN_STOP 4
#define PIN_BUZZER 8

// Indirizzi utilizzati nella memoria EEPROM
#define EEPROM_ORA 0
#define EEPROM_MINUTO 1
#define EEPROM_STATO 2

// Tempi di gestione del programma
const unsigned long TEMPO_DEBOUNCE = 180;
const unsigned long INTERVALLO_SUONO = 350;

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

RTC_DS3231 rtc;

// Modalità disponibili nell'interfaccia
enum ModalitaDisplay {
  MODALITA_OROLOGIO,
  MODIFICA_ORA,
  MODIFICA_MINUTI,
  MODIFICA_STATO
};

ModalitaDisplay modalitaAttuale = MODALITA_OROLOGIO;

// Impostazioni iniziali della sveglia
byte oraSveglia = 7;
byte minutoSveglia = 30;
bool svegliaAttiva = true;

// Stato corrente dell'allarme
bool allarmeInCorso = false;

// Impedisce più attivazioni nello stesso minuto
bool attivataQuestoMinuto = false;

// Tempi utilizzati per pulsanti e buzzer
unsigned long ultimaPressione = 0;
unsigned long ultimoCambioSuono = 0;

// Alterna le due frequenze del buzzer
bool tonoAlto = false;

// Memorizza il secondo già mostrato
int ultimoSecondoVisualizzato = -1;

void setup() {
  // I pulsanti sono collegati tra pin e GND.
  // INPUT_PULLUP attiva le resistenze interne di Arduino.
  pinMode(PIN_MODALITA, INPUT_PULLUP);
  pinMode(PIN_AUMENTA, INPUT_PULLUP);
  pinMode(PIN_STOP, INPUT_PULLUP);

  pinMode(PIN_BUZZER, OUTPUT);
  noTone(PIN_BUZZER);

  // Avvia il bus I2C
  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();

  // Inizializza il modulo RTC DS3231
  if (!rtc.begin()) {
    mostraErroreRtc();

    while (true) {
    }
  }

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

  // Recupera dalla EEPROM l'orario della sveglia
  caricaImpostazioni();
}

void loop() {
  // Legge l'ora corrente dal modulo DS3231
  DateTime adesso = rtc.now();

  // Controlla i tre pulsanti
  gestisciPulsanti();

  // Verifica se è arrivato l'orario della sveglia
  controllaSveglia(adesso);

  // Se l'allarme è attivo, aggiorna il suono
  // senza bloccare il programma.
  gestisciSuono();

  // Aggiorna il display quando cambia il secondo
  // oppure mentre l'utente modifica le impostazioni.
  if (adesso.second() != ultimoSecondoVisualizzato ||
      modalitaAttuale != MODALITA_OROLOGIO ||
      allarmeInCorso) {
    ultimoSecondoVisualizzato = adesso.second();
    mostraSchermata(adesso);
  }
}

void caricaImpostazioni() {
  // Legge i dati salvati nella EEPROM
  byte oraSalvata = EEPROM.read(EEPROM_ORA);
  byte minutoSalvato = EEPROM.read(EEPROM_MINUTO);
  byte statoSalvato = EEPROM.read(EEPROM_STATO);

  // Controlla che i valori siano validi.
  // Se la EEPROM non è mai stata utilizzata,
  // potrebbe contenere il valore 255.
  if (oraSalvata <= 23) {
    oraSveglia = oraSalvata;
  }

  if (minutoSalvato <= 59) {
    minutoSveglia = minutoSalvato;
  }

  if (statoSalvato <= 1) {
    svegliaAttiva = statoSalvato;
  }

  // Salva anche i valori predefiniti quando
  // nella EEPROM non erano presenti dati validi.
  salvaImpostazioni();
}

void salvaImpostazioni() {
  // update() scrive soltanto se il valore è cambiato,
  // riducendo l'usura della memoria EEPROM.
  EEPROM.update(EEPROM_ORA, oraSveglia);
  EEPROM.update(EEPROM_MINUTO, minutoSveglia);
  EEPROM.update(EEPROM_STATO, svegliaAttiva ? 1 : 0);
}

void gestisciPulsanti() {
  // Accetta un nuovo comando solo dopo il tempo
  // necessario a ridurre il rimbalzo meccanico.
  if (millis() - ultimaPressione < TEMPO_DEBOUNCE) {
    return;
  }

  if (digitalRead(PIN_MODALITA) == LOW) {
    ultimaPressione = millis();
    cambiaModalita();
    return;
  }

  if (digitalRead(PIN_AUMENTA) == LOW) {
    ultimaPressione = millis();
    aumentaValore();
    return;
  }

  if (digitalRead(PIN_STOP) == LOW) {
    ultimaPressione = millis();
    gestisciPulsanteStop();
  }
}

void cambiaModalita() {
  // Interrompe prima l'allarme, se attivo
  if (allarmeInCorso) {
    fermaAllarme();
    return;
  }

  // Passa alla modalità successiva
  switch (modalitaAttuale) {
    case MODALITA_OROLOGIO:
      modalitaAttuale = MODIFICA_ORA;
      break;

    case MODIFICA_ORA:
      modalitaAttuale = MODIFICA_MINUTI;
      break;

    case MODIFICA_MINUTI:
      modalitaAttuale = MODIFICA_STATO;
      break;

    case MODIFICA_STATO:
      modalitaAttuale = MODALITA_OROLOGIO;

      // Quando si esce dalla configurazione,
      // salva tutte le impostazioni.
      salvaImpostazioni();
      break;
  }
}

void aumentaValore() {
  // Il pulsante AUMENTA agisce soltanto
  // nelle schermate di configurazione.
  switch (modalitaAttuale) {
    case MODIFICA_ORA:
      oraSveglia++;

      if (oraSveglia > 23) {
        oraSveglia = 0;
      }
      break;

    case MODIFICA_MINUTI:
      minutoSveglia++;

      if (minutoSveglia > 59) {
        minutoSveglia = 0;
      }
      break;

    case MODIFICA_STATO:
      svegliaAttiva = !svegliaAttiva;
      break;

    case MODALITA_OROLOGIO:
      break;
  }
}

void gestisciPulsanteStop() {
  // Durante l'allarme, il pulsante spegne il buzzer
  if (allarmeInCorso) {
    fermaAllarme();
    return;
  }

  // Nella schermata dello stato permette
  // di attivare o disattivare la sveglia.
  if (modalitaAttuale == MODIFICA_STATO) {
    svegliaAttiva = !svegliaAttiva;
  }
}

void controllaSveglia(const DateTime& adesso) {
  // Quando cambia il minuto, permette una nuova
  // attivazione futura della sveglia.
  if (adesso.second() > 5) {
    attivataQuestoMinuto = false;
  }

  // Controlla tutte le condizioni necessarie
  // per avviare l'allarme.
  if (svegliaAttiva &&
      !allarmeInCorso &&
      !attivataQuestoMinuto &&
      adesso.hour() == oraSveglia &&
      adesso.minute() == minutoSveglia &&
      adesso.second() == 0) {
    avviaAllarme();
  }
}

void avviaAllarme() {
  allarmeInCorso = true;
  attivataQuestoMinuto = true;
  ultimoCambioSuono = millis();
  tonoAlto = false;

  // Avvia immediatamente il primo tono
  tone(PIN_BUZZER, 1000);
}

void fermaAllarme() {
  // Interrompe qualsiasi frequenza generata
  noTone(PIN_BUZZER);
  allarmeInCorso = false;
}

void gestisciSuono() {
  if (!allarmeInCorso) {
    return;
  }

  // Alterna due frequenze per rendere
  // il suono più riconoscibile.
  if (millis() - ultimoCambioSuono >= INTERVALLO_SUONO) {
    ultimoCambioSuono = millis();
    tonoAlto = !tonoAlto;

    if (tonoAlto) {
      tone(PIN_BUZZER, 1500);
    } else {
      tone(PIN_BUZZER, 1000);
    }
  }
}

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

  if (allarmeInCorso) {
    mostraAllarme(adesso);
  } else if (modalitaAttuale == MODALITA_OROLOGIO) {
    mostraOrologio(adesso);
  } else {
    mostraConfigurazione();
  }

  display.display();
}

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

  // Titolo e stato della sveglia
  display.setCursor(0, 0);
  display.print("OROLOGIO");

  display.setCursor(91, 0);

  if (svegliaAttiva) {
    display.print("ON");
  } else {
    display.print("OFF");
  }

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

  // Ora corrente con caratteri grandi
  display.setTextSize(2);
  display.setCursor(16, 18);

  stampaDueCifre(adesso.hour());
  display.print(":");
  stampaDueCifre(adesso.minute());
  display.print(":");
  stampaDueCifre(adesso.second());

  // Data corrente
  display.setTextSize(1);
  display.setCursor(0, 44);
  display.print("Data: ");

  stampaDueCifre(adesso.day());
  display.print("/");
  stampaDueCifre(adesso.month());
  display.print("/");
  display.print(adesso.year());

  // Orario programmato
  display.setCursor(0, 56);
  display.print("Sveglia: ");

  stampaDueCifre(oraSveglia);
  display.print(":");
  stampaDueCifre(minutoSveglia);
}

void mostraConfigurazione() {
  display.setTextSize(1);
  display.setCursor(0, 0);
  display.print("IMPOSTA SVEGLIA");

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

  // Mostra sempre l'orario programmato
  display.setTextSize(2);
  display.setCursor(34, 20);

  stampaDueCifre(oraSveglia);
  display.print(":");
  stampaDueCifre(minutoSveglia);

  display.setTextSize(1);

  // Indica quale parametro è selezionato
  if (modalitaAttuale == MODIFICA_ORA) {
    display.setCursor(15, 44);
    display.print("> Modifica ORE");
  } else if (modalitaAttuale == MODIFICA_MINUTI) {
    display.setCursor(11, 44);
    display.print("> Modifica MINUTI");
  } else if (modalitaAttuale == MODIFICA_STATO) {
    display.setCursor(6, 44);
    display.print("> Sveglia: ");

    if (svegliaAttiva) {
      display.print("ATTIVA");
    } else {
      display.print("SPENTA");
    }
  }

  display.setCursor(0, 56);
  display.print("MODE avanti  + cambia");
}

void mostraAllarme(const DateTime& adesso) {
  // Disegna un bordo attorno alla schermata
  display.drawRect(
    0,
    0,
    128,
    64,
    SSD1306_WHITE
  );

  display.setTextSize(2);
  display.setCursor(25, 8);
  display.print("SVEGLIA");

  // Mostra l'ora corrente
  display.setCursor(34, 30);
  stampaDueCifre(adesso.hour());
  display.print(":");
  stampaDueCifre(adesso.minute());

  display.setTextSize(1);
  display.setCursor(18, 53);
  display.print("Premi STOP");
}

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

  display.print(valore);
}

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

  display.setCursor(15, 17);
  display.print("Sveglia Arduino");

  display.setCursor(31, 33);
  display.print("RTC DS3231");

  display.setCursor(28, 49);
  display.print("Progetto 127");

  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
​

Il modulo DS3231 fornisce continuamente l’ora reale.
Arduino confronta ore e minuti correnti con quelli impostati per la sveglia.
​
Quando i valori coincidono e i secondi sono uguali a zero, il buzzer viene attivato.
Il display mostra contemporaneamente:
  • ora corrente;
  • data;
  • orario della sveglia;
  • stato attivo o disattivato.
👉 La sveglia viene avviata una sola volta durante quel minuto, evitando riattivazioni continue.

🎛️ Programmazione della sveglia
​

Premendo il pulsante MODALITÀ si entra nella configurazione.
​
Le schermate vengono mostrate in questo ordine:
  1. regolazione delle ore;
  2. regolazione dei minuti;
  3. attivazione o disattivazione;
  4. ritorno all’orologio.
​
Nella schermata delle ore, il pulsante AUMENTA modifica il valore da 0 a 23.
Nella schermata dei minuti modifica invece il valore da 0 a 59.
Quando viene superato il valore massimo, il conteggio riparte da zero.

💾 Salvataggio nella EEPROM
​

Ore, minuti e stato della sveglia vengono salvati nella memoria EEPROM di Arduino.
​
La EEPROM mantiene i dati anche quando la scheda viene spenta.
Il programma utilizza tre indirizzi:
EEPROM.update(0, oraSveglia);
EEPROM.update(1, minutoSveglia);
EEPROM.update(2, svegliaAttiva);


La funzione EEPROM.update() scrive il dato soltanto quando è differente da quello già presente.
👉 Questo riduce il numero di scritture e prolunga la durata della memoria.

🛑 Arresto della sveglia
​

Quando il buzzer suona, premi il pulsante STOP.
Arduino:
  • interrompe il tono;
  • disattiva lo stato di allarme;
  • mantiene programmata la sveglia per il giorno successivo.
La sveglia non riparte nello stesso minuto grazie a una variabile che memorizza l’ultima attivazione.

🔁 Riattivazione giornaliera
​

Quando cambia il minuto, Arduino permette nuovamente l’attivazione futura dell’allarme.
La sveglia rimane quindi programmata ogni giorno allo stesso orario fino a quando non viene disattivata manualmente.

⚠️ Problemi comuni
​

Il display non mostra nulla
Controlla:
  • alimentazione del display;
  • collegamenti SDA e SCL;
  • indirizzo I2C 0x3C;
  • installazione delle librerie.

Il DS3231 non viene rilevato
Controlla:
  • collegamenti I2C;
  • alimentazione del modulo;
  • cavetti;
  • batteria CR2032.

Il buzzer non emette suoni
Controlla:
  • polarità del buzzer;
  • collegamento al pin 8;
  • collegamento a GND;
  • tipo di buzzer utilizzato.
Il codice è progettato per un buzzer passivo. Con un buzzer attivo il comportamento potrebbe essere differente.

I pulsanti cambiano più valori
Il codice utilizza un controllo antirimbalzo. Se necessario, aumenta leggermente il valore:
const unsigned long TEMPO_DEBOUNCE = 180;

La sveglia non mantiene le impostazioniControlla che il programma abbia caricato valori validi dalla EEPROM.
Al primo avvio vengono utilizzate automaticamente le impostazioni predefinite:
  • ore: 7;
  • minuti: 30;
  • sveglia attiva.

🧠 Perché è un progetto importante
​

Con questo progetto impari a:
  • utilizzare il modulo RTC DS3231
  • programmare un orario tramite pulsanti
  • creare più modalità operative
  • utilizzare un buzzer passivo
  • generare suoni con tone()
  • salvare dati nella EEPROM
  • controllare un evento in base all’ora
  • utilizzare millis() per più operazioni
  • realizzare un’interfaccia di configurazione
  • evitare attivazioni ripetute dell’allarme
👉 Queste tecniche saranno utili nel prossimo progetto dedicato al timer settimanale con RTC.

🔄 Varianti possibili
​

Vuoi migliorare il progetto?
  • 😴 aggiungi la funzione snooze
  • 🔽 inserisci un pulsante per diminuire i valori
  • 📆 programma giorni diversi della settimana
  • 🔔 crea più orari di sveglia
  • 🎵 aggiungi melodie differenti
  • 💡 accendi gradualmente un LED
  • 🌙 riduci la luminosità del display di notte
  • 🌡️ mostra anche la temperatura del DS3231
  • 📟 utilizza un display OLED più grande
  • 📶 sincronizza automaticamente l’orario tramite Internet
  • 🔋 aggiungi un indicatore di batteria
  • 🎚️ sostituisci i pulsanti con un encoder rotativo

Foto
Foto

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