Don't use millis() or micros(), or delay() or even delayMicroseconds() in your project
timers - Using millis() and micros() inside an interrupt routine - Arduino Stack Exchange
Arduino Micros() Question
Using micros() over a lo..ng time?
Videos
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.
I want a source of semi-random numbers for a dice-roller. I did consider using the random() and randomseed() functions but instead I decided to try and take the output of micros() when a button is pressed and just use the least significant digit.
This means I get a long number and have to throw away everything except for the one or two least significant digits. But does anyone know how to do that? If it was all in binary then it'd be easy as I could just AND the number with zeros to dispose of unwanted elements but in a raw long it's more tricky. I did consider converting the long to binary but I'm not 100% sure how to.
Does anyone have any advice?