«

»

nov 27 2011

swRTC, un Orologio in Tempo Reale via software

In questo articolo vi illustro swRTC, una implementazione software, basata sui timer, di un Orologio in Tempo Reale (Real-Time Clock, o RTC) per le schede Arduino e diversi microcontrollori Atmel.

La libreria al momento supporta i seguenti microcontrollori Atmel:

  • Atmega640/1280/1281/2560/2561 e le schede Arduino MEGA
  • Atmega48/88/168/328 e le schede Arduino 2009/UNO
  • Attiny24/44/84
  • Attiny25/45/85
  • Attiny2313/4313
  • Atmega644/1284 e le schede Sanguino
Le frequenze di clock supportate sono 1/4/8/16 MHz.
Requisiti
  • la libreria swRTC usa l’IDE di Arduino versione 0022 per lavorare con gli Atmega48/88/168/328/328 (con o senza il core “P”, PicoPower), con gli Atmega640/1280/1281/2560/2561 e con gli Atmega8/8A;
  • per lavorare con gli Attiny24/44/84, gli Attiny25/45/85 e gli Attiny2313/4313 bisogna installare il core Tiny che può essere scaricato da http://code.google.com/p/arduino-tiny/
  • per lavorare con gli Atmega644/1284 e le schede Sanguino è necessario il core Sanguino che può essere scaricato da http://sanguino.cc/useit

Le istruzioni per installare ed utilizzare i core Tiny e Sanguino sono fornite dai loro rispettivi autori.

Installazione
  1. scompattare l’archivio e copiare la cartella swRTC all’interno della cartella /libraries contenuta nella propria cartella degli sketch. Se tale cartella non esiste, bisogna crearla.
    Per conoscere dove risiede la propria cartella degli sketch, bisogna aprire l’IDE di Arduino, selezionare la voce del menu “File/Preferences” e controllare il percorso alla voce “Sketchbook location”.
    Alla fine del processo dovrebbe risultare un percorso simile al seguente (da un’installazione su Linux):
    /home/username/sketchbook/libraries/swRTC
  2. Dopo ciò bisogna sostituire un file del core Tiny. Consiglio di farsene una copia di backup in caso si volesse ripristinare la versione originale dello stesso.
    Per fare questo cercate il file denominato core_build_options.h che è contenuto nella cartella percorso-alla-vostra-IDE-di-Arduino/hardware/tiny/cores/tiny/ e cambiate il nome del file in core_build_options.bck (o in qualcosa che vi piace di più).
  3. Adesso copiate il file core_build_options.h che è contenuto nella libreria swRTC al posto del precedente.

Grazie a questi passi potrete avere sia la libreria swRTC che le funzioni temporali di Arduino delay/millis funzionanti sui microcontrollori Attiny.

Utilizzo e metodi

Prima di tutto bisogna includere la libreria nel proprio sketch con:

#include

Fatto ciò, per usarla bisogna creare un’istanza della libreria, ad esempio così:

swRTC rtc;

Adesso bisogna impostare l’RTC con dei valori validi di orario e data. Questo può essere fatto sia via software sia direttamente dall’utente tramite un’interfaccia (ad esempio un display LCD) usando i seguenti metodi:

rtc.setTime(hours, minutes, seconds);
rtc.setDate(day, month, year);

Suggerisco di fermare sempre il swRTC prima di cambiare la data/ora:

rtc.stopRTC();

e poi di riattivarlo quando le impostazioni sono state fatte:

rtc.startRTC();

Il metodo startRTC() imposta anche il timer HW in base alla frequenza di clock dell’Arduino o del microcontrollore, sincronizzando il prescale del timer per ottenre le giuste temporizzazioni.

Per ottenere la data o l’ora si usano i seguenti metodi:

rtc.getSeconds();
rtc.getMinutes();
rtc.getHours();
rtc.getDay();
rtc.getMonth();
rtc.getYear();

Quasi tutti restituiscono un valore di tipo byte, ad eccezione di rtc.getYear() che restituisce una variabile di tipo signed integer.

Se si vuole controllare se un dato anno è bisestile, basta chiamare il seguente metodo:

rtc.isLeapYear([year])

per avere un valore booleano che è vero nel caso l’anno sia bisestile. L’argomento “year” è facoltativo: se non si fornisce, la libreria controlla l’anno attuale.

La libreria supporta anche i timestamp.

rtc.getTimeStamp([epoch]);
rtc.setClockWithTimestamp(timestamp[, epoch]);
rtc.weekDay(timestamp);
rtc.getWeekDay();

La prima funzione restituisce il numero di secondi dall’inizio di una particolare epoca (1900 o 1970). Di default essa restituisce il numero di secondi dal 1970.0, o 01/01/1970, l’era UNIX, ma può essere usata anche l’epoca 1900.0, o 01/01/1900. La seconda imposta l’orologio interno con un timestamp (ad esempio il timestamp fornito da un server NTP). Se specificata, sarà usata epoch come epoca di riferimento. La terza e la quarta funzione restituiscono un numero che indica il giorno della settimana di uno specifico timestamp o del giorno corrente, con valore da 0 per la domenica fino a 6 per il sabato.

Ci sono ancora 2 metodi che sono utilizzati per correggere la differenza tra il tempo segnato dall’orologio interno e quello reale.

rtc.setDeltaT(value);
rtc.getDeltaT();

Il primo è un metodo molto importante. Introdotto a partire dalla versione 0.8 vi è il concetto di correzione temporale rappresentato dal parametro interno deltaT, un valore che corregge la deviazione tra il tempo calcolato ed il tempo reale, ossia lo scostamento tra il tempo calcolato dalla libreria ed il tempo effettivamente trascorso. Questo metodo è stato introdotto per correggere gli scostamenti che possono essere introdotti nel computo del tempo sia a livello software (ad esempio altre librerie che utilizzano gli interrupt, come la NewSoftSerial) sia a livello hardware. Ad esempio, bisogna considerare che i risonatori esterni (come nel caso di quello presente sulle nuove schede Arduino UNO) o gli oscillatori interni non sono molto precisi, con variazioni anche di +/- 10% rispetto alla frequenza nominale.

Valori accettati dal metodo setDeltaT variano da -8.400 a +8.400, che corrispondono ad una correzione massima di -14.0/+14.0 minuti/giorno. Il deltaT è il numero di decimi di secondo al giorno da applicare al computo interno per correggere la deviazione dal tempo reale. Se l’RTC è in anticipo rispetto all’ora reale, provate ad aggiustare il swRTC con valori positivi, se il swRTC è più lento provate a correggerlo con valori negativi.Es.: 102 significa una correzione di 10200 millisecondi/giorno, ossia 10.2 secondi/giorno.

Invece, getDeltaT() restituisce il valore corrente della correzione temporale.

IMPORTANTE:l’utilizzo della correzione in virgola mobile è ora DEPRECATO. I vecchi codici che usavano questo formato sono ancora compatibili con la swRTC (il metodo accetta un valore che indica il numero di secondi da aggiungere/sottrarre con una 1 singola cifra decimale, nell’intervallo -840,0..+840,0) ma ciò non significa che lo saranno anche in futuro per cui si raccomanda di aggiornare il codice ed iniziare ad utilizzare la nuova sintassi basata sugli interi.

Dalla versione 1.2.0 la libreria supporta l’uso del Real-Time Counter (RTC) presente su diverse MCU. Questo modulo permette di utilizzare il timer 2 in modalità asincrona con un quarzo esterno da 32.768 Hz. Impostando il timer con un prescaler a 128, si ha esattamente 1 overflow ogni secondo per cui è possibile incrementare l’orologio software in maniera più accurata. Al momento, l’uso del deltaT non è supportato in combinazione con l’uso del modulo RTC.

Per usare il modulo RTC (presente solo negli Atmega88/168/328, Atmega8, Atmega344/644/1284 e Atmega1280/256x), basta ggiungere la seguente #define prima dell’inclusione della libreria

#define USE_INTERNAL_RTC
#include “swRTC.h”

Il modulo Real-Time Counter può essere usato solo in abbinamento con l’oscillatore interno perché il quarzo esterno da 32.768 Hz deve essere connesso agli stessi pin usati per i normali quarzi (non dimenticatevi i condensatori ceramici da 18/22 pF).

La libreria è stata modificata e il file .cpp rimosso perché il suo contenuto è stato integrato nel file header. Questo non modifica l’uso della libreria stessa.

Frequenze/microcontrollori supportati e limitazioni

La libreria introduce un contatore temporale pilotato tramite interrupt ed usa un timer ad 8 bit interno al microcontrollore. Questa è l’elenco completo dei microcontrollori supportati:

  • ATMEL Atmegax0: Atmega640/1280/1281/2560/2561
    La libreria supporta i microcontrollori Atmega640/1280/1281/2560/2561; gli Atmega1280/2560 sono i chip installati sulle schede Arduino MEGA/MEGA2560. Su questi micro viene usato il timer 2.
  • ATMEL Atmegax8: Atmega48/88/168/328/328 e le loro varianti /P (core PicoPower) (ciò non significa che lo specifico micro sia anche supportato dall’IDE di Arduino e/o da avrdude)
    La libreria supporta i microcontrollori Atmega48/88/168/328 anche nelle varianti /P ed usa il timer 2. Non ci sono limitazioni sull’Arduino perché le funzioni temporali quali delay() o millis() usano l’INT0/timer 0 ma prestate attenzione al fatto che non potete utilizzare la funzione PWM dei pin 3 ed 11 dato che essa è gestita su quei pin proprio dal timer 2, che è usato appunto dalla libreria swRTC.
  • ATMEL Atmega8/8A
    Questo è il micro usato sugli Arduino molto vecchi: ad esempio, si trova sull’ArduinoNG. Anche con questo micro viene usato il timer 2.
  • ATMEL Attinyx5: Attiny25/45/85
    Su questa famiglia di microcontrollori la libreria utilizza l’INT0/Timer 0. Le funzioni delay() e millis() del core Tiny usano su questi micro l’INT1/Timer 1 per cui la swRTC usa l’INT0/Timer 0 senza conflitti.
  • ATMEL Attinyx4: Attiny24/44/84
    La libreria usa l’INT0/Timer 0 perché su questi micro il timer 1 è a 16 bit: le librerie temporali vengono perciò spostate sul timer 1. Ciò è possibile grazie al file modificato core_build_options.h che abbiamo installato nel core Tiny.
  • ATMEL Attiny2313/4313
    Stesso discorso relativo agli Attiny24/44/84: le funzioni delay() e millis() sono stato spostate sul timer 1 per poter usare il timer 0 ad 8 bit.
  • ATMEL Atmega644/1284 e loro varianti /P
    Su questi micro la libreria usa il timer 2.
IMPORTANTE: attualmente la libreria supporta solo frequenze di 1/4/8/16 MHz a causa di problemi di arrotondamento che escono fuori usando altre frequenze, arrotondamenti che non permettono un calcolo preciso all’intero del valore iniziale del timer.

Come funziona

La libreria imposta il timer interno in modalità contatore con overflow così da avere esattamente 1 overflow ogni millisecondo. Ogni 1000 millisecondi essa incrementa i registri interni a partire da quello dei secondi fino ad arrivare a quello degli anni, per tenere il conto dello scorrere del tempo.

Per fare ciò, la libreria calcola il corretto valore di partenza del contatore e del prescaler del timer, a seconda della frequenza di clock. Essa sceglie anche il corretto timer interno dato che questo sistema funziona solo sui timer ad 8 bit.

Il deltaT introduce un anticipo o un ritardo sull’avanzamento del registro dei secondi così da avere 1 secondo “software” più o meno lungo rispetto ad 1 secondo reale.

Aggiornamenti:

  • 1.0: prima versione stabile della libreria
  • 1.0.1: aggiornamento per cambio di licenza, adesso il software è distribuito sotto GNU GPL3 o successive
  • 1.0.2: corretto un bug nella funzione getTimestamp
  • 1.0.3: aggiunto il supporto ai 4 MHz
  • 1.0.5: introdotto il nuovo metodo getWeekDay
  • 1.0.6: corretto un bug nella funzione usata per impostare l’orologio dato un timestamp
  • 1.1.0: nuova sintassi per setDeltaT – nuovo metodo getDeltaT
  • 1.1.1: sistemato un bug in setDeltaT
  • 1.1.2: getDelta restituisce il valore di deltaT con il giusto segno

Licenza

La libreria è “software libero” (free software); puoi ridistribuirla e/o modificarla sotto i termini della GNU General Public License come pubblicata dalla Free Software Foundation, o la versione 2.1 della Licenza o (a tua scelta) una qualunque versione più recente.
La libreria è distribuita nella speranza che sia utile a qualcuno ma SENZA NESSUNA GARANZIA; senza anche la garanzia implicita di COMMERCIABILITA’ o IDONEITA’ PER UN PARTICOLARE UTILIZZO. Vedi la GNU General Public License per maggiori dettagli.

Autore

Scritta da Leonardo Miliani con il contributo di lesto del forum di www.arduino.cc.

swRTC
swRTC
swRTC-1.2.0.zip
Versione: 1.2.0
26.6 KiB
2675 Downloads
Dettagli...

19 comments

Vai al modulo dei commenti

  1. Leonardo Miliani

    Sistemato un piccolo bug nel file swRTC.h. Adesso la compilazione avviene correttamente

  2. Leonardo Miliani

    Fixed a little bug in file swRTC.h. Now the lib compiles correctly.

  3. Ciao! Ti ringrazio per la libreria che hai pubblicato!!! mi sembra ben fatta!
    Volevo fare qualche domanda…
    1. A che pin collego il Real Time Clock?
    2. Puoi sugerirmi un Real Time Clock?
    3. Hai uno schema elettrico per la configurazione dell’ RTC (quello che mi suggerisci).

    Grazie!

  4. Risolto ho capito da solo! non c’è nessun componente RTC esterno…

    Ma come fa ad essere preciso?
    Ci si può fidare???

  5. Leonardo Miliani

    Lavora usando dei timer interni. La precisione dipende dal risonatore esterno dell’Arduino UNO o dal quarzo dell’Arduino 2009. Nel secondo caso la precisione è maggiore rispetto al primo perché un risonatore è di per sé meno preciso di un quarzo.

  6. cesare76m

    Complimenti per il lavoro svolto, mi è stato davvero utile,

    mi chiedevo se fosse possibile aprire più istanze per gestire più orologi contemporaneamente, o se c’è il modo di utilizzare un contatore (con un impulso al secondo o al millis) che possa partire da zero ad un comando di start e che fosse indipendente dall’orologio. Grazie e saluti Cesare

  7. markocont

    Ciao, una domanda, qualora io volessi mettere in power save il microcontrollore è possibile continuare ad utilizzare questa libreria senza perdere le informazioni temporali?
    Complimenti per il lavoro fatto….!
    Ciao!

  8. Just to inform you that I integrated swRTC with the Panstamp SWAP stack, that allows wireless motes to talk together. You can see a post about that at http://www.panstamp.org/forum/showthread.php?tid=140

    Any comment welcome.

  9. @markocont (Sorry my italian is too bad to answer in italian)
    My understanding of swRTC is that it uses timer 2 (on most arduinos, ATMEGA328) and fires every millisecond. This means that if you enter a power save mode (I think there are more than one), either you will wake up again after at most 1 msec (if interrupt allow wakeup), meaning power save won’t deliver what you expect, or the swRTC won’t work (because it will only count milliseconds when the board is awake).

  10. Last comment for today : what about adding a set of (optional) functions for triggering an event every second/minute/hour/day ? I think this can be done with including simple tests such as in the library.

    if (&hourly != NULL) hourly();

    not sure at all that’s correct, my C language knowledge is under construction ;-) But you probably get the idea ?

  11. Leonardo Miliani

    @cesare76m:
    non è possibile aprire più istanze della libreria per via dell’uso esclusivo che si fa del timer. Se hai bisogno di un contatore avviabile/arrestabile, potresti prendere in considerazione l’uso del leOS, col quale puoi creare un RTC software sulla falsa riga del swRTC e contemporaneamente un contatore con la tipologia di funzionamento che hai descritto.

  12. Leonardo Miliani

    @markocont:
    dipende dal tipo di microcontrollore. Ognuno ha il datasheet a cui far riferimento per sapere quali interrupt di quali timer risvegliano il micro a seconda della modalità di sleep scelta. Per semplificare il discorso, prendiamo il caso dell’Atmega328. La swRTC usa il timer 2 su questo micro, il timer 2 continua a funzionare anche in modalità “power save” (ma non “power down”). Impostato in modalità “power save” il micro verrà risvegliato ogni millisecondo dall’interrupt del timer 2. Il risparmio energetico c’è rispetto ad un microcontrollore che funziona costantemente a pieno regime, anche se si sarebbe tenuto a pensare il contrario vista l’apparente brevità del riposo (1 ms). Ma tutto deve essere rapportato ai tempi del micro, considera che per le istruzioni in codice macchina parliamo di ns, un ordine di grandezza molto inferiore al ms.
    Casomai il problema è un altro: l’ingresso e l’uscita dallo sleep sono operazioni che comportano l’attesa di piccoli periodi di tempo per portare tutte le periferiche interne allo stato desiderato (stand-by o piena operatività). La somma di questi tempi altera sensibilmente il tempo misurato dalla swRTC. Se il tuo problema è la misura del tempo ed il risparmio energetico, ti consiglio di adottare le soluzioni dell’altro mio progetto Micrologio, dove ho realizzato un orologio software molto preciso con un micro che sta in sleep la maggior parte del tempo, risvegliandosi solo 1 volta al secondo.

  13. Leonardo Miliani

    @tochinet:
    what you say is in part true. If you choose the “power save” mode, the timer 2 still continues to run. The timer 2 is halted only in “power down” mode. But the problem is that the continuosly entering in and exiting by the sleep mode consumes a little bit of time. The sum of all of that times creates a significant amount of lag between the real time and the computed time. So if the necessity is primarly the power consumption I suggest to look at another project of mine, Micrologio, where I used a different approch to misure the time and save power.

  14. Leonardo Miliani

    @tochinet (2):
    if you mean a soft of “alarm”, it’s not difficult to do that.
    If you need a scheduler, I suggest to use leOS. With leOS you can create a software implementation of an RTC (there’s a post of mine that shows this use) and a scheduler too, to execute little tasks at fixed intervals.

  15. Leonardo Miliani

    @tonitech (3):
    I’m curious about panStamp and the use of swRTC in that project. Can you give more details? (if you prefer, you can write me an e-mail at < leonardo AT leonardomiliani DOT com >).

  16. Hi, I’m still using swrtc in panstamps, what do you want to know ? I put a few details below

    BTW I studied LeOS too and I may go for that one. I’m just not sure 100% whether it’s better to use leOS, looper, rtduinos, chibios or similar… And I’m a bit afraid of clashes between leOS and swRTC (and panstamp stack) regarding use of timers and interrupts

    I created one panstamp register (array of 7 bytes) for the clock. Since registers are usually BE, I chose to order them as “century, year, month, day,hour, minute, second”. Then a sette and getter method allows me to query and set the clock using teh SWAP stack wirelessly. Works fine. Note that since panstamps use the internal 8MHz clock, there is a serious drift of clock. My first tested panstamp had a deviation of 13 minutes/day, close to the “840.0″ seconds max.

    Also note that I will have to/you should add a “getDeltaT” method so that it is possible to query the status of deltaT variable. Also a setDeltaT accepting an integer should be interesting, I try to avoid floats as much as I can on Arduino.

    I also added an “automatic deltaT setting”, that tunes deltaT each time you manually set the clock. But after a while I commented it out because I wasn’t convinced of its effectiveness.

  17. Leonardo Miliani

    leOS and swRTC can’t work together because both use timer 2. leOS2 uses the Watchdog Timer, so is/should be compatible with swRTC.

    The suggestion to introduce a method to manage the deltaT is interesting. I will work on it. You’re right when you say that floats should be used only in particular situations becuase their implementation heavily affects the MCU’s performances.

  18. Barclay

    Ciao, anzitutto complimenti per il bel lavoro e per tutto il tuo blog molto interessante.
    La libreria è molto interessante e mi sarebbe molto utile, premetto che ho l’arduino mega tra le mani da 10 gg, e sto leggendo di tutto di più, il risultato è una gran confusione.
    Tuttavia ho provato i tuoi sketch di esempio che naturalmente funzionano alla perfezione, ma vorrei visualizzare le informazioni su un display anzichè sul serial monitor, io uso questo:
    http://easyelectronics.ru/img/STM8/displ/SSD1298.pdf ,
    mi daresti una mano a visualizzare i dati sul display?
    Saluti

  19. Leonardo Miliani

    Ti consiglio il forum di Arduino:
    http://forum.arduino.cc/index.php?board=34.0

Lascia un Commento