🌐
Arduino Getting Started
arduinogetstarted.com › reference › arduino-micros
micros() | Arduino Getting Started
June 5, 2026 - Learn micros() example code, reference, definition. Returns the number of microseconds since the Arduino board began running the current program. Returns the number of microseconds since the Arduino board began running the current program.
🌐
DeepBlue
deepbluembedded.com › home › blog › arduino micros() function – (millis vs micros)
Arduino Micros() Function - (millis vs micros)
August 17, 2023 - Without further ado, let’s get right into it! ... The Arduino micros() is a function that returns to you the time elapsed (in microseconds) since the Arduino board was powered up.
🌐
TutorialsPoint
tutorialspoint.com › arduino › arduino_micros_function.htm
Arduino - micros () function
The micros() function returns the number of microseconds from the time, the Arduino board begins running the current program. This number overflows i.e. goes back to zero after approximately 70 minutes.
🌐
Arduino
docs.arduino.cc › language-reference › en › functions › time › micros
micros() | Arduino Documentation
June 5, 2025 - This function returns the number of microseconds since the Arduino board began running the current program. Data type: ... The code returns the number of microseconds since the Arduino board began running the current program. ... There are 1,000 microseconds in a millisecond and 1,000,000 ...
🌐
The Robotics Back-End
roboticsbackend.com › home › arduino millis() vs micros()
Arduino millis() vs micros() - The Robotics Back-End
October 11, 2021 - The millis() and micros() both store the current time since the Arduino started, in an unsigned long variable. On 16 bits Arduino (Uno, Mega, etc), an unsigned long is stored on 4 bytes, or 32 bits.
🌐
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.
🌐
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.…
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.

🌐
Mechatronics LAB
mechatronicslab.net › home › lessons › arduino programming handbook › 16 timers & delays › 16.4 using micros() for microsecond resolution in arduino programming
16.4 Using micros() for Microsecond Resolution in Arduino Programming - Mechatronics LAB
The micros() function returns the number of microseconds since the Arduino board began running the current program. One microsecond is a millionth of a second. Unlike delayMicroseconds(), which simply pauses, micros() lets you measure very short time intervals without stopping your program.
Find elsewhere
🌐
Arduino Forum
forum.arduino.cc › projects › programming
Arduino micros function - Programming - Arduino Forum
May 9, 2020 - Hi all I have a very specific question about the Arduino micros() function. Only purpose is to understand and learn, so I do NOT have a practical issue. But I hope someone will be able to enlighten me. The function (which I found on a forum): unsigned long micros() { unsigned long m; uint8_t oldSREG = SREG, t; cli(); m = timer0_overflow_count; #if defined(TCNT0) t = TCNT0; #elif defined(TCNT0L) t = TCNT0L; #else #error TIMER 0 not defined #endif #ifde...
🌐
Circuit Geeks
circuitgeeks.com › home › arduino millis() and micros()
Arduino millis() and micros()
March 2, 2022 - micros() returns the number of microseconds passed since the Arduino started running the program. If you need more precise time you should use micros(). But keep it in mind that this number will overflow (go back to zero) very quickly, after ...
🌐
Arduino Forum
forum.arduino.cc › projects › programming
Yet Another Tutorial On Timing With millis()/micros() - Programming - Arduino Forum
October 18, 2017 - Since I've had success with developing an idea to preproduction prototype stage using Arduinos, I'm giving back to the community by spamming several subfora with things I've worked out through my dev process that I know people have asked about. ("I know people asked about" because I also asked, ...
🌐
Arduino Forum
forum.arduino.cc › projects › programming
Why is micros() so much slower than millis()? - Programming - Arduino Forum
August 18, 2021 - I set up a sketch to test the hz of the main loop with millis() vs micros(). With millis() hz was giving a reading between 288,935 and 289,232 but with micros is was reading 174,730 which is substantially slower. Is is just because the arduino has to deal with bigger numbers or because it has ...
🌐
ElectricRCAircraftGuy
electricrcaircraftguy.com › 2014 › 02 › Timer2Counter-more-precise-Arduino-micros-function.html
ElectricRCAircraftGuy.com--RC, Arduino, Programming, & Electronics: Arduino micros() function with 0.5us precision - using my Timer2_Counter Library
February 9, 2014 - ...merging the world of Arduino and Radio Control, one tool at a time... ...CODE FOR A PRECISE MICROS() FUNCTION IS POSTED BELOW... "I wrote a libary to get 0.5us precision on a "micros()" replacement function, so that I can get repeatable results reading a PWM or PPM signal, to within 1us. I searched all around the internet and could not find something comparable (or that was easy to use, and maintained the Arduino's ability to write PWM signals via the Servo Libary), so I think this is my first real contribution to the world of Arduino and Radio Control."
🌐
YouTube
youtube.com › robotics back-end
Arduino - How to Compute a Duration with micros() - YouTube
Learn how to compute the duration of any action in your Arduino program - using the micros() function to get the time.👉 Complete Arduino Course for Beginner...
Published   March 10, 2021
Views   5K
🌐
Arduino
docs.arduino.cc › language-reference › funções › time › micros
micros()
The official Arduino programming language structure reference pages.
Top answer
1 of 3
10

Yes, depending your Arduino's basic clock rate. For example here are the counter-timer input frequencies and periods after pre-scaling, for an ATMega2560's counter-timer 2, and a basic clock rate of 16MHz. The timer has built in "prescaler" value options which determine frequency/period, shown in this table:

    TCCR2B bits 2-0    Prescaler    Freq [KHz], Period [usec] after prescale
          0x0          (TC stopped)      --         --
          0x1                1        16000.        0.0625
          0x2                8         2000.        0.500
          0x3               32          500.        2.000
          0x4               64          250.        4.000
          0x5              128          125.        8.000
          0x6              256           62.5      16.000
          0x7             1024           15.625    64.000

For better timing resolution, you use a value called TCNT2. There is build in counter that goes from 0 to 255 because the timer is 8 bit. When the counter reaches the value assigned by TCNT2 it triggers an interrupt. This interrupt is called TIMER2_OVF_vect.

given this information, the resulting interrupt rate would be: 16MHz / (prescaler * (255 - TCNT2))

You could get the timer to run at the full 16MHz (62.5nSec) though that's way faster than you need; 2MHz with an initial count of (255-2) would give you 1MHz interrupt rate. Divide that by 2 in your ISR:

extern uint32_t MicroSecClock = 0;

ISR(TIMER2_OVF_vect) {// this is a built in function that gets called when the timer gets to the overflow counter number
  static uint_8 count;            // interrupt counter

  if( (++count & 0x01) == 0 )     // bump the interrupt counter
    ++MicroSecClock;              // & count uSec every other time.

  digitalWrite(53,toggle);// pin 53 is arbitrary
  TCNT2 = 253;                    // this tells the timer when to trigger the interrupt. when the counter gets to 253 out of 255(because the timer is 8 bit) the timmer will trigger an interrupt
  TIFR2 = 0x00;                   // clear timer overflow flag
};

The data sheet for your MCU is the basic resource; this article will give you (and gave me!) a good head-start.

2 of 3
4

If dropping down to AVR Level is acceptable (as you mentioned in your question), you can set up a timer and even get the ticks of the AVR's clock.

You need to refer to your AVR's datasheet because it differs within the different ATMegas and ATTinys. But the procedure is always the same. What you need to do is:

  • decide which prescaler to use (for example set it to 1, i.e. no prescaling if you want the actual CPU clock speed), refer to the TCCR documentation
  • set up a timer overflow interrupt, an interrupt handler and activate interrupts globally
  • activate the timer in the Timer/Counter Control Register TCCR

That way can get the exact ticks from the timer register, however you need to count the overflows manually. This is as precise as possible by technology.

Here is some example code for the outdated AT90S2313, but it gives you good hints what to do basically:

/* uC: AT90S2313 */
#include <avr/io.h>
#include <avr/interrupt.h>

int main(void)
{
  // set up timer 0
  TCCR0 = (1<<CS01); // Prescaler 8

  // enable overflow interrupt
  TIMSK |= (1<<TOIE0);

  // activate interrupts
  sei();

  while(1)
  {
     /* Do whatever you like */
  }
}


ISR (TIMER0_OVF_vect)
{    
   /*
      This gets called everytime there in an overflow in the timer register  
   */
}