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 not millis(). Also delayMicroseconds() 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).
Answer from Nick Gammon on Stack Exchange
Top answer
1 of 4
21

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 not millis(). Also delayMicroseconds() 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).
2 of 4
9

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.

🌐
Arduino Forum
forum.arduino.cc › projects › programming
micros() on interrupt - Programming - Arduino Forum
July 25, 2018 - Hi, I'm trying to read rpm. I have an timer interrupt that enables interruptPin/code. Te interrupt code is: void RPMISR(){ if(RPMPulseCount == 0){ RPMStartTime=micros(); RPMPulseCount++; } else if(RPMPulseCount > 0 && RPMPulsesToMeasure > RPMPulseCount){ RPMPulseCount++; } else if(RPMPulseCount == RPMPulsesToMeasure) { detachInterrupt(digitalPinToInterrupt(RPMPin)); RPMEndTime=micros(); RPM=((1000000/((RPMEndTime-RPMStartTime)/(RPMPulseCount)))/TriggerToo...
Discussions

Using millis() or micros() in an ISR
I am testing my sketch by asking the Arduino to output the time taken by millis() at every interrupt, to which I keep getting 0s returned on the serial monitor. Intrigued, I tried using micros() to which I kept getting 500s returned on the serial monitor. Does anyone have any idea as to why ... More on forum.arduino.cc
🌐 forum.arduino.cc
14
0
July 27, 2018
millis/micros/interrupts
Hey people, trying to wrap my head around all this programming, could some one point me in the right direction so i can have a look at the code behind millis/micros. Also i have got my head around interrupts and timer manipulation, those of you who do a lot of coding, could you give me a few ... More on forum.arduino.cc
🌐 forum.arduino.cc
10
0
June 13, 2016
Micros() within interrupt - limitations or alternatives?
I have an ISR that generally executes very quickly, but needs to test for signal loss timeouts. I believe that micros() will work within an interrupt, at least up to some point before the clock overflows. Can anyone tell me what is the minimum time (if any) I can count on from micros() working ... More on forum.arduino.cc
🌐 forum.arduino.cc
6
0
September 4, 2014
Inaccurate micros() with interrupts
I observed that the micros() function is not accurate when called inside an interrupt (Arduino pro 5V 16 mMHz) The structure of the code is similar to the following: volatile unsigned long trig_time = 0; volatile byte … More on forum.arduino.cc
🌐 forum.arduino.cc
10
0
November 13, 2013
Top answer
1 of 1
3

Even tachometer() and the function that updates millis() are called from an interrupt, so even it would "break" your code.

How much would this ruin your lecture? Not very much. Arduino 2009, with using a crystal for 16 MHz, has a drift of many seconds at day. Arduino Uno, which uses a less precise oscillator, would drift a lot more.

So, unless you are doing a lot of calculation in the interrupt routine, you are fine. Also remember that a micros() call cost you 4 µs (in fact you will see it growing 4 by 4... or this was to have Timer0 to overflow every second? Take a look at the timer prescaler; you can change it if it does not break the Servo lib. It will break millis() and micros(), and you can use Timer1 or Timer2, but Timer0 is the only 16-bit timer, so it depends on you), so this is your real precision killer.

I would suggest to eliminate the function call in the interrupt:

unsigned long tmpTime;
void tachometer() {

    /* Determine time between rotations of engine (pulses from tachometer) */
    tmpTime = micros();
    period = tmpTime - microseconds;
    microseconds = tmpTime;
}

And even attachInterrupt call an ISR that call your function. You may implement attachInterrupt by yourself so you implement the ISR directly (one fewer function call, and function calls are relatively expensive as you have to work with the stack and registers).

Also don't use micros(), which does a lot of things (read the Timer0 actual count, and calculate count to µs, and is a function call); just read the timer register directly and do the difference with that value, and do the translation of count to µs into loop(). That way it should be a lot faster.

I'm not writing code as you just have to open Arduino's library and look at what they do, and replicate it by yourself. It is quite easy as you have a working example, an ATmega datasheet and a lot of tutorials on timers, interrupts and even PWM.

🌐
The Robotics Back-End
roboticsbackend.com › home › arduino millis() vs micros()
Arduino millis() vs micros() - The Robotics Back-End
October 11, 2021 - Plus, if you stay too long inside an interrupt, you might miss important micros interrupts and your micros() will not be on time anymore! Anyway, keep that in mind: when using interrupts, keep the code very short and quick. Only modify some variables that you’ll process later in the main Arduino ...
🌐
Arduino Forum
forum.arduino.cc › projects › programming
Using millis() or micros() in an ISR - Programming - Arduino Forum
July 27, 2018 - I am testing my sketch by asking the Arduino to output the time taken by millis() at every interrupt, to which I keep getting 0s returned on the serial monitor. Intrigued, I tried using micros() to which I kept getting 500s returned on the serial monitor. Does anyone have any idea as to why ...
🌐
Instructables
instructables.com › circuits › arduino
How to Get an Arduino Micros() Function With 0.5us Precision : 5 Steps - Instructables
October 17, 2017 - How to Get an Arduino Micros() Function With 0.5us Precision: I love Arduino microcontroller programming, and I regularly use it in aerospace research, as well as in home projects. As I work on my many home projects, however, I frequently find myself needing a very precise timer.
🌐
Arduino Forum
forum.arduino.cc › projects › programming
millis/micros/interrupts - Programming - Arduino Forum
June 13, 2016 - Hey people, trying to wrap my head around all this programming, could some one point me in the right direction so i can have a look at the code behind millis/micros. Also i have got my head around interrupts and timer manipulation, those of you who do a lot of coding, could you give me a few of your best practice guidelines for the use of interrupts. one thing im still a little unsure of is the use of 'clear flag' when using interrupts.
Find elsewhere
🌐
Arduino Forum
forum.arduino.cc › projects › general guidance
Micros() within interrupt - limitations or alternatives? - General Guidance - Arduino Forum
September 4, 2014 - I have an ISR that generally executes very quickly, but needs to test for signal loss timeouts. I believe that micros() will work within an interrupt, at least up to some point before the clock overflows. Can anyone tell…
🌐
Arduino Forum
forum.arduino.cc › projects › programming
Inaccurate micros() with interrupts - Programming - Arduino Forum
November 13, 2013 - I observed that the micros() function is not accurate when called inside an interrupt (Arduino pro 5V 16 mMHz) The structure of the code is similar to the following: volatile unsigned long trig_time = 0; volatile byte trig_flag = 0; void setup() { attachInterrupt(0, trig_detected, RISING); } void loop() { if (trig_flag == 1){ // Do some timimg calculations with trig_time trig_flag = 0; } else { // Do other stuff } } void trig_detected (){ trig_time = micros(); tr...
🌐
Wordpress
ucexperiment.wordpress.com › 2012 › 03 › 17 › examination-of-the-arduino-micros-function
Examination of the Arduino micros() Function | µC eXperiment
July 28, 2016 - Background To fully understand the micros() function, you first need to understand the Timer #0 overflow interrupt handler which was covered in this post. Recall the typical Ardiuno runs on a 16MHz oscillator. Both the millis() and micros() functions base their calculations on the Arduino Timer #0, which is running with a prescale of 64.…
🌐
GitHub
github.com › arduino › Arduino › issues › 1301
Possible bug in micros() when called inside ISR? (Due) · Issue #1301 · arduino/Arduino
March 2, 2013 - Period) of an input signal on pin 28 (in Arduino due). The signal is a square wave 0/3.3V with PWM 50%. For example I set the frequency to 2000Hz ( period of 500 micro second ) with a function generation. this is the simple code: volatile unsigned long time, Time1, Time2, Period =0; volatile int i=0; int Signal=28; void setup() { Serial.begin(9600); pinMode(Signal,INPUT); attachInterrupt(Signal,InterruptSegnaleGiriT,FALLING); //Interrupt on Falling Edge } void loop() { if(Period<490 || Period >510){ Serial.println(Period); Serial.println(Time1); Serial.println(Time2); Serial.println(""); } void InterruptSegnaleGiriT(){ time=micros(); if(i==0){ Time1=time; i=1; return; } if(i==1){ Time2=time; Period=(Time2-Time1); i=0; return; } } If the function micros work fine, this code does not print anything.
Author   arduino
🌐
Arduino Forum
forum.arduino.cc › projects › programming
Is there problems to use millis() and micros() in the interrupt method? - Programming - Arduino Forum
December 28, 2016 - Board Uno. I need to measure the time for a wheels rotation. I have a hall effect sensor to pin 2 and use interrupt. The question is: How is it with the millis() and micros()? I have read that there is problem to use this in the interrupt method!? In my solution I have micros() in the interrupt method and everything seems to function OK, and for a very long time two days.
🌐
DeepBlue
deepbluembedded.com › home › blog › arduino micros() function – (millis vs micros)
Arduino Micros() Function - (millis vs micros)
August 17, 2023 - The Arduino micros() is a function that returns to you the time elapsed (in microseconds) since the Arduino board was powered up. Which can be used to create a time base for various events in your applications (like LED blinking, short pulse ...
🌐
Arduino
docs.arduino.cc › language-reference › en › functions › external-interrupts › attachInterrupt
attachInterrupt() | Arduino Documentation
April 24, 2025 - delay() requires interrupts to work, it will not function if called inside an ISR. micros() works initially but starts behaving erratically after 1-2 ms.
🌐
Arduino
docs.arduino.cc › language-reference › en › functions › interrupts › interrupts
interrupts() | Arduino Documentation
interrupts()noInterrupts() delay()delayMicroseconds()micros()millis() random()randomSeed() SPIPrintSerialStreamWire · KeyboardMouse · Wi-Fi OverviewWiFi NetworkIPAddressWiFiClientWiFiServerWiFiUDP · Home / Programming / Language Reference / Functions / interrupts() Last revision 06/05/2025 ·
🌐
Arduino Forum
forum.arduino.cc › forum 2005-2010 (read only) › software › bugs & suggestions
calling millis() or micros() from interrupt code - Bugs & Suggestions - Arduino Forum
March 1, 2009 - I'm running into a problem when calling millis() or micros() from within interrupt code. Strange things happen to timing, all of a sudden all sorts of polling dependent on time start running erratically, e.g. checking for millis() inside loop() gives unexpected results.
🌐
SparkFun Community
community.sparkfun.com › development boards › arduino
Interrupts and micros() (Arduino based EFI) - Arduino - SparkFun Community
April 18, 2014 - If I have a program loop that is keeping track of time using micros() and I use an external interrupt ISR that has a delayMicroseconds() up to 51 milliseconds (max, but this condition is highly unlikely, and yes, I’m awa…
🌐
GitHub
github.com › espressif › arduino-esp32 › issues › 5282
Issue with millis and micros with interrupt. · Issue #5282 · espressif/arduino-esp32
June 11, 2021 - As per the source of the interrupt, the output value is 101 in the serial monitor. what I am trying to do is calculate the RPM of a motor using a proximity sensor. According to me I think the reason is due to millis and/or micros used with interrupt cause the issue.
Author   espressif
🌐
Arduino Getting Started
arduinogetstarted.com › reference › attachinterrupt
attachInterrupt() | Arduino Getting Started
5 days ago - If your sketch uses multiple ISRs, ... to work, it will not work if called inside an ISR. micros() works initially but will start behaving erratically after 1-2 ms....