In this article I will introduce you swRTC, a software implementation, based on timers, of a Real-Time Clock (or RTC) for Arduino boards and Atmel microcontrollers.
The library actually it supports several Atmel microcontrollers:
- Atmega640/1280/1281/2560/2561 and Arduino MEGA boards
- Atmega48/88/168/328 and Arduino 2009/UNO boards
- Attiny24/44/84
- Attiny25/45/85
- Attiny2313/4313
- Atmega644/1284 and Sanguino boards
Requirements
- the swRTC library needs the Arduino IDE v. 0022 to work with Atmega48/88/168/328/328 (with or w/out the “P”, PicoPower, core), with Atmega640/1280/1281/2560/2561 and with Atmega8/8A;
- to work Attiny24/44/84, Attiny25/45/85 and Attiny2313/4313 you need the Tiny Core libraries that you can download from http://code.google.com/p/arduino-tiny/
- to work with Atmega644/1284 you need the Sanguino core libraries that you can download from http://sanguino.cc/useit
Directions to install and use the Tiny and Sanguino cores are provided from their respective authors.
Installation
- uncompress the archive and copy the swRTC folder inside the /librariesfolder inside your sketchbooks’ folders. If that folder doesn’t exist, you have to create it.To know where the sketchbooks folder is located, open the Arduino IDE then select from the menu “File/Preferences” and look at the path in “Sketchbook location”.At the end, you should have something similar to this (for Linux): /home/username/sketchbook/libraries/swRTC
- After that, you have to replace a file of the Tiny core. Make a backup copy of it in case you need to roll back to the original one.To do this, find the file named core_build_options.h that is located in your-arduino-IDE-folder/hardware/tiny/cores/tiny/ and rename it to core_build_options.bck (or a name you like it).
- Then, copy the core_build_options.h that comes from the swRTC into the previous path.
This will permit to have both the swRTC library and the delay/millis functions from Arduino IDE up and running on Tinyx5/x4/2313 microcontrollers.
Usage & methods
Include the library in your sketch with
#include
To use the library, first you have to create an instance of the library, i.e.:
swRTC rtc;
Then you have to set up the internal clock with valid time&date. This can be done via software or by the user through a user interface (i.e. LCD display) using the following methods:
rtc.setTime(hours, minutes, seconds);
rtc.setDate(day, month, year);
It is suggested to stop the swRTC before to change the time and/or the date with:
rtc.stopRTC();
and then to start it again, after changes are done, with:
rtc.startRTC();
The method startRTC() also sets the HW timer according to the clock frequency of your Arduino/Atmel microcontroller, synchronizing the prescaler of the timer to match the correct timings.
To get the time&date you can use the following methods:
rtc.getSeconds();
rtc.getMinutes();
rtc.getHours();
rtc.getDay();
rtc.getMonth();
rtc.getYear();
Most of the above methods return a byte value, only getYear() returns a signed integer value.
If you want to know if a specific year is a leap year, you just have to call:
rtc.isLeapYear([year])
to get a boolean value that is true in case of a leap year. The argument “year” is optional: if you don’t provide it, the library will check the current year.
The library can work with timestamps too.
rtc.getTimeStamp([epoch]);
rtc.setClockWithTimestamp(timestamp[, epoch]);
rtc.weekDay(timestamp);
rtc.getWeekDay();
The first function returns the number of seconds since the beginning of a particular dateepoch (1900 or 1970). By default, it returns the number of seconds since 1970.0, or 1970/01/01 but, the UNIX era, but you can also use the epoch 1900.0, or 1900/01/01. The second one sets the internal clock using a timestamp (i.e. a timestamp provided from an NTP server). If specified, epoch will be used. The third and the forth functions return a number indicating the weekday of a given timestamp of of the current day, starting from 0 for sunday to 6 for saturday.
There are two more functions that are used to correct the difference between the time of the internal clock and the real time.
rtc.setDeltaT(value);
rtc.getDeltaT();
Allowed values are integer values between -8,400 and 8,400 (max -14.0 or +14.0 minutes/day). The deltaT is the number of decimal seconds per day to apply to the RTC to correct the deviation from the real time. If your RTC is faster than the real time, try adjusting deltaT with positive values, if your RTC is slower, try a deltaT with a negative values.
I.e. 102 means a correction of 10200 ms/day, 10.2 seconds/day.
getDeltaT(), on the other hand, returns the current value of the time correction.
Since release 1.2.0, the library supports the use of the internal Real-Time Counter (RTC) present on several MCUs. This module permits to use the timer 2 in asynchronous mode with an external 32,768 Hz crystal. Setting up the timer 2 with a prescaler of 128, we get 1 overflow every 1 secon so that we can increment the software clock in a more accurate manner. At the moment, the use of deltaT is not supported with the use of the RTC module.
To use the RTC module (that is present only in Atmega88/168/328, Atmega8, Atmega344/644/1284 and Atmega1280/256x), just add the following #define before the inclusion of the library:
#define USE_INTERNAL_RTC
#include “swRTC.h”
The Real-Time Counter can only be used with the internal oscillator due to the fact that the external 32,768 Hz crystal must be connected to the same pins used for the normal crystals (don’t forget to add 2 18/22pF ceramic capacitors).
The library has been modified and now the .cpp file has been removed, while its content has been included in the header file. This does not change the usage of the library itself.
Supported frequencies/microcontrollers and limitations
The library is interrupt driven and uses an 8-bit internal timer. This is the complete list of the supported microcontrollers:
- ATMEL Atmegax0: Atmega640/1280/1281/2560/2561
The library supports the Atmel microcontrollers Atmega640/1280/1281/2560/2561; the Atmega1280/2560 are the chips that are installed on Arduino MEGA/MEGA2560 boards - ATMEL Atmegax8: Atmega48/88/168/328/328 and their /P (PicoPower core) variants (this does not mean that the specific micro is supported from the Arduino IDE and/or avrdude too)
The library supports the Atmel microcontrollers Atmega48/88/168/328 and their /P variants. The library uses the timer 2. No limitations are on Arduino INT0/timer0 based functions like delay() or millis() but keep in mind the you cannot use the PWM functions on pins 3 and 11 because PWM on those pins uses INT2/timer2, that is used by swRTC. - ATMEL Atmega8/8A
This is the micro prior to Atmegax8 series. It has been used on ArduinoNG. With this micro the library uses the timer 2. - ATMEL Attinyx5: Attiny25/45/85
On this family of micros the library uses the INT0/Timer 0. Delay() & millis() functions, that in the Tiny core are based on INT1/timer1, so we can use the INT0/timer 0 with no conflicts. - ATMEL Attinyx4: Attiny24/44/84
The library uses the INT0/Timer 0 because timer 1 is a 16 bit counter. To do this, we have moved the delay() and millis() functions on INT1/timer1 thanks to the modified core_build_options.h file. - ATMEL Attiny2313/4313
Same for Attiny24/44/84: we have moved delay() and millis() functions to timer 1 to use the 8-bit timer 0. - ATMEL Atmega644/1284 and their /P variants
The library uses the timer 2.
How it works
The library sets an internal timer in counter mode to have 1 overflow interrupt exactly every 1 millisecond. Every 1000 ms it increments the internal registers starting from seconds to finish with years to keep the running of the time.
To do this, is calculates the correct starting value of the counter and the prescaler of the timer, depending on the system frequency. It also chooses the correct timer because this trick only works with 8-bit counters. On some Attiny micros, the library must move the delay/millis functions on timer 1 because these micros have only 2 timers, and only timer 0 is a 8-bit timer.
deltaT introduces an anticipation or a delay while the register of the seconds is updated so that we can have 1 “software” second that is longer or shorter than 1 real second.
Updates:
- 1.1.1: fixed a bug in setDeltaT
- 1.1.0: new syntax for setDeltaT – new method getDeltaT
- 1.0.6: fixed a bug in the function used to set the clock given a timestamp
- 1.0.5: new the method getWeekDay
- 1.0.3: added support for clocks at 4MHz
- 1.0.2: fixed a bug in the getTimestamp function
- 1.0.1: minor update to introduce the new license of the library: now it’s released under GNU GPL3 or newer
- 1.0: first stable release
- 1.1.2: getDelta now returns the value of deltaT with the right sign
- 1.2.0: now it supports the internal Real-Time Counter (if present)
- 1.2.1: minor adjustments
- 1.2.2: fixed a bug that prevented the getWeekDay from returning the correct weekday for leap years for dates before the 1st of march
- 1.2.3: fixed the type of the prototype of the function setClockWithTimestamp
- 1.2.4: updated to use with latest Arduino IDE branches (>=1.6.7)
License
This library is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
Author
Written by Leonardo Miliani with the contribution of lesto from the forum of www.arduino.cc.
Sistemato un piccolo bug nel file swRTC.h. Adesso la compilazione avviene correttamente
Fixed a little bug in file swRTC.h. Now the lib compiles correctly.
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!
Risolto ho capito da solo! non c’è nessun componente RTC esterno…
Ma come fa ad essere preciso?
Ci si può fidare???
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.
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
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!
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.
@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).
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 ?
@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.
@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.
@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.
@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.
@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 >).
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.
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.
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
Ti consiglio il forum di Arduino:
http://forum.arduino.cc/index.php?board=34.0
e’ possibile usare/modificare questa libreria per avere un timer con i millisecondi ?
io vorrei creare un cronometro con precisione dei millisecondi con arduino uno; mi conviene integrare un quarzo da 32MHz come per il micrologio ?
Grazie
La swRTC è stata scritta per operare calcolando intervalli temporali di 1 secondo, anche se poi nella ISR c’è un contatore che avanza di 1 ms per volta (tranne quando si usa il quarzo esterno, caso in cui il timer viene impostato per sollevare 1 interrupt ogni 1 secondo). Potresti inserire nella ISR un contatore di millisecondi che non viene azzerato, come accade ora. Oppure usare il leOS che ha un altro tipo di uso del timer, ed ha una risoluzione di circa 1 ms. Puoi fare un contamillisecondi facilmente. Tieni presente comunque che la precisione dipende dall’oscillatore montato sulla scheda, quindi nel lungo periodo il sistema potrebbe perderà in precisione.
Ciao,ma questa libreria esegue il cambio ora in automatico legale/solare e viceversa??
Grazie,Mauro
Ciao, io ho un problema non ho capito come far funzionare la tua libreria. chiedo scusa ma sono ancora alle prime armi. hocreato un orologio con ora in tempo reale usando una rtc e collegando all’arduino dei relè che si attivano in un determinato orario del giorno, ora mi serve la tua libreria per far aggiornare l’ora legale e per anno bisestile, ma non so come fare. grazie in anticipo
Buongiorno e complimenti per questa libreria, per necessita’ di compatibilita’ devo usare l’ide 1.5 ma sembra che la swrtc non sia compatibile, anche se provo a compilare un esempio mi restituisce sempre questo errore:
swRTC.h:92:11: error: candidate is: boolean swRTC::setClockWithTimestamp(long unsigned int, int)
boolean setClockWithTimestamp(unsigned long timeT, int yearT = 0);
^
Errore durante la compilazione
E’ possibile risolvere questo problema o e’ un lavoro troppo grosso?
Grazie
Ciao essereumano, ho avuto anchio lo stesso problema e ho risolto cambiando nel swRTC questa riga:
boolean setClockWithTimestamp(unsigned long timeT, int yearT = 0);
con:
byte setClockWithTimestamp(unsigned long timeT, int yearT = 0);
semplicemente nella dichiarazione della funzione diciamo che l’output (return) può essere byte anzichè booleano dato che, analizzando la funzione può restituire 0, 1, 2 ecc. in base ai vari errori.
Volevo cogliere l’occasione per ringraziare Leonardo per tutto il materiale che ci mette a disposizione.
Saluti.
Tip for italian users : I studied swRTC code a bit, so in some cases I may be able to help, but for that you need to ask … in English.
Hi all, I’m still using the swRTC with panstamp in my system, and it served me right for these years. One pretty nice thing is that it has a very simple structure (only one file) and runs on many cores.
Now on the other hand, I’ve seen that the time library of Arduino itself has been sensibly improved since 2012, and I am wondering whether it would not be better for me to move back to it. The reason is that it is based on millis(), that I use as well, and allows to use the same API for time for a variety of RTC sources (in other words, whether you use NTP, I2C, 32k or Timer2, the application API is the same. That’s pretty neat !
In addition, since the “derivative” I use (panstamp) relies on the internal 8MHz oscillator, the clock is not precise at all. I tried to use the DeltaT feature to correct that, but it didn’t work for two reasons : first 14 minutes/day was not enough, and second the 8MHz oscillator frequency can vary (a lot) according to the temperature, so the deltaT setting is inefficient.
Finally, the new “time” library is able to detect an “unset” clock (at reset), for example after a mains outage. This is also neat, because it allows to exclude time-of-day mechanisms/optimisations when they could be wrong.
So my question is whether there are (Leonardo has) plans to evolve swRTC further, either towards an API closer to the time library, or a feature parity (unset parameter for example) or whether the 1.2.1 version is going to be the last one forever ?
Thanks for the great library in any case.
At the moment I’m passing a period of very hard working so I don’t really have a lot of time to do other thing such as upgrading the library. I’m very sorry, I apologize for this.
Buongiorno. Mi aggiungo anch’io alla lista delle persone che le fanno i complimenti per questa ottima libreria.
La sta utilizzando da qualche mese su alcuni miei progetti. Con il nuovo anno (2016) ho notato che il valore ritornato dalla funzione getweekday() non è corretto. Ho fatto alcune prove l’errore si verifica nei primi due mesi di tutti gli anni bisestili.
Faccio un esempio: il 31/12/2015 era giovedì. La funzione ritorna come weekday=4. Corretto. Il giorno dopo, 1/1/2016 dovrebbe ritornare =5 (venerdì), invece ritorna = 6. L’errore permane fino al 29 febbrario, weekday=2 quando invece sarebbe lunedì, e si “risolve” il 1° marzo tornando di nuovo al valore corretto, in cui di nuovo la funzione ritorna weekday=2.
Il problema penso riguardi il valore di timestamp durante questi giorni.
Può darmi una mano? La ringrazio.
ps: sto utilizzando un arduino pro mini (5V 16 Mhz)
Ciao loba, sì: c’è un bug nel codice che calcola il timestamp. Riassumendo, la funzione non tiene conto che finché non si arriva al 29 febbraio di un anno bisestile, semplicemente il giorno bisestile… NON c’è ancora stato! Quindi dobbiamo calcolare il tempo normalmente mentre la funzione non lo fa. Solo quando siamo dopo il 28/02 scatta il giorno aggiuntivo. Ecco da dove nasce l’errore del giorno settimanale calcolato avanti fino al 1° marzo. La versione 1.2.2 che sto per pubblicare sistemerà il problema.
E’ possibile settare degli allarmi?
grazie
@edirectoor:
la libreria svolge la sola funzione di tener traccia del tempo per cui se vuoi impostare uno o più allarmi devi farlo a livello di codice, controllando che l’orario corrente coincida con uno prefissato