1

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 '15 at 19:01
  • Using millis() inside an ISR is fine. Waiting for its return value to change is not. – Edgar Bonet Aug 17 '15 at 19:23
  • @Gerben@Edgar see comments on Nick's answer. – Mohsen Salahshoor Aug 19 '15 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 '15 at 21:28
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

  • 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." – Mohsen Salahshoor Aug 19 '15 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 '15 at 10:20
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.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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