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

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

About: I'm an aerospace research engineer with a B.S. in Aeronautical Engineering and an M.S. in Mechanical Engineering. I have a *tremendous* interest in Radio Control (RC) aircraft and have developed many skills i…

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 :)).

Step 2: Download & Extract the Timer2_Counter Code!

Go here:
-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.

Click the download link near the top, following any instructions written there to download and save the zip file. Extract the files.

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!

Thanks for reading.

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) - Nick Gammon's article on "Timers and counters"
2) - Nick Gammon's article on "Interrupts"
3) - 660 pg. ATmega328 datasheet

Happy coding!


Gabriel Staples

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

1 Person Made This Project!


  • Organization Challenge

    Organization Challenge
  • Baking Contest

    Baking Contest
  • Anything Goes Contest

    Anything Goes Contest



8 years ago on Introduction

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 :)


5 years ago

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.

If your objective


Reply 1 year ago

You are correct about resolution, precision, and accuracy. Thank you. I have since then mended my ways and begun using correct terms. :)


3 years ago

What is minimum timing(microseconds) that an arduino UNO can measure accurately.


Reply 3 years ago

Without testing it conclusively, I speculate 5us is the shortest pulse that can be measured by an ATmega328 mcu running at 16Mhz.


Nick Gammon, an Arduino expert I've learned a lot from, states here (, that it takes around "4 μs" to enter an ISR (Interrupt Service Routing, or interrupt handler), and "around 5 µS to enter and leave an ISR".

In order to measure a pulse, you need to interrupt on a pin change at the start of the pulse, enter the ISR, grab a timestamp (or use the input capture register if using the Timer 1 input capture feature, which is the best way to do it), and exit the ISR. Then, you need to do the same thing on the trailing edge of the pulse. Since it takes 4us to enter an ISR, I speculate the shortest pulse you could measure is 5us. Otherwise, the pulse will be over before you can even grab a timestamp from the leading edge of it. An Arduino can easily output a pulse, using the Output Compare registers in a timer, of 62.5ns, however, since that is the time it takes for 1 clock tick on a 16MHz clock, so this could be tested with 2 Arduinos where 1 generates a pulse anywhere between 62.5ns and 20us or so, and the other tries to read this pulse until it no longer can.

Anyway, without testing it conclusively, I speculate 5us is the shortest pulse that can be measured by an ATmega328 mcu running at 16Mhz. Let's walk through what this might look like: at 0us the edge occurs and the interrupt flag is triggered. At 4us you enter the ISR and store the timestamp (of 0us if reading the Input Capture register, or of 4us if reading a raw timestamp from a timer/counter). At 5us you exit the ISR, and the trailing edge of the pulse occurs, tripping the interrupt flag. At 9us you enter the ISR, and store the timestamp (of 5us if reading the Input Capture register, or of 9us if reading a raw timestamp from a timer/counter). At 10us you exit the ISR. Your main loop does the calculation of ending_timestamp - beginning_timestamp and you calculate 5-0 = 5us in the Input Capture case, or 9-4 = 5us in the raw timestamp case.

Perhaps I'm off a little and it would be more like 6us, but like I said, this could be tested. In either case, being able to do anything better than probably 20us or so would require knowledge of everything I said above, plus a very tight control over all interrupts and processes happening on the microcontroller to ensure that measuring the pulses takes highest priority, even possibly requiring turning on nested interrupts to ensure this interrupt measuring the pulse can interrupt other interrupt handlers (ISRs).

I hope that helps. Someday perhaps I'll actually do this test, get conclusive results, and post them on GitHub. Could be interesting, though I've personally never needed to measure anything < 20us ~ 30us or so yet, and usually measure more like 500us or more. Having said all that, my library here is *not* optimized to measure 5us pulses. I wrote it to measure 500~2500us pulses (servo "PWM signal" pulses), and my library probably wouldn't like anything less than somewhere in the vicinity of 15~30us or so (guestimated).


6 years ago

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


6 years ago

This is great, thank you so much!

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


6 years ago

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


Tecwyn Twmffat
Tecwyn Twmffat

Reply 6 years ago

Sounds interesting.

Thanks for the kind words "Danger!" Do you use Arduino much? I glanced at your instructables and a lot were on cooking and backpacking stuff.

If you'd like to follow my articles be sure to subscribe to my blog (link is under my name above) by clicking the envelope icon at the top right of the blog, as I write most of my articles on the blog. Thanks!