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
previousMillisto currentmillis()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
previousMillisvariable 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 longfor time variables, which can cause incorrect timing due to overflow. - Confusing
millis()withmicros(), 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 longfor 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.