Orologio con Arduino

In questo articolo ti mostro come è possibile realizzare un orologio con Arduino.
DigitSpace
Prima di passare al contenuto è doveroso ringraziare il sito DigitSpace per avermi fornito parte del materiale di questo progetto.
Come promesso iniziamo a fare qualcosa di più interessante mettendo assieme quelle che sono state le conoscenze apprese nei precedenti articoli.
Abbiamo visto come collegare un display OLED ad Arduino, quindi abbiamo giocato un pò con un encoder rotativo e scoperto come interfacciare il modulo RTC DS1307 al micro controllore.
Bene!
A questo punto possiamo pensare di mettere insieme queste nozioni per realizzare qualcosa di più intrigante.
Premessa
Di certo lo scopo dell’articolo non è quello di farti risparmiare i costi relativi all’acquisto di un orologio.
Non è costruendoci da soli una sveglia che risolleveremo le nostre economie, ma di certo sarà un ottimo spunto per tutti quei progetti in cui vorremo far comparire a “video” informazioni relative alla data e all’ora con possibilità (ed è questa la parte interessante) di regolazione senza l’ausilio del PC.
In Breve
Mettendo assieme quindi quello che ti ho mostrato nei precedenti articoli, andremo a realizzare un orologio costituito da un display OLED 128x64px per mostrare a video la data e l’ora, un modulo RTC DS1307 per la parte di gestione del tempo, ed un encoder rotativo HW-040/YK-040 per la regolazione ed il salvataggio delle impostazioni.
Codice orologio con Arduino
Il codice è abbastanza semplice, solo che per via dei commenti può sembrare un po complesso. In realtà non lo è, quindi magari ti consiglio di ripulirlo e tenere a fianco la versione commentata per capire riga dopo riga cosa ho fatto e perché.
/*
Orologio con Arduino
Autore : Andrea Lombardo
Web : http://www.lombardoandrea.com
Post : https://wp.me/p27dYH-Q2
*/
// Inclusione librerie
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <RTClib.h>
#include <Bounce2.h>
/*
Definisco le dimensioni del display, serviranno per creare l'istanza del display
e magari riutilizzarle nel codice qualora dovessero servirmi queste informazioni
*/
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
// Delay del debounce per il bottone "mode"
#define DEBOUNCE_DELAY 15
/*
Per alleggerire il numero di operazioni da far eseguire ad Arduino
limito la lettura dei dati dal modulo RTC ad ogni secondo piUttosto
che ad ogni ciclo del loop, tanto sarebbe inutile.
*/
#define DELAY_RTC_READINGS 1000
// Definisco pin per encoder rotativo KY-040 / HW-040
const unsigned int pinClk = 2;
const unsigned int pinDt = 3;
const unsigned int pinSwMode = 5;
// Creo un enum per definire due modalità "user-friendly"
typedef enum Mode {
MODE_NORMALE,
MODE_REGOLA
};
/*
In base allo stato di questa variabile siamo in modalità
"Regolazione" o "Normale"
*/
Mode mode = MODE_NORMALE; // Do per scontato che sono in modalità "Normale"
// Creo istanza del display
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT);
// Creo istanza modulo DS1307
RTC_DS1307 rtc;
// Creo istanza pulsante (incorporato nell'encoder)
Bounce btnMode = Bounce();
// Conservo istante ultima lettura dal modulo RTC
unsigned long lastRTCReads;
// Conservo ultima posizione del pin Clk dell'encoder
unsigned int prevClk;
/*
Contatore dell'encoder che verrà utilizzato
in fase di regolazione della data/ora
*/
unsigned int countEncoder;
/*
Da quanti step è composta la nostra fase di regolazione?
1 = REGOLO IL GIORNO
2 = REGOLO IL MESE
3 = REGOLO L'ANNO
4 = REGOLO L'ORA
5 = REGOLO I MINUTI
6 = REGOLO I SECONDI
*/
const unsigned int numStep = 6;
// Tengo traccia dello step corrente durante fase di regolazione
unsigned int stepRegolazione = 0;
/*
Creo un array che conterrà i valori numerici durante la reimpostazione della data/ora
La classe DateTime prende in considerazione gli anni dal 2000 al 2099. Ce li faremo bastare!
*/
int newDateTime[numStep] = {1, 1, 20, 0, 0, 0};
void setup() {
//Definizione modalità dei pin
pinMode(pinClk, INPUT);
pinMode(pinDt, INPUT);
pinMode(pinSwMode, INPUT_PULLUP);
btnMode.attach(pinSwMode);
btnMode.interval(DEBOUNCE_DELAY);
/*
Per essere sicuro che vengano intercettati tutti i cambiamenti di stato dell'encoder
sfrutto le potenzialità degli interrupt di Arduino.
*/
attachInterrupt(digitalPinToInterrupt(pinClk), checkEncoder, CHANGE);
//Provo ad inizializzare il display all'indirizzo 0x3C (il tuo potrebbe essere diverso)
if (!display.begin( SSD1306_SWITCHCAPVCC, 0x3C)) {
/*
Se non sono riuscito ad inizializzare il display
creo un loop infinito ed impedisco al programma di andare avanti
*/
while (true);
}
// Pulisco il buffer
display.clearDisplay();
// Applico la pulizia al display
display.display();
//Inizializza comunicazione I2C con modulo DS1307
rtc.begin();
/*
Quando il modulo viene acceso per la prima volta o risulta essere sconfigurato
a causa della perdita della memoria (esempio batteria scarica)
il metodo rtc.isrunning() restituisce false
Ho scritto un funzione per essere utilizzata sia qui in fase di setup
sia durante l'esecuzione del programma.
Se il modulo è sconfigurato passa in automatico in modalità "Regolazione"
*/
checkRTC();
//Inizializzo variabili
lastRTCReads = millis();
//Eseguo prima lettura del valore del pin Clk dell'encoder
prevClk = digitalRead(pinClk);
// Inizializzo la variabile contatore dell'encoder
countEncoder = 1;
}
void loop() {
// Aggiorna lettura del bottone "mode"
btnMode.update();
if (mode == MODE_REGOLA) { // Se ci troviamo in modalità di regolazione
/*
Per comodità e pulizia del codice
sposto le azioni di regolazione in un altra funzione
*/
editMode();
} else { // Se ci troviamo in modalità normale
/*
Per comodità e pulizia del codice
sposto le azioni della fase normale in un altra funzione
*/
normalMode();
}//Fine modalità normale
}//Fine loop
/*
Interpreta i movimenti dell'encoder
Maggiori info qui -> https://wp.me/p27dYH-PP
Questa funzione viene chiamata tramite interrupt
*/
void checkEncoder() {
int currClk = digitalRead(pinClk);
int currDt = digitalRead(pinDt);
if (currClk != prevClk) {
if (currDt == currClk) {
countEncoder --;
} else {
countEncoder ++;
}
prevClk = currClk;
}
}
/*
Operazioni da eseguire quando siamo in modalità normale
*/
void normalMode() {
/*
Se siamo in modalità normale la pressione
del bottone mode ci fa passare in modalità "Regolazione"
*/
if (btnMode.fell()) {
mode = MODE_REGOLA;
// Resetta contatore encoder e contatore step prima di passare in modalità regolazione
countEncoder = 1;
stepRegolazione = 0;
}
if (millis() - lastRTCReads >= DELAY_RTC_READINGS) {
// Aggiorna variabile per reimpostare il delay del prossimo ciclo
lastRTCReads = millis();
// Ripulisco display ad ogni ciclo
display.clearDisplay();
// Mostro a video contenuti statici
printStaticContent();
/*
Ad ogni passaggio controlla se il modulo RTC è ancora
in buone condizioni o si è sconfigurato.
Se si è sconfigurato passerò in modalità "Regolazione"
*/
checkRTC();
// Eseguo lettura valori dal modulo RTC
DateTime data = rtc.now();
/*
Formati passati al metodo toString() della classe DateTime
per ottenere due stringhe da stampare in due sezioni differenti del display.
*/
char formatoData[] = "DD-MM-YYYY";
char formatoOra[] = "hh:mm:ss";
display.setTextColor(WHITE);
display.setTextSize(2);
display.setCursor(4, 22);
display.print(data.toString(formatoData));
display.setCursor(16, 40);
display.print(data.toString(formatoOra));
//Mando in stampa le modifiche
display.display();
}
}
/*
Operazioni da eseguire quando siamo in modalità Regolazione
*/
void editMode() {
// Ripulisco display ad ogni ciclo
display.clearDisplay();
// Setto dimensione font e colore
display.setTextSize(2);
display.setTextColor( WHITE);
// Mi posiziono nella parte alta del display
display.setCursor(0, 0);
// In base al numero dello step mostro e regolo una porzione della data/ora
switch (stepRegolazione) {
case 0:
// Se siamo in posizione 0 vogliamo regolare il giorno
// E facciamo si che non si vada oltre i valori consentiti per il numero relativo al giorno
if (countEncoder > 31 ) {
countEncoder = 1;
} else if ( countEncoder < 1) {
countEncoder = 31;
}
display.print("SET GIORNO");
if (countEncoder < 10) {
display.setCursor((SCREEN_WIDTH / 2 ) - 10, 24);
} else {
display.setCursor((SCREEN_WIDTH / 2 ) - 21, 24);
}
display.setTextSize(4);
display.print(countEncoder);
newDateTime[stepRegolazione] = countEncoder;
// Alla pressione del pomello vado avanti con gli step e reimposto il contatore
if (btnMode.fell()) {
countEncoder = 1;
stepRegolazione++;
}
break;
case 1:
// Se siamo in posizione 1 vogliamo regolare il mese
// E facciamo si che non si vada oltre i valori consentiti per il numero relativo al mese
if (countEncoder > 12 ) {
countEncoder = 1;
} else if ( countEncoder < 1) {
countEncoder = 12;
}
display.print("SET MESE");
if (countEncoder < 10) {
display.setCursor((SCREEN_WIDTH / 2 ) - 10, 24);
} else {
display.setCursor((SCREEN_WIDTH / 2 ) - 21, 24);
}
display.setTextSize(4);
display.print(countEncoder);
newDateTime[stepRegolazione] = countEncoder;
// Alla pressione del pomello vado avanti con gli step e reimposto il contatore
if (btnMode.fell()) {
countEncoder = 1;
stepRegolazione++;
}
break;
case 2:
// Se siamo in posizione 2 vogliamo regolare l'anno
// E facciamo si che non si vada oltre i valori consentiti dalla classe DateTime 2000 - 2099
if (countEncoder > 99 ) {
countEncoder = 0;
} else if ( countEncoder < 0) {
countEncoder = 99;
}
display.print("SET ANNO");
if (countEncoder < 10) {
display.setCursor((SCREEN_WIDTH / 2 ) - 10, 24);
} else {
display.setCursor((SCREEN_WIDTH / 2 ) - 21, 24);
}
display.setTextSize(4);
display.print(countEncoder);
newDateTime[stepRegolazione] = countEncoder;
// Alla pressione del pomello vado avanti con gli step e reimposto il contatore
if (btnMode.fell()) {
countEncoder = 1;
stepRegolazione++;
}
break;
case 3:
// Se siamo in posizione 3 vogliamo regolare l'ora
// E facciamo si che non si vada oltre i valori consentiti per il numero relativo all'ora
if (countEncoder > 23 ) {
countEncoder = 0;
} else if ( countEncoder < 0) {
countEncoder = 23;
}
display.print("SET ORA");
if (countEncoder < 10) {
display.setCursor((SCREEN_WIDTH / 2 ) - 10, 24);
} else {
display.setCursor((SCREEN_WIDTH / 2 ) - 21, 24);
}
display.setTextSize(4);
display.print(countEncoder);
newDateTime[stepRegolazione] = countEncoder;
// Alla pressione del pomello vado avanti con gli step e reimposto il contatore
if (btnMode.fell()) {
countEncoder = 0;
stepRegolazione++;
}
break;
case 4:
// Se siamo in posizione 4 vogliamo regolare i minuti
// E facciamo si che non si vada oltre i valori consentiti per il numero relativo ai minuti
if (countEncoder > 59 ) {
countEncoder = 0;
} else if ( countEncoder < 0) {
countEncoder = 59;
}
display.print("SET MINUTI");
if (countEncoder < 10) {
display.setCursor((SCREEN_WIDTH / 2 ) - 10, 24);
} else {
display.setCursor((SCREEN_WIDTH / 2 ) - 21, 24);
}
display.setTextSize(4);
display.print(countEncoder);
newDateTime[stepRegolazione] = countEncoder;
// Alla pressione del pomello vado avanti con gli step e reimposto il contatore
if (btnMode.fell()) {
countEncoder = 0;
stepRegolazione++;
}
break;
case 5:
// Se siamo in posizione 5 vogliamo regolare i secondi (anche se francamente me lo eviterei)
// E facciamo si che non si vada oltre i valori consentiti per il numero relativo ai secondi
if (countEncoder > 59 ) {
countEncoder = 0;
} else if ( countEncoder < 0) {
countEncoder = 59;
}
display.setTextSize(1);
display.print("SET ");
display.setTextSize(2);
display.print("SECONDI");
if (countEncoder < 10) {
display.setCursor((SCREEN_WIDTH / 2 ) - 10, 24);
} else {
display.setCursor((SCREEN_WIDTH / 2 ) - 21, 24);
}
display.setTextSize(4);
display.print(countEncoder);
newDateTime[stepRegolazione] = countEncoder;
// Alla pressione del pomello vado avanti con gli step e reimposto il contatore
if (btnMode.fell()) {
countEncoder = 1;
stepRegolazione++;
}
break;
case 6:
/*
Se siamo in posizione 6 abbiamo finito di regolare l'orologio
quindi mostriamo un prompt di conferma ed in caso di risposta affermativa
salviamo le modifiche
*/
if (countEncoder > 1 ) {
countEncoder = 0;
} else if ( countEncoder < 0) {
countEncoder = 1;
}
display.print("CONFERMI?");
display.setCursor(10, 24);
display.setTextSize(2);
if (countEncoder) {
display.setTextColor(BLACK, WHITE);
display.print(" SI ");
display.setTextColor(WHITE);
display.print(" NO ");
} else {
display.setTextColor( WHITE);
display.print(" SI ");
display.setTextColor(BLACK, WHITE);
display.print(" NO ");
display.setTextColor( WHITE);
}
/*
Alla pressione del pomello:
se il valore del contatore è 1 allora salvo
altrimenti abbiamo perso solo tempo ;-)
*/
if (btnMode.fell()) {
if (countEncoder) {
/*
SALVO LE IMPOSTAZIONI
Uno dei formati accettai per l'istanza dalla classe DateTime è quello americano
DateTime(uint16_t year, uint8_t month, uint8_t day, uint8_t hour, uint8_t min, uint8_t sec)
*/
rtc.adjust(DateTime(newDateTime[2], newDateTime[1], newDateTime[0], newDateTime[3], newDateTime[4], newDateTime[5]));
}
// Ritorno in modalità normale
mode = MODE_NORMALE;
}
break;
}
//Mando in stampa le modifiche al display
display.display();
}
/*
Per comodità creo una funzione per disegnare sul display
eventuali contenuti statici come linee o scritte fisse
che rimarranno inalterate per tutta l'esecuzione del programma (o parte)
In questo caso disegno un rettangolo alto 16px e lungo 128px
e lo posiziono nella parte più alta del display.
Al suo interno inserisco una scritta in negativo e la posiziono
al centro.
*/
void printStaticContent() {
display.fillRect(0, 0, SCREEN_WIDTH, 16, WHITE);
display.setTextColor(BLACK, WHITE);
display.setTextSize(1);
display.setCursor(10, 4);
display.print("LOMBARDOANDREA.COM");
}
/*
Controlla se il modulo RTC è configurato.
Se non lo è setta la modalità in "Regolazione"
*/
void checkRTC() {
if (!rtc.isrunning()) {
mode = MODE_REGOLA;
countEncoder = 1;
stepRegolazione = 0;
}
}
Schema orologio con Arduino
Come visto in precedenza sia il display, sia il modulo RTC, sfruttano l’interfaccia I2C per la comunicazione con Arduino, quindi per comodità di collegamento ho collegato “in cascata” al modulo RTC 1307 il display OLED.

Orologio con Arduino funzionamento
Cosa accadrà quindi una volta messo in moto?
- Controllo stato di configurazione modulo RTC all’avvio.
- Se modulo OK tutti contenti.
- Se modulo non configurato entra in modalità REGOLAZIONE.
- Ruotando l’encoder definisco il numero da assegnare alla porzione della data che sto configurando.
- Ad ogni pressione del pomello passo alla porzione di data successiva.
- Se ho completato tutti gli step di configurazione, mi verrà chiesta conferma per il salvataggio.
- Se tutto ok torna in modalità NORMALE.
- Per entrare in modalità REGOLAZIONE manualmente durante la fase NORMALE, premo il pomello.
Non abbiamo di certo scoperto l’acqua calda, ne tantomeno reinventato la ruota, abbiamo semplicemente visto un sistema, a mio avviso semplice, per gestire e regolare un orologio all’interno dei nostri progetti con Arduino.
Inoltre ho giocato un po con il display per creare il prompt di conferma con i “bottoni” SI e NO che si evidenziano quando selezionati.
A fine pagina trovi il link per scaricare il pacchetto con codici e schemi di collegamento. Come sempre ti ricordo che acquistando prodotti Amazon passando attraverso i link del mio sito, io percepisco una piccola commissione (parliamo di centesimi) in buoni regalo. Questi buoni sommati alle eventuali donazioni PayPal, servono a mantenere attivo il sito web e ad acquistare nuovi componenti.
RUNCCI-YUN 6PCS ky-040 modulo encoder rotativo con 15 × 16.5 mm con tappo manopola (confezione da 6)
10,95 € (1,82 € / unità)AZDelivery 3 x Moduli Codificatore a Rotazione Codificatore Encoder Rotativo KY-040 compatibile con Arduino incluso un E-Book!
8,99 €QWORK 5pcs KY-040 360 gradi Modulo encoder rotativo con tappo a manopola per Arduino
9,45 €RUNCCI-YUN 10pcs Encoder Rotativo EC11, 360 Gradi Rotary Encoder Modulo Encoder Rotativo Potenziometro Digitale EC11 con Interruttore e Manopole Tappo per Arduino
10,99 €2 Pezzi AS5600 Encoder Magnetico, Modulo sensore Magnetico per Arduino di Induzione 12 Bit Ad Alta Precisione
6,99 €eMagTech 4Pcs DS1307 RTC Modulo Orologio In Tempo Reale Chip Orologio In Tempo Reale I2C 28x27x9mm Compatibile con Raspberry Pi ESP E Molti Altri Senza Batteria
12,09 €DollaTek Tiny RTC I2C DS1307 AT24C32 Modulo Orologio in Tempo Reale per Arduino AVR Arm PIC 51
5,99 €AZDelivery 5 x DS1302 Orologio seriale in tempo reale RTC compatibile con Arduino e Raspberry Pi incluso un E-Book!
9,99 €Circuito Integrato DS1307 RTC Real Time Clock Orologio pc per Arduino ds1307n
1,99 € (a partire da 12 Novembre 2025 01:47 GMT +01:00 - Altre informazioniProduct prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on [relevant Amazon Site(s), as applicable] at the time of purchase will apply to the purchase of this product.)Aihasd 3 pezzi I2C DS1307 AT24C32 modulo orologio orario reale
6,99 €Auto Amazon Links: Nessun prodotto trovato.




















































![Arduino Nano [A000005] - Scheda di sviluppo compatta e potente, compatibile con Arduino IDE, ideale per progetti elettronici, robot, PLC e applicazioni fai da te. #1](https://m.media-amazon.com/images/I/51p0HZ18KtL._SL120_.jpg)
![Arduino Nano [A000005] - Scheda di sviluppo compatta e potente, compatibile con Arduino IDE, ideale per progetti elettronici, robot, PLC e applicazioni fai da te. #2](https://m.media-amazon.com/images/I/41g5pY8njrL._SL120_.jpg)
![Arduino Nano [A000005] - Scheda di sviluppo compatta e potente, compatibile con Arduino IDE, ideale per progetti elettronici, robot, PLC e applicazioni fai da te. #3](https://m.media-amazon.com/images/I/51IfbNowHgL._SL120_.jpg)
![Arduino Nano [A000005] - Scheda di sviluppo compatta e potente, compatibile con Arduino IDE, ideale per progetti elettronici, robot, PLC e applicazioni fai da te. #4](https://m.media-amazon.com/images/I/41ceSJfIfHL._SL120_.jpg)
![Arduino Nano [A000005] - Scheda di sviluppo compatta e potente, compatibile con Arduino IDE, ideale per progetti elettronici, robot, PLC e applicazioni fai da te. #5](https://m.media-amazon.com/images/I/41TANpxmbzL._SL120_.jpg)
![Arduino Nano [A000005] - Scheda di sviluppo compatta e potente, compatibile con Arduino IDE, ideale per progetti elettronici, robot, PLC e applicazioni fai da te. #6](https://m.media-amazon.com/images/I/41mGAFfpn9L._SL120_.jpg)


























RSS - Articoli
Commentati Recentemente