🚀 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.
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:
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
🛒 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
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:
Per installare le altre librerie:
Per realizzare il progetto devi installare:
- RTClib
- Adafruit SSD1306
- Adafruit GFX Library
- Wire
- EEPROM
Per installare le altre librerie:
- apri Arduino IDE;
- vai su Sketch → Include Library → Manage Libraries;
- cerca RTClib;
- installa la libreria sviluppata da Adafruit;
- cerca Adafruit SSD1306;
- installa la libreria;
- verifica che sia presente anche Adafruit GFX Library.
🔌 Schema di collegamento
Display OLED SSD1306
Modulo RTC DS3231
Il display OLED e il modulo RTC condividono gli stessi pin I2C.
I due dispositivi possono funzionare contemporaneamente perché utilizzano indirizzi differenti:
Pulsante MODALITÀ
Pulsante AUMENTA
Pulsante STOP
Nella schermata di configurazione permette inoltre di attivare o disattivare la sveglia.
Buzzer passivo
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
Pulsante AUMENTA
- un terminale → pin digitale 3
- terminale opposto → GND
Pulsante STOP
- un terminale → pin digitale 4
- terminale opposto → GND
Nella schermata di configurazione permette inoltre di attivare o disattivare la sveglia.
Buzzer passivo
- terminale positivo → pin digitale 8
- terminale negativo → GND
💻 Codice Arduino
Il programma utilizza quattro schermate:
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.
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();
}
============================================================
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:
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.
🎛️ Programmazione della sveglia
Premendo il pulsante MODALITÀ si entra nella configurazione.
Le schermate vengono mostrate in questo ordine:
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.
Premendo il pulsante MODALITÀ si entra nella configurazione.
Le schermate vengono mostrate in questo ordine:
- regolazione delle ore;
- regolazione dei minuti;
- attivazione o disattivazione;
- 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.
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:
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.
🔁 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.
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:
Il DS3231 non viene rilevato
Controlla:
Il buzzer non emette suoni
Controlla:
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:
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.
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:
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
🔄 Varianti possibili
Vuoi migliorare il progetto?
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