The other answers are very good, but I want to elaborate on how micros() works. It always reads the current hardware timer (possibly TCNT0) which is constantly being updated by the hardware (in fact, every 4 µs because of the prescaler of 64). It then adds in the Timer 0 overflow count, which is updated by a timer overflow interrupt (multiplied by 256).
Thus, even inside an ISR, you can rely on micros() updating. However if you wait too long then you miss the overflow update, and then the result returned will go down (i.e you will get 253, 254, 255, 0, 1, 2, 3 etc.)
This is micros() - slightly simplified to remove defines for other processors:
unsigned long micros() {
unsigned long m;
uint8_t oldSREG = SREG, t;
cli();
m = timer0_overflow_count;
t = TCNT0;
if ((TIFR0 & _BV(TOV0)) && (t < 255))
m++;
SREG = oldSREG;
return ((m << 8) + t) * (64 / clockCyclesPerMicrosecond());
}
The code above allows for the overflow (it checks the TOV0 bit) so it can cope with the overflow while interrupts are off but only once - there is no provision for handling two overflows.
TLDR;
- Don't do delays inside an ISR
- If you must do them, you can time then with
micros()but notmillis(). AlsodelayMicroseconds()is a possibility. - Don't delay more than 500 µs or so, or you'll miss a timer overflow.
- Even short delays may cause you to you miss incoming serial data (at 115200 baud you will get a new character every 87 µs).
The other answers are very good, but I want to elaborate on how micros() works. It always reads the current hardware timer (possibly TCNT0) which is constantly being updated by the hardware (in fact, every 4 µs because of the prescaler of 64). It then adds in the Timer 0 overflow count, which is updated by a timer overflow interrupt (multiplied by 256).
Thus, even inside an ISR, you can rely on micros() updating. However if you wait too long then you miss the overflow update, and then the result returned will go down (i.e you will get 253, 254, 255, 0, 1, 2, 3 etc.)
This is micros() - slightly simplified to remove defines for other processors:
unsigned long micros() {
unsigned long m;
uint8_t oldSREG = SREG, t;
cli();
m = timer0_overflow_count;
t = TCNT0;
if ((TIFR0 & _BV(TOV0)) && (t < 255))
m++;
SREG = oldSREG;
return ((m << 8) + t) * (64 / clockCyclesPerMicrosecond());
}
The code above allows for the overflow (it checks the TOV0 bit) so it can cope with the overflow while interrupts are off but only once - there is no provision for handling two overflows.
TLDR;
- Don't do delays inside an ISR
- If you must do them, you can time then with
micros()but notmillis(). AlsodelayMicroseconds()is a possibility. - Don't delay more than 500 µs or so, or you'll miss a timer overflow.
- Even short delays may cause you to you miss incoming serial data (at 115200 baud you will get a new character every 87 µs).
It is not wrong to use millis() or micros() within an interrupt routine.
It is wrong to use them incorrectly.
The main thing here is that while you are in an interrupt routine "the clock isn't ticking". millis() and micros() won't change (well, micros() will initially, but once it goes past that magic millisecond point where a millisecond tick is required it all falls apart.)
So you can certainly call on millis() or micros() to find out the current time within your ISR, but don't expect that time to change.
It is that lack of change in the time that is being warned about in the quote you provide. delay() relies on millis() changing to know how much time has passed. Since it doesn't change delay() can never finish.
So essentially millis() and micros() will tell you the time when your ISR was called no matter when in your ISR you use them.