# How to Get an Arduino Micros() Function With 0.5us Precision

23,898

30

9

Published

## Introduction: How to Get an Arduino Micros() Function With 0.5us Precision

I love Arduino microcontroller programming, and I regularly use it in aerospace research, as well as in home projects. As I work on my many home projects, however, I frequently find myself needing a very precise timer. This is because my home projects focus around Radio Control (RC) aircraft, and RC hobby communication signals are timing-based signals. These RC communication signals are called PWM (Pulse Width Modulation) and PPM (Pulse Position Modulation). In the signals, a full stick deflection in one direction, on a hand-held radio transmitter, usually corresponds to ~1000us (microseconds), and a full stick deflection in the opposite direction corresponds to ~2000us.

To measure the timing in these signals, I first used the Arduino micros() function, in conjunction with external interrupts. The built-in Arduino micros() function is good, but not good enough for my needs. It has a precision of 4us (see here). This means that if I'm reading in a PWM signal that I know is exactly 1500us (center-stick position on a hand-held transmitter), I would see readings of 1496, 1504, 1500, and even sometimes 1492 or 1508us. This is too much deviation.

So...I looked and I looked and I looked for a solution. The only solution I could find used the Atmega328 microcontroller's Timer1, which is unacceptable for my needs, because then I lose use of the Arduino servo library. Therefore, I decided to do a ton of reading and get down into the guts of the microcontroller, accessing the Atmel's timers directly, and writing my own timer function.

From this endeavor is born my Timer2_Counter "library," which provides functions which can be used in place of the micros() function, and which provide a precision of 0.5us, which is 8x better than the micros() function!

For more detailed information on my code, as well as the latest version of my code, including a full list of its functions, please refer to my article here:
Arduino micros() function with 0.5us precision - using my Timer2_Counter "Library".

## Step 1: Make Sure You Have an Arduino

This code is based on the Arduinos that use the Atmel ATmega328 microcontroller, such as the Arduino Uno and Nano. I highly recommend the Elegoo Uno kits from Amazon, as they are the best value I've seen, so check them out here. Their Uno kit prices range from ~\$17 to ~\$60, but they include tons of parts and will keep you busy for many months (if not years :)).

Go here: http://electricrcaircraftguy.blogspot.com/2014/02/Timer2Counter-more-precise-Arduino-micros-function.html
-This is where the most up-to-date article on this code, and link to download the code, will always be kept. Refer to this main page for any future changes to the code.

Feel free to check out my other articles by looking at the menus down the right side of the screen. Check out my most recent article by going to "Blog Home," and be sure to subscribe and share using the icons at the top right!
-Links to additional articles you may be interested in reading are at the very bottom of this instructable.

## Step 3: Open the Example File in Your Arduino IDE

Click the "Timer2_Counter_Basic_Example.ino" file to open it in your Arduino IDE.  When the IDE opens, notice that it automatically opens the "Timer2_Counter.ino" file with it, as a second tab.  Click the tab to view its contents, including detailed descriptions of the available functions.

To get access to my Timer2_Counter 0.5us-precision timing functions, you must first call "setup_T2();" in order to properly set up the Atmega Timer2 prescalers and such.  In my example code, I called this function within the Arduino setup() function.

This timer is 8x more precise than what the built-in Arduino micros() function gives you!

You can call "get_T2_micros();" to get the microsecond value of the timer, down to the nearest 0.5 microsecond value, or you can call "get_T2_count();" to get the count value on the microcontroller's Timer2.  Since the count value increments one count every 0.5us, dividing this value by 2 gives you the microsecond value on the timer.

This Timer2_Counter code automatically takes care of the 8-bit timer overflows via an interrupt, and will therefore return count values from 0 to 4,294,967,296, since it returns count values as an unsigned long data type.  This corresponds to microsecond values of 0us to 2,147,483,648us.  This means that the timer can run for up to 35.79 minutes before overflowing back to 0.  If you'd like to manually reset the timer back to zero you may call the "reset_T2();" function.

Again, for a full description of the code, refer to my main article here, as well as to the documentation within the Timer2_Counter tab, which automatically opened up in the Arduino IDE when you opened up the "Timer2_Counter_Basic_Example.ino" file just a minute ago.

## Step 4: Run the Example and View the Output

Upload the code to your Arduino and open up the Serial Monitor to view the output.  Be sure your Serial Monitor baud rate is set to 115200.  This is what you will see.  As you study my example code and compare it to this output you will see how I show various methods to measure a time interval, and how I compare them to the precision of the time interval as measured by micros().

Note that this example code does *not* show clearly the true benefit of using my Timer2_Counter functions.  Rather, it simply shows how to use them.  If you ever use my Timer2_Counter to measure a timed signal, or the time span of any recurring event, however, you will see that it returns much more precise and consistent values than using the micros() function!

Don't forget to go back to Step 1 and subscribe to my blog if you haven't done so yet.

Next step: references and additional articles to check out.

## Step 5: References

My sincere thanks to Massimo Banzi and all of the developers who went into making Arduino possible!

Here are my primary references that helped me learn how to write this code:

Primary References:
1) http://www.gammon.com.au/forum/?id=11504 - Nick Gammon's article on "Timers and counters"
2) http://www.gammon.com.au/forum/?id=11488 - Nick Gammon's article on "Interrupts"
3) http://www.atmel.com/Images/Atmel-8271-8-bit-AVR-Microcontroller-ATmega48A-48PA-88A-88PA-168A-168PA-328-328P_datasheet.pdf - 660 pg. ATmega328 datasheet

Happy coding!

Sincerely,

Gabriel Staples
http://electricrcaircraftguy.blogspot.com/

=======================================================
Other Articles I've Written That You May Be Interested in Reading:

1) The Power of Arduino
2) The Goal of a Lifetime
3) A Few Tips & Tricks: Arduinos, PCB Tricopter Frames, Home-made Acid Etchant for Copper
4) Propeller Static & Dynamic Thrust Calculation
5) Arduino Power, Current, and Voltage Limitations
6) Quick Tip: 4 Ways to Power an Arduino

## Recommendations

• ### Arduino Class

69,893 Enrolled

• ### Planter Challenge

We have a be nice policy.

## Questions

great project man! =D

I'll definetely use it when dealing with precision timing!

Thanks for sharing this! The references are really helpful too! I can't wait to see what other sorts of projects you post :)

Good project if your goal is to be able to tell if two timings differ by .5µs or more. This would be the resolution of your measuring instrument.

The precision has to do with the repeatbility of the measurement (do I get the same value when measuring the same duration several times). And since we are it the accuracy is how close the measurement is to a given standard.

I fear that if you are after precision or accuracy in the microsecond range or below Arduino by itself is simply not up to the challenge : its crystal frequency (or oscillator for some versions) can be off by tens of ppm, and then there's the temperature drift.

This specific parameter is never mentionned in the Arduino specs. To get an idea for it just use an Arduino to measure the PPS (pulse per second) signal of a GPS (accurate to a few nanoseconds) and see how many microseconds away it is from 1 second.

Hi dear . thank you very much for sharing .many thanks.

This is great, thank you so much!

I've been tearing out my hair with this problem, I wish I had found you sooner!

You can get accurate timing by using the capture event for timer1. See the ATmega48P series data sheet, section 16.6. This is done in hardware, with a delay of only 1 or 2 CPU cycles, and is not influenced by interrupt response times. The capture produces an interrupt, in whose ISR you read the capture register - you only have to read it before the next capture event interrupt. The ATxmega devices are more flexible, and I'm starting to work on the SAMD21, where things get more complicated

Jerry