Realizziamo un orologio con l’RTC di Arduino UNO R4 WiFi

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 🙂

Questa voce è stata pubblicata in arduino e contrassegnata con , , , , , , . Contrassegna il permalink.

5 risposte a Realizziamo un orologio con l’RTC di Arduino UNO R4 WiFi

  1. Mirco Lasagni scrive:

    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

  2. Domenico Bramanti scrive:

    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

    • admin scrive:

      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.

  3. Federico di MilanoLaserWorks scrive:

    Guida estremamente pratica e puntuale. Grazie davvero 😉

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *

Questo sito usa Akismet per ridurre lo spam. Scopri come i tuoi dati vengono elaborati.