Introduction
Every sketch so far has used delay(). It is the easiest way to make something happen slowly enough to see — and it is a blunt instrument.
delay(1000) does not mean "wait a second while other things carry on". It means stop. For that whole second the Arduino does nothing else: it will not read a button, will not check a sensor, will not answer the Serial Monitor. A press during that second is simply missed.
millis() is the alternative. It does not wait at all. It hands you the number of milliseconds since the board was switched on, and leaves you to decide whether enough time has passed. Nothing is blocked, so the sketch can watch several things at once.
micros() is the same idea a thousand times finer, for things too quick to measure in milliseconds.
The shift from "wait here" to "has it been long enough yet" is the single biggest step in this course. Everything that reacts while it is doing something else depends on it.
What you will be able to do
By the end of this lesson you can:
- Say exactly what
delay()stops the Arduino from doing. - Read the board's clock with
millis(). - Measure how long a piece of code takes.
- Explain why
millis()returns anunsigned longand not anint. - Choose between
millis()andmicros(). - Describe the pattern that replaces
delay()without writing it yet.
What you need
| Part | Type | Qty |
|---|---|---|
| Arduino UNO R3 | Microcontroller | 1 |
| USB A to B cable | Cable | 1 |
Basic
No wiring. Everything here is read in the Serial Monitor at 9600 baud.
→ Blink Without Delay — the canonical example, taken apart line by line.
The four calls
| Call | Gives you | Range before it wraps |
|---|---|---|
delay(ms) | nothing — it stops | — |
delayMicroseconds(us) | nothing — it stops, briefly | — |
millis() | milliseconds since power-on | about 49 days |
micros() | microseconds since power-on | about 70 minutes |
delay() stops everything
void setup() {
Serial.begin(9600);
}
void loop() {
Serial.println("tick");
delay(1000);
}
One line a second, and for 999 of every 1000 milliseconds the board is asleep on its feet. Nothing else can happen.
delayMicroseconds() is the same, for very short waits — under about 16000 microseconds. Below three microseconds it is not accurate, and it is used mostly for timing signals to sensors.
millis() is a clock, not a pause
void setup() {
Serial.begin(9600);
}
void loop() {
Serial.println(millis());
delay(500);
}
The numbers climb: 0, 500, 1000, 1500. That is time since the board started, not time since anything you did.
Reset the board and it starts again from zero. millis() has no idea what day it is — it only knows how long it has been awake.
Challenges
Challenge 1
Watch the clock.
Print millis() once every second and let it run.
Then answer, from the output:
- What is the first number printed?
- Are the gaps exactly 1000, or slightly more? Why might that be?
- Press the reset button on the board. What happens to the numbers?
Write one sentence for each.
Log in to ask for the answer.
Challenge 2
Time your own code.
Measure how long each of these takes, using micros() and printing the result:
- A single
Serial.println("hello"). delayMicroseconds(100).- Doing nothing at all — take the time twice in a row with nothing between.
The third one is the interesting one. It tells you the cost of asking the question, which is the floor on anything you can measure this way.
Log in to ask for the answer.
Challenge 3
Prove that delay() blocks.
Write a sketch that prints working as fast as it can, with no delay at all. Watch the Serial Monitor flood.
Now add delay(2000) at the end of loop().
While it is running, count how many working lines appear in ten seconds. Compare with your estimate of how many appeared in ten seconds without the delay.
Then answer: during those two seconds, could the Arduino have noticed a button being pressed and released?
Log in to ask for the answer.
Extra challenge
Two clocks at once.
Using only millis() and no delay() anywhere, print:
fastevery 200 msslowevery 1000 ms
Both must keep their own rhythm. Every fifth fast should be followed by a slow.
You will need two variables remembering when each last ran, and the if pattern from the lesson above. This is the first sketch in the course that does two things at genuinely different rates.
Think about it: try writing the same thing with delay() only. You cannot — not without the two rhythms interfering. That is the whole argument, and it is why millis() is worth the extra lines.
Log in to ask for the answer.