Take the 2-minute tour ×
Electrical Engineering Stack Exchange is a question and answer site for electronics and electrical engineering professionals, students, and enthusiasts. It's 100% free, no registration required.

The micros() documentation notes that the return value will always be a multiple of 4.

Is there any way to get a higher resolution microsecond click, preferably down to the 1 microsecond level?

Dropping down to the AVR level is acceptable.

share|improve this question
    
Why do you insist on starting your title with a tag when I made it a perfectly English question? –  stevenvh Nov 26 '11 at 17:44
2  
Apologies Steven, I sincerely thought (and think) it's a good way to express the question succinctly and clearly. There was a lot of discussion about this, and Jeff agreed in some cases that it was a good way of asking. The discussion is here; the heatmaps are what convinced me that for these style of questions it pays to emphasize the operating environment. meta.stackexchange.com/questions/10647/writing-good-titles/… But, out of respect for your excellent answers, I would be happy to change it back if you think it's best. –  Mark Harrison Nov 28 '11 at 6:58
    
Is it possible to use it for pulsein() function? I need to measure pulses length in resolution les than 1 usec. –  user20449 Mar 20 '13 at 13:03
    
This space is reserved for answers to the question at top. If you have something to ask, start your own question. –  Olin Lathrop Mar 20 '13 at 13:37
add comment

migrated from stackoverflow.com Nov 21 '11 at 23:41

This question came from our site for professional and enthusiast programmers.

3 Answers

up vote 2 down vote accepted

Yes, depending your Arduino's basic clock rate. For example here are the counter-timer input frequencies and periods after pre-scaling, for an ATMega2560's counter-timer 2, and a basic clock rate of 16MHz:

    TCCR2B bits 2-0    Prescaler    Freq [KHz], Period [usec] after prescale
          0x0          (TC stopped)      --         --
          0x1                1        16000.        0.0625
          0x2                8         2000.        0.500
          0x3               32          500.        2.000
          0x4               64          250.        4.000
          0x5              128          125.        8.000
          0x6              256           62.5      16.000
          0x7             1024           15.625    64.000

The resulting interrupt rate would be: 16MHz / (prescaler * (255 - TCNT2))

You could get the timer to run at the full 16MHz (62.5nSec) though that's way faster than you need; 2MHz with an initial count of (255-2) would give you 1MHz interrupt rate. Divide that by 2 in your ISR:

extern uint32_t MicroSecClock = 0;

ISR(TIMER2_OVF_vect) {
  static uint_8 count;            // interrupt counter

  if( (++count & 0x01) == 0 )     // bump the interrupt counter
    ++MicroSecClock;              // & count uSec every other time.

  digitalWrite(53,toggle);
  TCNT2 = 253;                    // reset counter
  TIFR2 = 0x00;                   // clear timer overflow flag
};

The data sheet for your MCU is the basic resource; this article will give you (and gave me!) a good head-start.

share|improve this answer
add comment

If dropping down to AVR Level is acceptable (as you mentioned in your question), you can set up a timer and even get the ticks of the AVR's clock.

You need to refer to your AVR's datasheet because it differs within the different ATMegas and ATTinys. But the procedure is always the same. What you need to do is:

  • decide which prescaler to use (for example set it to 1, i.e. no prescaling if you want the actual CPU clock speed), refer to the TCCR documentation
  • set up a timer overflow interrupt, an interrupt handler and activate interrupts globally
  • activate the timer in the Timer/Counter Control Register TCCR

That way can get the exact ticks from the timer register, however you need to count the overflows manually. This is as precise as possible by technology.

Here is some example code for the outdated AT90S2313, but it gives you good hints what to do basically:

/* uC: AT90S2313 */
#include <avr/io.h>
#include <avr/interrupt.h>

int main(void)
{
  // set up timer 0
  TCCR0 = (1<<CS01); // Prescaler 8

  // enable overflow interrupt
  TIMSK |= (1<<TOIE0);

  // activate interrupts
  sei();

  while(1)
  {
     /* Do whatever you like */
  }
}


ISR (TIMER0_OVF_vect)
{    
   /*
      This gets called everytime there in an overflow in the timer register  
   */
}
share|improve this answer
    
Thank FeeJai. Can I set these interrupts within the context of an Arduino sketch? –  Mark Harrison Nov 22 '11 at 0:07
1  
I am not familiar with the arduino framework. But if it doesn't set up all the timers internally, you certainly can. Otherwise you can still read the timer registers and calculate yourself. –  FeeJai Nov 22 '11 at 1:30
    
Yes, you are programming in full C++ in Arduino and can use all the registers and symbols such as TIMSK, TOIE0 etc (copy timer setup from the atmega328p datasheet). It looks like you can't use the ISR() macro, instead use arduino.cc/en/Reference/AttachInterrupt . –  joeforker Nov 22 '11 at 20:22
add comment

Mark, I decided to write a new set of functions, based on the Arduino Atmega328 Timer2, and using overflow interrupts, to get precision to 0.5us. My code is available for download and use here:

http://electricrcaircraftguy.blogspot.com/2014/02/Timer2Counter-more-precise-Arduino-micros-function.html

Here's a brief description: "I wrote a "libary" to get 0.5us precision on a "micros()" replacement function, so that I can get repeatable results reading a PWM or PPM signal, to within 1us. I searched all around the internet and could not find something comparable (or that was easy to use, and maintained the Arduino's ability to write PWM signals via the Servo Libary), so I think this is my first major contribution to the world of Arduino and Radio Control."

share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.