1

Since it is not right to use millis() in an ISR to calculate duration of the input, Is it correct to use pulseIn()?

asked Aug 17, 2015 at 16:23
4
  • Why can't you use millis inside and ISR? I don't see why not. Commented Aug 17, 2015 at 19:01
  • Using millis() inside an ISR is fine. Waiting for its return value to change is not. Commented Aug 17, 2015 at 19:23
  • @Gerben@Edgar see comments on Nick's answer. Commented Aug 19, 2015 at 10:42
  • Can you accept my (or someone's) answer please so that this question is not bumped to the top as unanswered every month? Thanks! The page for attachInterrupt has been corrected. Commented Sep 16, 2015 at 21:28

2 Answers 2

1

It is quite OK to use millis() or micros() inside an ISR. In fact that is an excellent time to do it, because you are recording the time of the event shortly after it happened. Make sure the variable you are saving it to is unsigned long and volatile. Eg.

volatile unsigned long whenItHappened;
volatile bool eventHappened;
void myISR ()
 {
 whenItHappened = millis ();
 eventHappened = true;
 }

Now in your main loop you can test the eventHappened flag, so you will know if this event has happened, and whenItHappened is when.

It is not a good idea to use pulseIn() because that can wait quite a long time for a pulse. The default timeout for pulseIn is 1 second, which is far too long to wait inside an ISR.

If you want to time something (eg. how long it takes a ball to cross a sensor) use the interrupt twice, once to find the first event, and again to find the second.


Example

Example code which times how long a ball passes a sensor:

const byte LED = 12;
const byte photoTransistor = 2;
unsigned long startTime;
volatile unsigned long elapsedTime;
volatile boolean done;
void ballPasses ()
{
 // if low, ball is in front of light
 if (digitalRead (photoTransistor) == LOW)
 {
 startTime = micros (); 
 }
 else
 {
 elapsedTime = micros () - startTime; 
 done = true;
 }
 digitalWrite (LED, !digitalRead (LED)); 
}
void setup ()
{
 Serial.begin (115200);
 Serial.println ("Timer sketch started."); 
 pinMode (LED, OUTPUT);
 attachInterrupt (0, ballPasses, CHANGE);
}
void loop ()
 {
 if (!done)
 return;
 Serial.print ("Time taken = ");
 Serial.print (elapsedTime);
 Serial.println (" uS");
 done = false;
 }

That code used micros() for a more accurate timing.


Reference

answered Aug 17, 2015 at 20:42
3
  • But the doc page (arduino.cc/en/Reference/attachInterrupt) says its incorrect : "as delay() and millis() both rely on interrupts, they will not work while an ISR is running." Commented Aug 19, 2015 at 10:15
  • 1
    It also says (higher up the page): Inside the attached function, delay() won't work and the value returned by millis() will not increment. That is my point. millis() won't increment but it will return an accurate figure. I'll raise a bug report about the "will not work" phrase further down the page. Commented Aug 19, 2015 at 10:20
  • See: github.com/arduino/Arduino/issues/3700 Commented Aug 19, 2015 at 10:25
0

You shouldn't really use anything much in interrupts. Using anything that runs for a period of time is usually bad since no other interrupts can happen at the same time.

It is more normal to use the interrupt to set a flag that is then checked within your main loop to determine what should be done.

answered Aug 17, 2015 at 17:06

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.