I’m being lazy – I know that people have posted here on the accuracy and stability of the Arduino clock (Nano or Uno), please could someone remind me of the numbers or point to the posts?
Context – I want to partially decode a DCF77-encoded signal being generated by a GPS-locked source. I am only interested in the “top of the minute” sync pulse and bit 18 of the carousel which is the DST indicator. Easy to detect the sync pulse from its extended length, the easiest way to detect the DST signal is just to sample the signal at a known time interval from the sync pulse (18150ms if my calculation is correct), timed using millis(). So for tolerancing purposes just want to make sure there is enough margin to cope with clock errors.
For millis() I think the clock is the least of your worries. The Arduino reference says:
“millis() is incremented (for 16 MHz AVR chips and some others) every 1.024 milliseconds, then incrementing by 2 (rather than 1) every 41 or 42 ticks, to pull it back into synch; thus some millis() values are skipped. For accurate timing over short intervals, consider using micros().”
The crystal on even a cheap clone should be more than good enough for this application. For best performance and the ability to know exactly what is going on use the hardware timers directly.
First off, many Ardiunos use Ceramic Resonators, not Crystals. Resonators are typically only within 0.5% of nominal frequency, are distinctly temperature sensitive, and not particularly stable.
Here’s a list of frequencies from an Arduion Mega2560 resonator, nominal 16000000Hz measured at GPS 1 second intervals:
Lowest is 15983918Hz, highest is 15983941Hz, jumping within a 21Hz range over 23 seconds, even though the temperature hasn’t altered. Resonators aren’t precision timekeepers!
For much better stability the Leonardo and Micropro Arduinos are clocked with real crystals, but these are the ordinary 100ppm type, and not temperature compensated. Actually, all those I’ve measured have been closer to 50ppm than 100ppm, so not bad. But the lack of temp compensation means a Leonardo programmed as a digital clock drifts noticeably over a few days compared with a digital clock.
For syncing to DCF I agree with Robert – ordinary Arduino accuracy should be ‘good enough’. I’d use micros() too. micros() counts in 4uS ticks, and wraps every 70 minutes or so, which I think makes it better suited to timing a 18150mS gap.
Now I’ve discovered the joys of Arduino hardware timers, I’m inclined to use them for a job like this. Rather than loop with an IF statement calling micros() repeatedly to see if 18150mS has elapsed, it’s more accurate and performant to set a timer for 18150mS and have it call an interrupt function after that time has elapsed complete. Using an interrupt avoids delays caused by the repeated IF check, and makes the DCF event handling pretty much independent of whatever else the Arduino has to do.
Some time ago, I made a display (encoder) for my mini lathe. This code also decode the signal based on timing. If you need inspiration, have a look at the code
Now you need to write a plug in to include so that people like me don’t have to get involved in setting registers (which makes my head hurt)
This Arduino timer calculator is a good start. You type in the required frequency, it does the sums, and generates an example program with all the required register settings.
However, apologies to John, I think my advice that a hardware timer is a good way of generating an 18.15 second delay is wrong! Or at least, more complicated to code than he needs. The problem is that 18.15 seconds is considerably longer than the maximum delay that can be counted in a 16 bit hardware timer. Overcoming the limitation isn’t exactly rocket science, but having to do more work is always unwelcome!
Thanks for the suggestions all. Using micros() is probably the right way to go. I’m not sure how significant the “if” statement delay would be overall since the processor will be doing virtually nothing else for most of the time. Some calibration needed I think.
Just to close this off. I eventually settled on an approach that uses interrupts on both the positive and negative edges of the waveform to measure timings using micros(). What I’m developing is a unit that drives a Gents impulse dial from a DCF77 encoded signal from a GPS receiver on a roof, sent down to the clock over a current loop interface. It generates a pulse every 30s to drive the dial; automatically copes with BST and GMT changes in March and October; and provides a method for initially setting the dial (which isn’t so easy when the dial can only run forwards).
Author
Posts
Viewing 9 posts - 1 through 9 (of 9 total)
Please log in to reply to this topic. Registering is free and easy using the links on the menu at the top of this page.