Built-in project · Arduino Uno R3

Stopwatch: four-digit display, digits on 10 to 13, on an Arduino Uno

A four-digit seven-segment display with segments a to dp on pins 2 to 9 and digits 1 to 4 on pins 10 to 13 counts minutes and seconds, lighting one digit at a time faster than the eye can follow. The whole build, an Arduino Uno and 9 more parts, runs here in your browser on the firmware below; open it in the editor to change the wiring or the code and run it again.

Teaching? Assign it to your class in one click.

Advanced About 30 minutes to build and run. Runs in your browser. Free, and no account needed.

The parts retail for about $33. On Mokxi they're free.

The circuit runs here once the page has loaded.

What you'll learn

  • Multiplexing a four-digit display
  • Segment patterns stored as bytes
  • Common cathode: LOW selects a digit
  • Splitting time into minutes and seconds with / and %
  • Difficulty: Advanced
  • Time: About 30 minutes
  • Board: Arduino Uno R3
  • Parts: 11

How it works

The four digits of the display share their segment lines, so only one digit can be on at a time. The sketch lights digit 1, then 2, then 3, then 4, 3 ms each, over and over. That is too fast to see, so all four look lit.

The segments a to dp go through 220 ohm resistors to pins 2 to 9. The digit pins are 10 to 13. It is a common cathode display, so setting a digit pin LOW turns that digit on.

The time comes from millis. The first two digits are minutes, the third and fourth are seconds, and a point after the second digit separates them. Minutes wrap at 100.

Parts list

11 parts, plus the jumper wires. They retail for about $33; on Mokxi they're free.

Wiring table

Every connection, pin by pin, read from the circuit itself. Each row joins the pin on the left to the pin on the right, by a jumper wire or a breadboard strip.

Part and pinConnects to
Four-digit seven segment, multiplexed pin DIG4Arduino Uno R3 pin 13
Four-digit seven segment, multiplexed pin DIG3Arduino Uno R3 pin 12
Four-digit seven segment, multiplexed pin DIG2Arduino Uno R3 pin 11
Four-digit seven segment, multiplexed pin DIG1Arduino Uno R3 pin 10
Resistor, 220 Ω (8) pin 1Arduino Uno R3 pin 9
Resistor, 220 Ω (7) pin 1Arduino Uno R3 pin 8
Resistor, 220 Ω (6) pin 1Arduino Uno R3 pin 7
Resistor, 220 Ω (5) pin 1Arduino Uno R3 pin 6
Resistor, 220 Ω (4) pin 1Arduino Uno R3 pin 5
Resistor, 220 Ω (3) pin 1Arduino Uno R3 pin 4
Resistor, 220 Ω (2) pin 1Arduino Uno R3 pin 3
Resistor, 220 Ω (1) pin 1Arduino Uno R3 pin 2
Resistor, 220 Ω (5) pin 2Four-digit seven segment, multiplexed pin E
Resistor, 220 Ω (4) pin 2Four-digit seven segment, multiplexed pin D
Resistor, 220 Ω (8) pin 2Four-digit seven segment, multiplexed pin DP
Resistor, 220 Ω (3) pin 2Four-digit seven segment, multiplexed pin C
Resistor, 220 Ω (7) pin 2Four-digit seven segment, multiplexed pin G
Resistor, 220 Ω (2) pin 2Four-digit seven segment, multiplexed pin B
Resistor, 220 Ω (6) pin 2Four-digit seven segment, multiplexed pin F
Resistor, 220 Ω (1) pin 2Four-digit seven segment, multiplexed pin A

The code

The firmware exactly as the editor opens it. Change a line there and press Run: it compiles in the browser.

sketch.ino · Arduino Uno R3
// A stopwatch on a four-digit display: minutes and seconds.
//
//   segments a, b, c, d, e, f, g, dp -> 220 ohm each -> pins 2 to 9
//   digit 1 -> pin 10   digit 2 -> pin 11   digit 3 -> pin 12   digit 4 -> pin 13
//
// The four digits share their segment lines, so only one digit can show at a
// time. The sketch lights digit 1, then 2, then 3, then 4, a few milliseconds
// each, over and over: too fast to see, so all four look lit. It is a common
// cathode display, so a digit pin LOW turns its digit on.

const int SEGMENTS[8] = {2, 3, 4, 5, 6, 7, 8, 9};
const int DIGIT_PINS[4] = {10, 11, 12, 13};

const byte PATTERNS[10] = {
  0b00111111, 0b00000110, 0b01011011, 0b01001111, 0b01100110,
  0b01101101, 0b01111101, 0b00000111, 0b01111111, 0b01101111,
};

void showDigit(int position, int value, bool dot) {
  byte bits = PATTERNS[value] | (dot ? 0b10000000 : 0);
  for (int s = 0; s < 8; s++) digitalWrite(SEGMENTS[s], (bits >> s) & 1);
  digitalWrite(DIGIT_PINS[position], LOW);
  delay(3);
  digitalWrite(DIGIT_PINS[position], HIGH);
}

void setup() {
  for (int s = 0; s < 8; s++) pinMode(SEGMENTS[s], OUTPUT);
  for (int d = 0; d < 4; d++) {
    pinMode(DIGIT_PINS[d], OUTPUT);
    digitalWrite(DIGIT_PINS[d], HIGH);
  }
  Serial.begin(9600);
  Serial.println("Mokxi Uno: stopwatch, minutes and seconds");
}

void loop() {
  unsigned long seconds = millis() / 1000;
  int minutes = (seconds / 60) % 100;
  int secs = seconds % 60;
  showDigit(0, minutes / 10, false);
  showDigit(1, minutes % 10, true);
  showDigit(2, secs / 10, false);
  showDigit(3, secs % 10, false);
}

Code walkthrough

The key functions of the sketch, and what each one does.

showDigit sketch.ino

showDigit builds the pattern for a number, adding the point if asked. It writes the eight segment pins, pulls that digit's pin LOW for 3 ms to light it, then sets it HIGH again.

void showDigit(int position, int value, bool dot) {
  byte bits = PATTERNS[value] | (dot ? 0b10000000 : 0);
  for (int s = 0; s < 8; s++) digitalWrite(SEGMENTS[s], (bits >> s) & 1);
  digitalWrite(DIGIT_PINS[position], LOW);
  delay(3);
  digitalWrite(DIGIT_PINS[position], HIGH);
}

setup sketch.ino

setup makes all segment and digit pins outputs, sets the digit pins HIGH so every digit starts off, and starts serial.

void setup() {
  for (int s = 0; s < 8; s++) pinMode(SEGMENTS[s], OUTPUT);
  for (int d = 0; d < 4; d++) {
    pinMode(DIGIT_PINS[d], OUTPUT);
    digitalWrite(DIGIT_PINS[d], HIGH);
  }
  Serial.begin(9600);
  Serial.println("Mokxi Uno: stopwatch, minutes and seconds");
}

loop sketch.ino

loop works out minutes and seconds from millis, then calls showDigit four times, once per digit. It runs constantly so each digit gets lit many times a second.

void loop() {
  unsigned long seconds = millis() / 1000;
  int minutes = (seconds / 60) % 100;
  int secs = seconds % 60;
  showDigit(0, minutes / 10, false);
  showDigit(1, minutes % 10, true);
  showDigit(2, secs / 10, false);
  showDigit(3, secs % 10, false);
}

Troubleshooting

The usual mistakes with this circuit, and the fix for each.

  • The digits are in the wrong order. This project
    DIG1 goes to pin 10, DIG2 to 11, DIG3 to 12 and DIG4 to 13.
  • Segments light in the wrong places. This project
    Segments A to DP go to pins 2 to 9 through the resistors, in that order.
  • The display flickers. This project
    Every pass of loop must draw all four digits. Adding long delays makes it blink.
  • Digits look dim, flicker, or show ghosts of other digits. Four-digit seven segment
    Refresh each digit quickly in a loop, at least 100 Hz for the whole set. Turn all segments off before switching digits. Do not use delay() for long pauses while displaying.
  • Segments burn out or the pins are overloaded. Four-digit seven segment
    Use a resistor of about 220 ohms on each segment line. Check whether the display is common cathode or common anode, since that sets which level turns a segment on.
  • The LED is dim, burns out, or the pin reads wrong because the resistor value is off. Resistor
    Read the color bands again. A 220 ohm to 330 ohm resistor suits a typical LED on 5 V. 10k is a common pull-up or pull-down value. Check with a multimeter if unsure.
  • A pull-up or pull-down resistor is missing, so the input floats and reads random values. Resistor
    Tie the input to 5 V or ground through about 10k. Or use INPUT_PULLUP and wire the switch to ground.
  • Upload fails or nothing runs after wiring pins 0 and 1 to a module. Arduino Uno R3
    Pins 0 and 1 are the USB serial port. Move the module to other pins, or unplug it while uploading. Also check the right board is selected.

Change it and keep it

Open it in the editor, change the circuit or the code, and keep your version in a free account.