Since it is not right to use millis() in an ISR to calculate duration of the input, Is it correct to use pulseIn()?
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
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– Mohsen Salahshoor2015年08月19日 10:15:48 +00:00Commented Aug 19, 2015 at 10:15
-
1It 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.2015年08月19日 10:20:30 +00:00Commented Aug 19, 2015 at 10:20 -
See: github.com/arduino/Arduino/issues/37002015年08月19日 10:25:22 +00:00Commented 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.
millis()
inside an ISR is fine. Waiting for its return value to change is not.