Chapter 11
Up to now, we’ve used delay() everywhere.
And that’s okay — for learning.
But at some point, delay() stops being your friend.
This chapter explains why, and introduces a better way to handle time on Arduino.
⏳ What delay() Actually Does
When you write:delay(1000);
Arduino does exactly this:
Stop everything. Wait for 1 second. Then continue.
During that delay:
no buttons are read
no sensors are checked
no logic runs
nothing else happens
The microcontroller is literally doing nothing.
🧠 Why This Is a Problem
Imagine you want to:
blink an LED
read a button
update a display
at the same time.
With delay():
LED blocks button reading
button blocks sensor updates
everything waits on everything else
This creates unresponsive systems.
🧪 Simple Example of the Problem
digitalWrite(LED_PIN, HIGH);
delay(1000);
digitalWrite(LED_PIN, LOW);
delay(1000);
During those 2 seconds:
a button press is ignored
a sensor change is missed
This is fine for demos, not for real systems.
🔢 What Is millis()?
Instead of waiting, we can ask Arduino:
“Has enough time passed?”
That’s what millis() does.
millis() returns:
the number of milliseconds
since the Arduino started running
It keeps increasing:
0, 1, 2, 3, ...
And it never blocks your program.
🔁 The Core Idea (Very Important)
Instead of this:delay(1000);
We do this:
remember the last time something happened
compare it to the current time
act only if enough time has passed
🧩 Non-Blocking Blink Example
const int ledPin = 13; unsigned long previousTime = 0; const long interval = 1000;void setup() { pinMode(ledPin, OUTPUT); }
void loop() { unsigned long currentTime = millis();
if (currentTime - previousTime >= interval) { previousTime = currentTime; digitalWrite(ledPin, !digitalRead(ledPin)); } }
This LED still blinks every second.
But now:
the loop keeps running
buttons can be read
sensors can be checked
multiple tasks can coexist
🧠 Why This Works
You’re no longer pausing time.
You’re:
letting the program run freely
making decisions based on time differences
This is how real embedded systems work.
What happens when your Arduino executes delay(1000)?
Why ismillis()preferred overdelay()for many Arduino projects?
delay() blocks the Arduino from doing anything else until the delay finishes.
With millis(), the Arduino keeps checking the elapsed time while continuing to read sensors, respond to buttons, and control outputs.
⚠️ Important Notes
millis()usesunsigned longit overflows after ~49 days (we’ll handle that later)
this pattern scales to many tasks
Don’t worry if this feels harder than delay() — that’s normal.
🧰 Common Beginner Mistakes
Mixing
delay()andmillis()blindlyForgetting to update previous time
Using
intinstead ofunsigned longOvercomplicating the logic early
Master the idea, not the syntax.
📌 What Comes Next
Now that we can:
control outputs
read inputs
handle time properly
We need a way to see what’s happening inside our code.
Comments
Share your thoughts, questions, or corrections below. Be kind and keep it on-topic ✨