0
0
AutocadHow-ToBeginner · 4 min read

How to Use millis Instead of delay in Arduino for Non-blocking Code

Use millis() to track elapsed time without stopping your program, unlike delay() which pauses everything. Store the start time, then check if the desired interval has passed by comparing millis() with the stored time to run code repeatedly without blocking.
📐

Syntax

The basic pattern to use millis() instead of delay() involves three parts:

  • Store the start time: Save the current time with unsigned long previousMillis = millis();
  • Check elapsed time: Compare current time with stored time using if (millis() - previousMillis >= interval)
  • Update start time: Reset previousMillis to current millis() after the action runs
arduino
unsigned long previousMillis = 0;
const long interval = 1000; // interval in milliseconds

void loop() {
  unsigned long currentMillis = millis();
  if (currentMillis - previousMillis >= interval) {
    previousMillis = currentMillis;
    // Your code here to run every interval
  }
}
💻

Example

This example blinks an LED every second without stopping the program. It uses millis() to check time passed and toggles the LED state accordingly.

arduino
const int ledPin = 13;          // LED connected to digital pin 13
unsigned long previousMillis = 0; // will store last time LED was updated
const long interval = 1000;       // interval at which to blink (milliseconds)

void setup() {
  pinMode(ledPin, OUTPUT);
}

void loop() {
  unsigned long currentMillis = millis();

  if (currentMillis - previousMillis >= interval) {
    previousMillis = currentMillis;

    // if the LED is off turn it on and vice-versa:
    if (digitalRead(ledPin) == LOW) {
      digitalWrite(ledPin, HIGH);
    } else {
      digitalWrite(ledPin, LOW);
    }
  }
}
Output
The LED on pin 13 blinks on and off every 1 second without pausing other code.
⚠️

Common Pitfalls

Common mistakes when using millis() include:

  • Not updating the previousMillis variable after the interval check, causing the code to run repeatedly without delay.
  • Using delay() inside the timing code, which blocks the program and defeats the purpose.
  • Not using unsigned long for time variables, which can cause incorrect timing due to overflow.
  • Confusing millis() with micros(), which measures microseconds, not milliseconds.

Example of wrong and right usage:

arduino
// Wrong: Using delay inside timing check
unsigned long previousMillis = 0;
const long interval = 1000;

void loop() {
  if (millis() - previousMillis >= interval) {
    delay(1000); // blocks program
    previousMillis = millis();
  }
}

// Right: Non-blocking with millis
unsigned long previousMillis = 0;
const long interval = 1000;

void loop() {
  unsigned long currentMillis = millis();
  if (currentMillis - previousMillis >= interval) {
    previousMillis = currentMillis;
    // non-blocking code here
  }
}
📊

Quick Reference

Tips for using millis() effectively:

  • Always use unsigned long for time variables.
  • Update the start time variable immediately after the action.
  • Use subtraction (currentMillis - previousMillis) to handle timer overflow safely.
  • Keep your loop code non-blocking to allow multitasking.

Key Takeaways

Use millis() to track elapsed time without stopping your program.
Always update your previousMillis variable after the timed action.
Avoid delay() to keep your Arduino responsive and multitasking.
Use unsigned long variables and subtraction to handle timer overflow safely.
millis() allows non-blocking code for better control and responsiveness.