How do I get an accurate time?
You do not need an RTC to build a clock: the ATmega chip has all the hardware needed to perform the duties of the RTC itself. Here is how:
Get a 32768 Hz watch crystal: either buy it or disassemble an old clock. These crystals, specifically designed for time keeping, have an extremely small temperature drift. You would also need one of those if you wanted to use an RTC chip.
Configure the fuses of your ATmega to run off the 8 MHz RC oscillator. This will make your
millis()
function horribly inaccurate, and also free the XTAL1 and XTAL2 pins.Connect the watch crystal to the TOSC1 and TOSC2 pins. These are the same pins as XTAL1 and XTAL2 (9 and 10 on the 328P). The different names are used to mean different functions.
Configure the Timer/Counter 2 for asynchronous operation, normal counting mode, prescaler set to 128, and enable the timer overflow interrupt.
Now you will get a TIMER2_OVF interrupt at a very steady rate of once per second. You only need to advance the clock display by one second in the ISR. In between the interrupts, you can put the MCU in very deep sleep (power-save sleep mode: nothing runs but Timer/Counter 2) and run for years on a couple of AA cells. Unless the display is power-hungry, obviously.
I did exactly this to build my 24-hour one handed wall clock. This link points now to the English translation of the original documentation in French.
Quartz calibration
If you do not calibrate your quartz, you can expect a significant drift, typically a few seconds per week. The drift rate depends on the stray capacitance of the traces that connect the crystal to the MCU. In principle, it could be removed by adding some extra, finely tuned capacitance. It is worth noting that you would have the same drift problem with an RTC.
If you are satisfied with this kind of accuracy, then live with it and be happy. However, if you care to measure the drift, you will notice that it is very stable. You can then easily compensate for it in software, and achieve an accuracy of a few seconds per year.
The algorithm for correcting the drift is very simple. From the measured drift, you figure out the precise delay between the interrupts, which should be very close to 109 nanoseconds, then:
#define ONE_SECOND 1000000000 // in nanoseconds
#define ONE_INTERRUPT 999993482 // for example
ISR(TIMER2_OVF_vect)
{
static uint32_t unaccounted_time;
unaccounted_time += ONE_INTERRUPT;
while (unaccounted_time >= ONE_SECOND) {
advance_display_by_one_second();
unaccounted_time -= ONE_SECOND;
}
}
In the above example, the quartz is slightly too fast, and the software compensates by “missing” a tick every few days. If the quartz was too slow, the same code would instead double-tick once every few days.
This kind of calibration could also be done for an RTC, but it would be significantly more complex because the RTC reports the time in a broken-down form that does not naturally lend itself to arithmetic operations.
Note: although my answer was accepted and has a higher vote score, make sure you read Edgar Bonet's great answer on how to make your Arduino keep time without an RTC.
I've been quite successful in using the DS1307 Real Time Clock. Here's a link to its datasheet.
Below are some of its features:
It uses IC interface for communication with Arduino, making it easy to program using the right libraries (available on the Net).
It is connected to Arduino through the SCL and SDA pins (analog A4 and A5 respectively), thus only using 2 pins.
It requires very little external components to run.
IT can be connected to a coin cell battery so it will keep time even while the Arduino is turned off. In its low power mode, the coin cell battery lasts for years.
It drifts very little (in my case it only drifts a few seconds per week).
It's not very expensive.
If you don't intend to use an RTC, you can replace the crystal that is commonly used to provide clock to arduino for a crystal oscillator module like this one from Farnel or this other one. They come in 4 pin packages like in the images below. They will generate a much more precise clock for your arduino.
Both modules mentioned have tolerances of 50 ppm and operate at 5V.
Again, just to be clear, these crystal oscillator modules are not to be confused with regular 2 pin crystal like this below. Those are part of the circuitry of external clocks for MCUs, for example.
The resonator you specified has a 0.3% stability, where the crystal or crystal oscillator (as mentioned by Ricardo) is 50ppm. Many times more stable. Not to even mention the temperature drift of resonator is horrible. Heating by sunlight will change it. Hence a resonator should not be used for keeping time over long periods.
Hence using either a crystal or crystal oscillator will get what you want. Either using it on the ATmega and set the fuses respectively or us one connected to an RTC.