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

  • Why can't you use millis inside and ISR? I don't see why not.
    – Gerben
    Aug 17, 2015 at 19:01
  • Using millis() inside an ISR is fine. Waiting for its return value to change is not. Aug 17, 2015 at 19:23
  • @Gerben@Edgar see comments on Nick's answer. 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.
    – Nick Gammon
    Sep 16, 2015 at 21:28

2 Answers 2


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 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 (); 
    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)

  Serial.print ("Time taken = ");
  Serial.print (elapsedTime);
  Serial.println (" uS");
  done = false;

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


  • 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." 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.
    – Nick Gammon
    Aug 19, 2015 at 10:20
  • See: github.com/arduino/Arduino/issues/3700
    – Nick Gammon
    Aug 19, 2015 at 10:25

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.

Your Answer

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

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