Accurate timers with an AVR

timer

An awful lot of microcontroller projects use timers to repeat an action every few minutes, hours, or days. While these timers can be as accurate as a cheap digital wrist watch, there are times when you need a microcontroller’s timer to measure exactly, losing no more than a few milliseconds a day. It’s not very hard to get a timer to this level as accuracy, as [Karl] shows us in a tutorial.

The problem with keeping time with a microcontroller has to do with the crystal, clock frequency, and hardware prescalers of your chip of choice. [Karl] started his project with an ATMega168 and a 20 MHz crystal and the prescaler set at 256. This made the 78.125 interrupts per second, but the lack of floating point arithmetic means one second for the microcontroller will be 0.9984 seconds to you and me.

[Karl]‘s solution to this problem was to have the ATMega count out 78 interrupts per second for seven seconds, then count out 79 interrupts for one second. It’s not terribly complicated, and now [Karl]‘s timers are as accurate as the crystal used for the ‘168’s clock.

Comments

  1. Arlet says:

    Simple solution is to keep an accumulator with the total number of cycles. In this case, the interrupt comes every 19,968 cycles, and a millisecond equals 20,000 cycles. At every interrupt do this:

    a += 19968;
    if( a >= 20000 )
    {
    msec++;
    a -= 20000;
    }

  2. Geebles says:

    Awesome! How does this compare with the Arduino millis() or the time library? Or is this what the article means by ‘accurate as a cheap wrist watch’. I’m interested as I’m building a clock around an Arduino, and debating the cost effectiveness of an RTC module

  3. Jeff Nichols says:

    “This made the 78.125 interrupts per second”

    20e6/256 != 78.125. That’s ignoring the whole grammar issue, too.

  4. Matthew says:

    Or you could use a clock-friendly crystal frequency. 20.48000 MHz with a prescaler of 256 gives 80,000 interrupts per second exactly.

  5. Matthew says:

    Jeff Nichols: Karl may be from Europe, where the , and . are swapped in numbers (e.g. 75.000,00 for 75 thousand point zero zero).

  6. Alex Rossie says:
  7. Max says:

    Why not use a watch crystall ?
    They are designed to give 32768 kHz (128*256).

  8. Martin says:

    Am I the only one who thinks “just set the prescaler to 1 and OCR1A to 20000-1″ ?
    But assuming you have to use one of the 8bit timers this approach is pretty reasonable.

  9. Willaim says:

    Been there done that.. temperature changes gain or lose a few seconds over time Ive pretty much given up on any accurate timing without a RTC on any micro you can get close with stuff like this but I’d recommend leaving a way to easily change the trim values w/o a reprogram

    • hat says:

      I know MSP430s with an AD converter (which is most of them) have an internal temp sensor. Do AVRs? You can get the tempco of most crystals from the manufacturer and compute the correction on the fly. And if you wanted to be really fancy, you could allow external updates of the ‘correct’ time to discipline the oscillator with a PLL.

  10. WitchDoc says:

    Actually there are several errors here, both in article as the original piece. Karl states; “There is no combination of prescalers and reload value that provides an accurate one millisecond interval.”. Which is wrong because he could have used a prescaler of 1 which would give 20000000 interrupts per second or 20000 per millisecond. Of course this doesn’t say anything on the accuracy of the crystal, if i am correct the 32Khz clock crystals are supposed to have better accuracy. It’s possible to run the micro on a 20Mhz crystal and use a second (32Khz) crystal just for timekeeping.

    • Arlet says:

      The device can’t handle anywhere near 20 million interrupts per second.

    • Daid says:

      Crystal accuracy is measured in PartsPerMillion (PPM) over the whole temperature range. Usually they are in the 200PPM range, or you can get them at 100PPM for higher accuracy. Which means you will lose 200 seconds every 1000000 seconds, in the worst case. Which means you can lose about 17 seconds every day in the worst case.

      I’ve done tests at stable temperature which gave me a 40ms lose every day at 20C with a 100PPM crystal. But real world conditions can vary.

      • hat says:

        I’m running ntpd on a few computers in a non-climate-controlled location, and I don’t see anywhere near 200PPM variation over about 5C to 30C, which is probably narrower than the range you’re talking about. This is using the ~3.5 MHz ACPI timecounter, so a cheap crystal. Actually, it’s closer to “a few” PPM over that range. Now, I *do* see a 30-60 PPM offset in the center frequency. The spec you’re looking at is probably the rated accuracy over the entire temperature range PLUS the frequency offset where the tempco is zero, plus things like stray capacitance, etc. If frequency stability over a wide temperature range is important, you should consider adding temperature compensation (check with the manufacturer for the tempco curve), a TCXO, or an OCXO.

        TL;DR: The bigger problem is probably the center frequency of your crystal.

  11. Tom the Brat says:

    The solution to the 78.125 (or 78,125, depending on what side of the pond) interrupt problem is quite simple.

    If you attempt to count seconds, yes, you’ll have to deal with the extra 1/8th of a tick each second, but just count the raw number of ticks. Then display the time by multiplying the number of ticks by 1000 and dividing by 78125. Now, the 1/8 of a tick problem will effect the calculated time, but never more than that 1/8th of a tick, but won’t accumulate second by second so your timepiece does not drift.

    Of course, the accuracy of the 20MHz clock becomes a problem. If you want 1 second accuracy over a year, you need the frequency accurate to within 1 in 31 million plus, and THAT’s no trivial matter.

  12. jc says:

    You should probably use an external temperature-corrected RTC or some good PPS source (like a GPS module for example)

  13. Eddie says:

    If you have access to an AC outlet, count the AC line frequency 60/50 Hz. The power utility in the US keeps the line frequency is pretty accurate over time.

    • SavannahLion says:

      I believe the power companies want to do away with that “accuracy”. I’m not sure of the logistics behind it but I think it was even mentioned on HaD a while back.

      • deathventure says:

        That would tick off no end of people if they did. There’s a lot of power control systems based on zero cross accuracy so if the frequency changes too much over time it’ll cause havoc.

    • Drone says:

      The AC Mains frequency varies a relatively large amount (for time-keeping) depending on load. Actually the grid suppliers (Public Electric Companies) use the variation in the mains frequency to determine grid load – and try to correct for it. IIRC there has been some debate about whether the grid suppliers should intentionally run the grid at a higher frequency when there is low-load to compensate for lower frequency during peak demand so the error averages out. Today, in the 1st-World at-least, grid suppliers compare their mains frequency to a GPS reference. IIRC (again) a company called “Aribter” supplies many of the GPS clock references to grid suppliers. Where I live (in the 3rd-World), the Electric Company’s line frequency is horrible – all over the map.

  14. IMHO It’s almost always best to run a timer in free-running mode and set a timer match interrupt at the correct intervals. That way you can get 16-bit or (even 32-bit accuracy) by calculating with fractional arithmetic with an arbitrary clock frequency and prescalar. Consider; a 20MHz clock with the prescalar at 256. There are 78.125 ticks per millisecond or (obviously) 20,000 ticks per 256 milliseconds. Thus if you have a 16-bit value, gNextOCR, then on each interrupt:

    gNextOCR +=gMilliSecondPeriod; // where short gMilliSecondPeriod = 20000 by default.
    OCRA=(gNextOCR>>8);

    will correctly (and easily) give the next 8-bit OCRA value with the fractional tick taken into consideration. Adjusting gMilliSecondPeriod by +/1 will adjust the period by 1/65536 or 1.3s per day, better than the adjustment with a standard 32KHz crystal. 32-bit variables will give a corresponding finer adjustment.

    The same accuracy can be achieved, e.g. with a 1MHz clock and a prescalar set to 64, giving 15.625 ticks per millisecond, here gMilliSecondPeriod would be 4000 by default and the same code above will give an OCRA update with *exactly* the same level of accuracy. The key thing is to make simple fractional arithmetic do the work for you; you can have virtually any clock rate and prescalar; achieve the same level of overall accuracy and adjustment, though obviously of course you can’t have millisecond interrupts if your combination gives a timer frequency <1KHz.

  15. CunningFellow says:

    1st up

    OP has a method that works fine.

    First post has a method that is conceptually easy (Think of it as Bresenham’s line algorithm for time)

    Everyone else sits here arguing about commas as decimal places rather than pointing out that 78.125 DOES NOT NEED FLOATING POINT MATHS to add up.

    POINT 125
    What about some simple fixed point boy
    No need to go running like a bull in a china shop straight for the clitoris//UM floating point unit.

    2nd

    NOW if we are really all about HACK-a-day why are we just suggesting straight away “Buy some companies already made accurate but proprietary RTC”

    Why doesn’t someone suggest instead of trim in software that trimming one of the load caps on the crystal could make it better that the 20ppm base at STP.

    If you really wanted to be fancy use a varactor under software control via a D/A converter. Then the CPU could measure the temp and try trim out that pesky 1ppm per degree celcius drift of the crystal.

    Now that would be a hack.

    • CunningFellow says:

      ah – I note that some evil script has filtered out my

      [put on John Cleese accent]
      [/John Cleese]

      around the bull in a china shop bit.

      must remember to use square braces in future

      • Galane says:

        Ever see the Mythbusters episode where they put a bunch of dishes on rickety shelves in a corral then turned a few bulls loose in it, with barely enough room to get between the shelves?

        The bulls never touched the shelves, no matter how much the crew ran them around and tried to startle and panic them.

        A bull in a china shop would be quite a non-disaster. ;)

  16. Preamp says:

    Use an oven to keep the crystal temperature constant. If the project is mains powered, you could attach the crystal to the transformer, which should have a constant temperature if the current draw is reasonably constant.

  17. mstone says:

    There’s a coincidence: I just finished reading ” Crystal Oscillator Design and Temperature Compensation” by Marvin Frerking a couple days ago.

    His favorite technique is to do a calibration run over the whole range of temperatures to learn how much offset you get at each temperature. You store those in an array, add a thermometer to your circuit, then use the microcontroller to control a varactor that pulls the crystal’s frequency enough to cancel the thermal effects. IIRC he said a well-tuned unit could get the short-term drift down to 10^-8.

    Long term drift is another story.. Dave Jones over at EEVBlog has a video about that: http://www.youtube.com/watch?v=0UksWKuVFFo

  18. MikeK says:

    While the project author says his timer is accurate, did he actually test it? I’m willing to bet he didn’t and that it’s nowhere near as accurate as he claims.

  19. Odokemono says:

    That guy should have first looked at my ovenized clock which is accurate down to less
    than a dozen millisecond per day: https://sites.google.com/site/dannychouinard/Home/atmel-avr-stuff/cheapovnxtalclk

  20. Drone says:

    Wikipedia has a nice table of “Crystal oscillator frequencies”. The table includes a column of crystals divisible by powers of 2 which may be appropriate for Real Time Clock (RTC) references…

    http://en.wikipedia.org/wiki/Crystal_oscillator_frequencies

    Xtal frequencies covered in the table (at my post-time) cover 32768KHz through 161.1328MHz. Typical applications for a specific frequency are also covered. Worth a look.

  21. seo vps says:

    Our users been seeing some great ranking improvements after they’ve started varying thier link building campaigns with the BHS VPS. We have some of the most popular SEO tools available, and if you’re interested feel free to check us out at http://goo.gl/55Xm4

  22. canal says:

    How to add function to turn on relay about 30 second in every hour? without RTC.. can you share the code please? (in Bascom code)

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

Join 97,838 other followers