Measuring time interval by using timer interrupts

Hello,
i would like to measure time intervals between specific events (lets say the time between a pin going from low to high which is triggered by a hall sensor or even a simple button). I need accuracy on this (sub ms), done some searching, and found out that probably the most accurate method for performing such tasks is enabling the timer interrupts and counting how many times it overflows. However, i can't get my head around how to start counting when a pin change occurs. Is it possible to trigger one interrupt that "sees" a pin change and another that starts counting and performs some sort of task after. I've displayed some sample code that enables timer interrupts and counts overflows. I am not concerned about prescaling and etc. for the momemt, and am trying to keep the code as simple as possible.
Once again i'll present the basic logic of what i want: an arduino pin change occurs--> timer1 (or whatever) starts counting --> timer1 overflows many times to a given value--> another pin change occurs--> timer1 stops counting--> some function is carried out --> the process starts over.
My sample code with timer1 interrupt set up.

// avr-libc library includes
#include <avr/io.h>
#include <avr/interrupt.h>
 

 int counts = 0;
 int pin = 13;
void setup()
{
    
     pinMode(pin, OUTPUT);
    // initialize Timer1
    cli();             // disable global interrupts
    TCCR1A = 0;        // set entire TCCR1A register to 0
    TCCR1B = 0;
 
    // enable Timer1 overflow interrupt:
    TIMSK1 = (1 << TOIE1);
    // Set CS10 bit so timer runs at clock speed:
    TCCR1B |= (1 << CS10);
    // enable global interrupts:
    sei();
    
}
void loop()
{
}
ISR(TIMER1_OVF_vect)
{
    count++;
    if (count > 1000)
   {
     digitalWrite(pin, HIGH);
   } 
   if (count > 1200)
   {
   digitalWrite(pin, LOW);
   count = 0;
   }
   
   
 
}

Thanks

You could connect your input to Pin 2 or Pin 3 and use attachInterrupt() to call a function when the signal goes up (or down). Then in the function you could note the time in microseconds. That should give you accuracy of about 1/250th of a millisecond.

Some examples:

There's some awesome stuff on that page, Nick. Thanks for doing all that work.

Do you have an example of using the input capture unit?

Yes, on this page:

Thank You all for the replies.

johnwasser:
You could connect your input to Pin 2 or Pin 3 and use attachInterrupt() to call a function when the signal goes up (or down). Then in the function you could note the time in microseconds. That should give you accuracy of about 1/250th of a millisecond.

Dear, Johnwasser,I could use that, however, as i investigated, counting overflows would be far more efficient due to less overhead resulting in less instructions that need executing compared to attachInterrupt.

Dear, Nick,
i found your examples very informative, however, i am very new to programming, and everything is a bit overwhelming at the moment. What i can gather is that your code (first example) for counting frequency operates by using two timers, one to count overflows, and one to count events. After a given number of overflows is counted and a number of events occurred the frequency is deduced. However, i am trying to do something similar, though different. Is it possible at all to start counting only when a pin goes low (or high, doesn't matter)? My application differs in such a way, that i can't afford the luxury of counting many pulses, because when a pin goes from low to high (or vice versa) some code has to be executed. Due to this code that was executed, the next time the pin goes from low to high i should get a different time reading and perform some sort of compensating algorithm. Thanks again for the help.

done some searching, and found out that probably the most accurate method for performing such tasks is enabling the timer interrupts and counting how many times it overflows.

I fail to see how periodically checking for whether an event has occurred is going to be more accurate than simply recording when the event occurs, as it occurs.

PaulS:

done some searching, and found out that probably the most accurate method for performing such tasks is enabling the timer interrupts and counting how many times it overflows.

I fail to see how periodically checking for whether an event has occurred is going to be more accurate than simply recording when the event occurs, as it occurs.

It's not quite periodically checking. The idea is to start counting when an event occurred (an interrupt has to be set up that recognizes a change in pin state). And as the counter overflows, overflow counts are recorded. This process should continue until another pin state change occurs (this should be triggered by an interrupt). As i understand it is kind of: an interrupt should set up a timer interrupt. As i said, i'm very new to programming, perhaps this sort of thing in not even achievable, i would very appreciate if someone could clear things up.

The idea is to start counting when an event occurred (an interrupt has to be set up that recognizes a change in pin state). And as the counter overflows, overflow counts are recorded. This process should continue until another pin state change occurs (this should be triggered by an interrupt).

In the Interrupt Service Routine that deals with the interrupt, it is possible to call micros() or millis() to record when the event happened.

When the ISR is called again, it can copy the recorded time to another variable (lastTime), and then update thisTime.

The interval between events is then trivial to compute. Nothing to count.

PaulS:

The idea is to start counting when an event occurred (an interrupt has to be set up that recognizes a change in pin state). And as the counter overflows, overflow counts are recorded. This process should continue until another pin state change occurs (this should be triggered by an interrupt).

In the Interrupt Service Routine that deals with the interrupt, it is possible to call micros() or millis() to record when the event happened.

When the ISR is called again, it can copy the recorded time to another variable (lastTime), and then update thisTime.

The interval between events is then trivial to compute. Nothing to count.

I understand what you are saying. Indeed, placing attachInterupt and calling millis would be a lot easier. But to my understanding attachInterrupt alone has unnecessary overhead, i.e. it has instructions executing that needn't be executed for such a task, right? Or would you suggest that i shouldn't bother and just go with attachInterrupt and millis? Thanks for your help.

Indeed, placing attachInterupt and calling millis would be a lot easier.

If you want to know EXACTLY when the event occurs, it's not only easier, it's the ONLY way.

Otherwise, all you can determine is that the first event occurred between time n and time n+i and that the second event occurred between time m and time m+i. I is the interval between when you check. The actual interval lies somewhere between m-n and m-n+2i. Depending on how often you check, 2i may or may not be significant.

Well, exact is relative, isn't it?

I recommend Nick's version of the input capture unit code he linked to earlier. It looks like better accuracy and isn't all that much more complex.

It seems like the input capture unit would be the most accurate way to time all sorts of things. If it isn't any harder to implement, why isn't it the default recommendation when people ask about pulse timing?

Simonas:
I understand what you are saying. Indeed, placing attachInterupt and calling millis would be a lot easier. But to my understanding attachInterrupt alone has unnecessary overhead, i.e. it has instructions executing that needn't be executed for such a task, right? Or would you suggest that i shouldn't bother and just go with attachInterrupt and millis? Thanks for your help.

attachInterrupt should just be called once generally. Thus its overhead is irrelevant.

There is a smallish overhead to handling interrupts, as documented here. Around 2.9 µS before your own handler is entered. However as micros() has a resolution of 4 µS we don't need to get too excited. And millis() has a resolution of approximately one millisecond.

TanHadron:
I recommend Nick's version of the input capture unit code he linked to earlier. It looks like better accuracy and isn't all that much more complex.

Yes the input capture unit will remember the time an event occurred to within a clock cycle from memory. Then it calls an interrupt (if you want it to) and you then fetch that figure.

TanHadron:
Do you have an example of using the input capture unit?

I modified my timers page to add an example of timing a discrete interval with the input capture unit.

Awesome, Nick. More karma for you!

PaulS:

Indeed, placing attachInterupt and calling millis would be a lot easier.

If you want to know EXACTLY when the event occurs, it's not only easier, it's the ONLY way.

Otherwise, all you can determine is that the first event occurred between time n and time n+i and that the second event occurred between time m and time m+i. I is the interval between when you check. The actual interval lies somewhere between m-n and m-n+2i. Depending on how often you check, 2i may or may not be significant.

Thank You Paul, that really cleared some things up. I'll attempt doing this. What i can roughly estimate for the moment is that my signal that i'll be detecting may be as fast as 10 kHz. So the rough time between two pulses is 100us. Like i said, i'll have to perform some calculations between these pulses, judging by the value of time that i acquired. Perhaps you could give some pointers on that. I've read that i should disable interrupts when performing calculations, and re-enabling them after, correct? In addition, should i avoid floats (heard these are heavy on the processor)?