Mission 23 · Stage 3

Stopwatch

millis() arithmetic for elapsed time

Store elapsed time in variables using millis() and print seconds on Serial.

Stopwatch circuit diagram

Pin connections

Part 1Part 2

Pushbutton

pin 1

Arduino

pin 2

Pushbutton

pin 2

Arduino

GND

See it

Start and stop a real timer!

Press the button to toggle running — millis() and variables track elapsed seconds.

Sports timers and kitchen timers store start time and compute elapsed time the same way.

The story

The problem

You need to remember when the timer started and whether it is running.

Think of it like

Like pressing start on a phone stopwatch — it remembers the start moment for you.

Meet the parts

Runs your sketch

Arduino

Brain

Loading part…

How it works

1

Detect button press

When you press, we flip the running variable and record or print time.

if (digitalRead(BUTTON_PIN) == LOW)
2

Toggle running state

running is a bool variable — true means counting, false means stopped. startMs stores when we began.

running = !running;
if (running) startMs = millis();
3

Show live elapsed time

While running, subtract startMs from now to get seconds — updates every half second.

unsigned long elapsed = millis() - startMs;
Serial.print(elapsed / 1000.0, 2);

Then loop back to step 1

Build the circuit

Follow these steps in order. Match the wires to the colors shown.

  1. 1

    Place Arduino

    Place the Arduino (uno) on the breadboard.

    Arduino placed!

    Loading part…

Try it

  • Press once to start — Serial shows counting seconds.
  • Press again to stop and see your final time.

Peek at code

Timer variables

const int BUTTON_PIN = 2;
unsigned long startMs = 0;
bool running = false;

startMs remembers the start moment; running tells us if the clock is ticking.

Start / stop on press

    if (running) {
      startMs = millis();
      Serial.println("Started!");
    } else {
      unsigned long elapsed = millis() - startMs;
      Serial.print("Stopped at ");
      Serial.print(elapsed / 1000.0, 2);
      Serial.println(" seconds");
    }
    while (digitalRead(BUTTON_PIN) == LOW) {
      delay(20);
    }
  }
  if (running) {

Button press toggles running and either saves startMs or prints final elapsed time.

Live updates

    Serial.print("Time: ");
    Serial.print(elapsed / 1000.0, 2);
    Serial.println(" s");
    delay(500);
  }
  delay(20);
}

When running is true, loop() keeps printing the growing elapsed time.

Show full sketch (stopwatch.ino)
const int BUTTON_PIN = 2;
unsigned long startMs = 0;
bool running = false;
void setup() {
  pinMode(BUTTON_PIN, INPUT_PULLUP);
  Serial.begin(9600);
  Serial.println("Stopwatch — press button to start/stop");
}
void loop() {
  if (digitalRead(BUTTON_PIN) == LOW) {
    running = !running;
    if (running) {
      startMs = millis();
      Serial.println("Started!");
    } else {
      unsigned long elapsed = millis() - startMs;
      Serial.print("Stopped at ");
      Serial.print(elapsed / 1000.0, 2);
      Serial.println(" seconds");
    }
    while (digitalRead(BUTTON_PIN) == LOW) {
      delay(20);
    }
  }
  if (running) {
    unsigned long elapsed = millis() - startMs;
    Serial.print("Time: ");
    Serial.print(elapsed / 1000.0, 2);
    Serial.println(" s");
    delay(500);
  }
  delay(20);
}

Quick quiz

Q1. What is a variable?

  • A. A named place to store a value
  • B. A type of wire
  • C. Only delay()
Why: Correct — int score = 0; creates a box named score.

Q2. What does startMs = millis() save?

  • A. The moment the stopwatch started
  • B. The final score
  • C. The button pin number
Why: Correct — startMs is the timestamp when running turned on.

Code lab — try on your own

  1. Print time more often — change delay(500) to delay(250) in the running block.

    Hint: Line 32 inside if (running).

  2. Add a comment on running = !running explaining it flips start/stop.

    Hint: Line 13.

Code walkthrough

A line-by-line tour of the sketch — the same steps as in Robo Gurukul Studio.

Program overview

Technical

Sketches have globals, then setup() once, then loop() forever.

In this project

Store elapsed time in variables using millis() and print seconds on Serial.

Why here

Read from top to bottom. Hover words or lines for help!

const int BUTTON_PIN = 2;
unsigned long startMs = 0;
bool running = false;

setup()

Technical

Runs one time when the board turns on.

In this project

Sets up pins and libraries for Stopwatch.

Why here

One-time setup belongs here—not in loop().

void setup() {
  pinMode(BUTTON_PIN, INPUT_PULLUP);
  Serial.begin(9600);
  Serial.println("Stopwatch — press button to start/stop");
}

loop()

Technical

Runs again and again after setup() is done.

In this project

This is the main action you see in Stopwatch.

Why here

Repeating work (blink, read sensors) goes here.

void loop() {
  if (digitalRead(BUTTON_PIN) == LOW) {
    running = !running;
    if (running) {
      startMs = millis();
      Serial.println("Started!");
    } else {
      unsigned long elapsed = millis() - startMs;
      Serial.print("Stopped at ");
      Serial.print(elapsed / 1000.0, 2);
      Serial.println(" seconds");
    }
    while (digitalRead(BUTTON_PIN) == LOW) {
      delay(20);
    }
  }
  if (running) {
    unsigned long elapsed = millis() - startMs;
    Serial.print("Time: ");
    Serial.print(elapsed / 1000.0, 2);
    Serial.println(" s");
    delay(500);
  }
  delay(20);
}

Try this: Change numbers in loop(), then compile and run the simulator.

pinMode

Technical

Tells a pin if it listens or drives something.

In this project

Gets the Stopwatch circuit ready in the simulator.

Why here

Goes in setup() because we only set pins once at the start.

  pinMode(BUTTON_PIN, INPUT_PULLUP);

digitalRead

Technical

Checks if a pin is ON or OFF.

In this project

Reads buttons or sensors in Stopwatch.

Why here

Goes in loop() so we can react when something changes.

  if (digitalRead(BUTTON_PIN) == LOW) {

delay

Technical

Waits for some time. Nothing else runs during the wait.

In this project

Controls speed so you can see Stopwatch in the simulator.

Why here

Right after an action that should stay the same for a moment.

      delay(20);

millis

Technical

Counts milliseconds since the board started.

In this project

Tracks time in Stopwatch without using delay().

Why here

In loop() when you need to know how much time passed.

      startMs = millis();

begin

Technical

Starts talking to the computer screen (serial monitor).

In this project

Lets Stopwatch print debug messages.

Why here

Goes in setup() once before any Serial.print.

  Serial.begin(9600);

print

Technical

Sends text to the serial monitor without a new line.

In this project

Shows values from Stopwatch on the screen.

Why here

In loop() or setup() when you want to see what the board is doing.

      Serial.print("Stopped at ");

println

Technical

Sends text to the serial monitor and starts a new line.

In this project

Prints one line of output for Stopwatch.

Why here

In loop() when each reading should appear on its own line.

  Serial.println("Stopwatch — press button to start/stop");