Arduino UNO R4 WiFi possiede un RTC interno facilmente programmabile che ci consentirà di mantenere costantemente traccia dell’ora e della data corrente.
Per chi ha iniziato da poco le sperimentazioni elettroniche ricordo che un Real-Time Clock (RTC), o Orologio in Tempo Reale, è un tipo di orologio costituito da un circuito elettronico utilizzato per tracciare il tempo in tempo reale. Questo significa che tiene traccia del giorno della settimana, della data e dell’ora corrente, dei minuti, dei secondi, proprio come un orologio normale, inoltre è possibile impostare un RTC per gestire l’ora legale e l’ora solare.
Nelle versione precedente di Arduino, UNO R3 non era presente un RTC pertanto bisognava utilizzare un apposito circuito elettronico esterno così come dettagliato nel post su questo sito: Utilizzare un orologio RTC con Arduino – Modulo Tiny RTC I2C, modulo RTC dotato di un integrato DS1307 cuore fondamentale della scheda.
L’utilizzo dell’RTC su Arduino UNO R4 WiFi avviene utilizzando la libreria RTC che consente di impostare oppure ottenere l’orario o ancora gestire allarmi per attivare interrupt.
Come accennato ad inizio post l’RTC integrato dispone di un pin VRTC, che viene utilizzato per mantenere in funzione l’RTC, anche quando l’alimentazione della scheda viene interrotta. Per utilizzare questa funzione è sufficiente fornire una tensione compresa tra 1,6 e 3,6 V al pin VRTC. In un post successivo mostrerò come utilizzare il pin VRTC.
Facendo riferimento agli esempi disponibili sul sito Arduino e nell’IDE analizziamo le fasi di configurazione dell’RTC.
Impostazione della data e dell’ora
RTCTime startTime(01, Month::AUGUST, 2023, 20, 49, 00, DayOfWeek::TUESDAY, SaveLight::SAVING_TIME_ACTIVE) RTC.setTime(startTime)
Per impostare l’orario bisogna creare un oggetto RTCTime, in cui deve essere specificato il giorno, il mese, l’anno, l’ora, il minuto, il secondo, il giorno della settimana e l’attivazione dell’ora legale se prevista nella nazione in cui si sta utilizzando la scheda, quindi per impostare l’orario bisogna usare il metodo startTime.
Per chi incomincia con la programmazione il concetto di metodo appartiene alla programmazione ad orientata agli oggetti come ad esempio in C++, quando si programma in C è meglio parlare di funzione, ma spesso i due concetti vengono usati in modo alternativo.
Il primo sketch non fa altro che impostare l’ora corrente:
// inclusione della libreria RTC #include "RTC.h" void setup() { // impostazione della velocità della serial monitor Serial.begin(9600); // avvio dell'RTC RTC.begin(); // creazione dell'oggetto RTCTime (possiamo assegnare un nome a piacimento) // data del giorno, mese, anno, ore, minuti, secondi, giorno della settimana, attivazione passaggio all'ora legale RTCTime startTime(2, Month::AUGUST, 2023, 9, 15, 00, DayOfWeek::WEDNESDAY, SaveLight::SAVING_TIME_ACTIVE); // impostazione dell'RTC con la data e lora configurate per RTCTime RTC.setTime(startTime); } // il loop non contiene nulla void loop() { }
Leggere data e ora
Per recuperare l’ora e la data corrente bisogna usare la funzione:
RTC.getTime(currentTime)
è necessario creare un oggetto RTCTime, così come abbiamo fatto nello sketch precedente, usiamo il metodo getTime() per ottenere ora e data corrente:
#include "RTC.h" void setup() { // impostazione della velocità della serial monitor Serial.begin(9600); // avvio dell'RTC RTC.begin(); // creazione dell'oggetto RTCTime (possiamo assegnare un nome a piacimento) // data del giorno, mese, anno, ore, minuti, secondi, giorno della settimana, attivazione passaggio all'ora legale RTCTime startTime(2, Month::AUGUST, 2023, 9, 15, 00, DayOfWeek::WEDNESDAY, SaveLight::SAVING_TIME_ACTIVE); // impostazione dell'RTC con la data e lora configurate per RTCTime RTC.setTime(startTime); } void loop() { // Assegnamo alla variabile currentTime il tipo (oggetto) RTCTime RTCTime currentTime; // Ottieni l'orario corrente dall'RTC RTC.getTime(currentTime); }
Stampa della data e dell’ora
Gli esempi indicati sopra mostrano come impostare e ottenere l’orario e memorizzarlo in un oggetto. Questi dati possono essere recuperati attraverso diversi metodi:
getDayOfMonth() // giorno del mese getMonth() // mese getYear() // anno getHour() // ora getMinutes() // minuti getSeconds() // secondi
L’esempio che segue stampa data ed ora utilizzando l’oggetto currentTime:
// inclusione della libreria RTC #include "RTC.h" void setup() { // impostazione della velocità della serial monitor Serial.begin(9600); // avvio dell'RTC RTC.begin(); // creazione dell'oggetto RTCTime (possiamo assegnare un nome a piacimento) // data del giorno, mese, anno, ore, minuti, secondi, giorno della settimana, attivazione passaggio all'ora legale RTCTime startTime(2, Month::AUGUST, 2023, 12, 43, 00, DayOfWeek::WEDNESDAY, SaveLight::SAVING_TIME_ACTIVE); // impostazione dell'RTC con la data e lora configurate per RTCTime RTC.setTime(startTime); } void loop() { // Assegnamo alla variabile currentTime il tipo (oggetto) RTCTime RTCTime currentTime; // Ottieni l'orario corrente dall'RTC RTC.getTime(currentTime); // Stampa la data (DD/MM//YYYY) Serial.print(currentTime.getDayOfMonth()); Serial.print("/"); Serial.print(Month2int(currentTime.getMonth())); Serial.print("/"); Serial.print(currentTime.getYear()); Serial.print(" - "); // Stampa l'ora (HH/MM/SS) Serial.print(currentTime.getHour()); Serial.print(":"); Serial.print(currentTime.getMinutes()); Serial.print(":"); Serial.println(currentTime.getSeconds()); // attesa di 1 secondo delay(1000); }
Tempo Unix
Nei sistemi operativi Unix e Unix-like, il tempo è indicato come un offset in secondi rispetto alla mezzanotte (UTC – Tempo coordinato universale o Tempo Cicile) del 1º gennaio 1970, un punto nel tempo noto come “epoca Unix”, questo numero viene chiamato anche timestamp.
Ad esempio, alle 03:46:40 CET del 9 settembre 2001, questo differenziale era esattamente un miliardo. Questo significa che in quel preciso momento erano passati un miliardo di secondi dall’inizio dell’epoca Unix. Per esprimere questo differenziale temporale, si utilizza il tipo di dato time_t.
Il timestamp nel momento in cui scrivo questa lezione, l’ora Unix, è:
Oggi è il 02/08/2023 e sono le 09:34:14
Timestamp: 1690961654
Se vuoi approfondire l’argomento segui il link.
Ma perché utilizzare un tempo Unix?
Come segnalato nel link sopra:
Questo tipo di rappresentazione, oltre che a essere compatta, è indipendente dai fusi orari, ed è quindi direttamente confrontabile anche tra calcolatori situati a grandi distanze geografiche tra loro, ed evita di dover effettuare aggiustamenti nel caso per esempio di dati trasmessi da un fuso orario all’altro. Lo svantaggio è che per averne una rappresentazione sotto forma di data e ora locali è necessario effettuare una conversione; il sistema operativo offre allo scopo delle funzioni che consentono di effettuarle in entrambe le direzioni.
Il codice per la stampa del timestamp Unix è:
// inclusione della libreria RTC #include "RTC.h" void setup() { // impostazione della velocità della serial monitor Serial.begin(9600); // avvio dell'RTC RTC.begin(); // creazione dell'oggetto RTCTime (possiamo assegnare un nome a piacimento) // data del giorno, mese, anno, ore, minuti, secondi, giorno della settimana, attivazione passaggio all'ora legale RTCTime startTime(2, Month::AUGUST, 2023, 12, 49, 00, DayOfWeek::WEDNESDAY, SaveLight::SAVING_TIME_ACTIVE); // impostazione dell'RTC con la data e lora configurate per RTCTime RTC.setTime(startTime); } void loop() { // Assegnamo alla variabile currentTime il tipo (oggetto) RTCTime RTCTime currentTime; // Ottieni l'orario corrente dall'RTC RTC.getTime(currentTime); //Ottiene il timestamp Unix Serial.print("Timestamp Unix: "); Serial.println(currentTime.getUnixTime()); // attesa di 1 secondo delay(1000); }
Ovviamente è possibile stampare con facilità entrambe le notazioni di tempo:
// inclusione della libreria RTC #include "RTC.h" void setup() { // impostazione della velocità della serial monitor Serial.begin(9600); // avvio dell'RTC RTC.begin(); // creazione dell'oggetto RTCTime (possiamo assegnare un nome a piacimento) // data del giorno, mese, anno, ore, minuti, secondi, giorno della settimana, attivazione passaggio all'ora legale RTCTime startTime(2, Month::AUGUST, 2023, 12, 51, 00, DayOfWeek::WEDNESDAY, SaveLight::SAVING_TIME_ACTIVE); // impostazione dell'RTC con la data e lora configurate per RTCTime RTC.setTime(startTime); } void loop() { // Assegnamo alla variabile currentTime il tipo (oggetto) RTCTime RTCTime currentTime; // Ottieni l'orario corrente dall'RTC RTC.getTime(currentTime); // Stampa la data (DD/MM//YYYY) Serial.print(currentTime.getDayOfMonth()); Serial.print("/"); Serial.print(Month2int(currentTime.getMonth())); Serial.print("/"); Serial.print(currentTime.getYear()); Serial.print(" - "); // Stampa l'ora (HH/MM/SS) Serial.print(currentTime.getHour()); Serial.print(":"); Serial.print(currentTime.getMinutes()); Serial.print(":"); Serial.println(currentTime.getSeconds()); // Ottiene il timestamp Unix Serial.print("Timestamp Unix: "); Serial.println(currentTime.getUnixTime()); // attesa di 1 secondo delay(1000); }
Visualizziamo data ed ora su un display
L’applicazione più semplice che possiamo realizzare è quella che permette di realizzare un semplice orologio mostrando data ed ora su un display 1602 di tipo I2C. Per l’utilizzo di un display I2C fare riferimento alle guide che trovate su questo sito.
Ricordate di impostare l’indirizzo corretto per l’LCD che potrebbe differire da quello inserito nei miei esempi.
La modifica al codice precedente consiste nell’aggiungere la libreria di gestione del display, la sua configurazione e successivamente sostituire il metodo serial.print con il metodo lcd.print. Nello sketch nei commenti trovate tutti i dettagli.
// Prof. Maffucci Michele // 02.08.23 // Realizzazione di un orologio con Arduino UNO R4 WiFi // inclusione della libreria RTC #include "RTC.h" #include <Wire.h> #include <LiquidCrystal_I2C.h> // inizializzazione della libreria in cui è descritta la modalità di utilizzo dei pin LiquidCrystal_I2C lcd(0x27, 16, 2); // impostazione dell'indirizzo dell'LCD 0x27 di 16 caratteri e 2 linee // prevDay variabile per memorizzare la data del giorno precedente // utilizzata per verificare il passaggio al giorno successivo // e cancellare il display per non avere stampe di doppie cifre // non cancellate int prevDay = 0; // prevHour variabile per memorizzare l'ora precedente // utilizzata per verificare il passaggio all'ora successivo // e cancellare il display per non avere stampe di doppie cifre // non cancellate int prevHour = 0; void setup() { // impostazione della velocità della serial monitor Serial.begin(9600); // inizializzazione dell'LCD lcd.begin(); // attivazione della retroilluminazione lcd.backlight(); // avvio dell'RTC RTC.begin(); // creazione dell'oggetto RTCTime (possiamo assegnare un nome a piacimento) // data del giorno, mese, anno, ore, minuti, secondi, giorno della settimana, attivazione passaggio all'ora legale RTCTime startTime(3, Month::AUGUST, 2023, 18, 59, 00, DayOfWeek::THURSDAY, SaveLight::SAVING_TIME_ACTIVE); // impostazione dell'RTC con la data e lora configurate per RTCTime RTC.setTime(startTime); // Testo di Avvio lcd.setCursor(0, 0); lcd.print("Maffucci Michele"); lcd.setCursor(0, 1); lcd.print("www.maffucci.it"); delay(2000); lcd.clear(); lcd.setCursor(0, 0); lcd.print("Orologio"); delay(2000); } void loop() { // Assegnamo alla variabile currentTime il tipo (oggetto) RTCTime RTCTime currentTime; // Ottieni l'orario corrente dall'RTC RTC.getTime(currentTime); // Stampa la data (DD/MM//YYYY) // verifica se si è pasati al giorno successivo // se ciò avviene si cancella il display per evitare // la visualizzazione di doppie cifre non cancellate if (currentTime.getDayOfMonth() != prevDay) { lcd.clear(); prevDay = currentTime.getDayOfMonth(); } else { lcd.setCursor(0, 0); lcd.print("Data: "); lcd.print(currentTime.getDayOfMonth()); lcd.print("/"); lcd.print(Month2int(currentTime.getMonth())); lcd.print("/"); lcd.print(currentTime.getYear()); // Stampa l'ora (HH/MM/SS) // verifica se si è pasati all'ora successiva // se ciò avviene si cancella il display per evitare // la visualizzazione di doppie cifre non cancellate if (currentTime.getHour() != prevHour) { lcd.clear(); prevHour = currentTime.getHour(); } else { lcd.setCursor(0, 1); lcd.print("Ora: "); lcd.setCursor(6, 1); lcd.print(currentTime.getHour()); lcd.print(":"); lcd.print(currentTime.getMinutes()); lcd.print(":"); // Controllo per evitare la non cancellazione della cifra meno significativa // al passaggio del minuto successivo if (currentTime.getSeconds() == 0) { lcd.print("0 "); lcd.setCursor(12, 1); } else { lcd.print(currentTime.getSeconds()); } } } }
Per quanto riguarda l’interrupt periodico a cui si fa riferimento nella pagina di esempio del sito di Arduino, attualmente ci sono alcuni problemi di utilizzo e lo sketch presenta alcuni refusi, di cui si fa menzione anche nel forum di Arduino, confido che nel breve il problema venga risolto.
Nelle prossime lezioni proporrò ulteriori esempi di utilizzo dell’RTC di Arduino UNO R4, per ora no mi resta che augurarvi:
Buon Making 🙂
Buongiorno. Articoli sempre interessanti e ben spiegati (si vede che è un professore e sa come spiegare le cose in modo semplice e comprensibile, e comunque non tutti i professori ci riescono).
Seguirò con interesse il seguito di questo articolo.
Grazie e buona giornata
Grazie mille per le sue parole. 🙂
Buongiorno Sig. Maffucci
Da qualche giorno sto provando la precisione dell’ RTC di Arduino R4, ma ahime mi risulta poco preciso.
Non faccio altro che visualizzare l’ora sul seriale (ho seguito il suo esempio), confrontandolo con un orologio si vede che gia’ dopo qualche minuto, ci sono delle imprecisioni, l’RTC di Arduino risulta di qualche secondo in avanti, e se si aspetta qualche ora si nota che e’ qualche minuto avanti!
Non e’ una bella cosa!
L’ha notato?
Grazie e buona giornata
Gentilissimo,
grazie per avermi scritto, perdoni la risposta tardiva ma ero in vacanza.
Si ho notato ed ho verificato ed effettivamente su un test di un giorno si ha una perdita di precisione importante. Guardando gli schemi di Arduino UNO R4 Minima e WiFi noto che entrambi NON usano il quarzo esterno da 32.768khz sui pin XCIN/XCOUT del microcontrollore RA4M1 e ciò non è positivo in quanto porta inevitabilmente ad una perdita di precisione che può raggiungere, dai test che sto effettuando, a circa ± 20 minuti al giorno. Utilizzando un cristallo esterno la perdita non supererebbe i ± 2 secondi (circa) al giorno. Cercherò appena possibile di approfondire meglio questo aspetto con ulteriori test.
Le lascio un link ad una discussione sul forum di Arduino che rimanda ad una discussione dove si parla proprio di questo problema.
https://forum.arduino.cc/t/uno-r4-wifi-rtc-runs-fast-by-about-1-second-per-minute/1145956
Saluti.
Guida estremamente pratica e puntuale. Grazie davvero 😉