It runs the clock and times your press.
Arduino
The brain
millis() with if conditions
Measure button reaction time with millis() after a random GO signal.

Pin connections
| Part 1 | Part 2 | |
|---|---|---|
Arduino pin 2 | → | Button pin 1 |
Button pin 2 | → | Arduino GND |
Arduino pin 13 | → | Resistor pin 1 |
Resistor pin 2 | → | GO LED anode (+) |
GO LED cathode (-) | → | Arduino GND |
Let's time how fast you are!
Wait… wait… GO! Press as fast as you can and see your speed in numbers.
Game timers and sports clocks use this same trick to count time.
The problem
If we used delay to wait, the program would freeze. We need a clock that keeps ticking.
Think of it like
millis() is like a stopwatch that never stops counting.
It runs the clock and times your press.
Arduino
The brain
Press it the second the GO light turns on.
Button
The button
Slows the power down so the GO light does not get hurt.
Resistor
The protector
It tells you the exact moment to press.
GO LED
The GO light
Wait a surprise time
Instead of freezing, we just check the clock until it reaches the GO time.
if (state == WAIT && millis() >= waitUntil)
Show GO
The light turns on and we save the exact moment in goTime.
digitalWrite(GO_LED, HIGH); goTime = millis();
Measure your speed
Take the time now and subtract goTime to find how fast you pressed.
reaction = millis() - goTime;
Then loop back to step 1
Follow these steps in order. Match the wires to the colors shown.
Place Arduino
Place the Arduino (uno) on the breadboard.
Arduino placed — ready to build!
Place Button
Place the Button (btn1) on the breadboard.
Place Resistor
Place the Resistor (r1) on the breadboard.
Place GO LED
Place the GO LED (led1) on the breadboard.
Connect Arduino pin 2 to Button (btn1) 1.l
Connect Arduino pin 2 to Button (btn1) 1.l.
Connect Button (btn1) 2.l to Arduino GND
Connect Button (btn1) 2.l to Arduino GND.
Connect Arduino pin 13 to Resistor (r1) 1
Connect Arduino pin 13 to Resistor (r1) 1.
Connect Resistor (r1) 2 to GO LED (led1) anode (+)
Connect Resistor (r1) 2 to GO LED (led1) anode (+).
Connect GO LED (led1) cathode (-) to Arduino GND
Connect GO LED (led1) cathode (-) to Arduino GND.
The game modes
enum State { WAIT, GO, SCORED };
State state = WAIT;
unsigned long goTime = 0;
unsigned long waitUntil = 0;The game has three modes: WAIT, GO, and SCORED. The program moves between them.
scheduleWait()
void scheduleWait() {
digitalWrite(GO_LED, LOW);
waitUntil = millis() + random(2000, 5000);
state = WAIT;
}This sets a surprise future time for GO, without freezing the program.
Timing your press
void loop() {
if (state == WAIT && millis() >= waitUntil) {
digitalWrite(GO_LED, HIGH);
goTime = millis();
state = GO;
Serial.println("GO! Press the button!");
}
if (state == GO && digitalRead(BUTTON_PIN) == LOW) {
unsigned long reaction = millis() - goTime;
Serial.print("Reaction: ");
Serial.print(reaction);
Serial.println(" ms");
state = SCORED;
delay(2000);
scheduleWait();
}
delay(10);loop() watches the clock to start GO, then times how fast you pressed.
const int BUTTON_PIN = 2;
const int GO_LED = 13;
enum State { WAIT, GO, SCORED };
State state = WAIT;
unsigned long goTime = 0;
unsigned long waitUntil = 0;
void scheduleWait() {
digitalWrite(GO_LED, LOW);
waitUntil = millis() + random(2000, 5000);
state = WAIT;
}
void setup() {
pinMode(BUTTON_PIN, INPUT_PULLUP);
pinMode(GO_LED, OUTPUT);
Serial.begin(9600);
randomSeed(analogRead(0));
scheduleWait();
Serial.println("Reaction Timer — wait for GO!");
}
void loop() {
if (state == WAIT && millis() >= waitUntil) {
digitalWrite(GO_LED, HIGH);
goTime = millis();
state = GO;
Serial.println("GO! Press the button!");
}
if (state == GO && digitalRead(BUTTON_PIN) == LOW) {
unsigned long reaction = millis() - goTime;
Serial.print("Reaction: ");
Serial.print(reaction);
Serial.println(" ms");
state = SCORED;
delay(2000);
scheduleWait();
}
delay(10);
}
Q1. Where does work that repeats go?
Q2. Why use millis() instead of delay() while waiting?
Make the waits shorter — change random(2000, 5000) to random(1000, 3000).
Hint: It's inside scheduleWait(), line 9.
Add a note (comment) on line 28 that says this is the time since GO.
Hint: That's the reaction = millis() - goTime line.
A line-by-line tour of the sketch — the same steps as in Robot Gurukul Studio.
Program overview
Big idea
Every Arduino program has a top part, a setup() part that runs once, and a loop() part that runs again and again.
In this project
The light waits, then says GO. You press fast, and it shows how quick you were.
Tip
Read from the top to the bottom. Tap any word or line if you need help!
const int BUTTON_PIN = 2;
const int GO_LED = 13;
enum State { WAIT, GO, SCORED };
State state = WAIT;
unsigned long goTime = 0;
unsigned long waitUntil = 0;
void scheduleWait() {
digitalWrite(GO_LED, LOW);
waitUntil = millis() + random(2000, 5000);
state = WAIT;
}setup()
Big idea
setup() runs one time when the board turns on.
In this project
It gets the button and GO light ready, mixes up the randomness, and starts the first wait.
Why here
Things we do only once go inside setup().
void setup() {
pinMode(BUTTON_PIN, INPUT_PULLUP);
pinMode(GO_LED, OUTPUT);
Serial.begin(9600);
randomSeed(analogRead(0));
scheduleWait();
Serial.println("Reaction Timer — wait for GO!");
}loop()
Big idea
loop() runs again and again, forever.
In this project
It checks the clock, shows GO at the right time, and times your press.
Why here
Things that repeat go inside loop().
void loop() {
if (state == WAIT && millis() >= waitUntil) {
digitalWrite(GO_LED, HIGH);
goTime = millis();
state = GO;
Serial.println("GO! Press the button!");
}
if (state == GO && digitalRead(BUTTON_PIN) == LOW) {
unsigned long reaction = millis() - goTime;
Serial.print("Reaction: ");
Serial.print(reaction);
Serial.println(" ms");
state = SCORED;
delay(2000);
scheduleWait();
}
delay(10);
}
Try this: Change a number inside loop(), then press Run to see what happens.
pinMode
Big idea
pinMode tells a pin if it will listen or push power out.
In this project
It makes pin 2 listen to the button and pin 13 push power to the GO light.
Why here
It goes in setup() because we only set it once.
pinMode(BUTTON_PIN, INPUT_PULLUP);
digitalWrite
Big idea
digitalWrite turns a pin ON or OFF.
In this project
It turns the GO light off again to get ready for the next round.
Why here
It is used when we set up the next wait.
digitalWrite(GO_LED, LOW);
digitalRead
Big idea
digitalRead checks if a pin is ON or OFF.
In this project
It checks if you pressed the button after GO.
Why here
It goes in loop() so we can catch your press.
if (state == GO && digitalRead(BUTTON_PIN) == LOW) {analogRead
Big idea
analogRead reads a number from a pin, from 0 up to 1023.
In this project
It reads a wiggly number from an empty pin to mix up the randomness.
Why here
In setup() so each game has a different GO time.
randomSeed(analogRead(0));
delay
Big idea
delay means wait. Nothing else happens while it waits.
In this project
It pauses for a moment after showing your score, before the next round.
Why here
Right after we print your reaction time.
delay(2000);
millis
Big idea
millis counts how many milliseconds the board has been on, like a stopwatch.
In this project
It marks when GO appears and when you press, so we can find the difference.
Why here
It lets us time things without stopping the whole program.
waitUntil = millis() + random(2000, 5000);
random
Big idea
random picks a surprise number for you.
In this project
It picks how long to wait before GO, so you cannot guess it.
Why here
When we set up each new round.
waitUntil = millis() + random(2000, 5000);
begin
Big idea
Serial.begin opens a way for the board to send words to your computer screen.
In this project
It lets the program print GO and your reaction time.
Why here
It goes in setup() once, before we print anything.
Serial.begin(9600);
Big idea
print sends words to the screen but stays on the same line.
In this project
It prints "Reaction: " right before your number.
Why here
In loop() so the label and number sit together.
Serial.print("Reaction: ");println
Big idea
println sends a line of words to the screen.
In this project
It prints the GO message and starts a new line.
Why here
In setup() so you see the start message.
Serial.println("Reaction Timer — wait for GO!");