Built-in project · Arduino Uno R3

Two-digit counter on an Arduino Uno

A bare two-digit seven-segment display on ten Uno pins counts 00 to 99, multiplexed: one digit at a time, five milliseconds each. 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.

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

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

The circuit runs here once the page has loaded.

What you'll learn

  • Multiplexing two digits over shared segment pins
  • Seven segment patterns stored as bit patterns
  • Common cathode: a digit is chosen by pulling it LOW
  • Persistence of vision
  • Difficulty: Intermediate
  • Time: About 25 minutes
  • Board: Arduino Uno R3
  • Parts: 10

How it works

A bare two digit display has only ten pins: eight segment pins shared by both digits, and one common pin for each digit. The Uno drives the segments on pins 2 to 9, each through a 220 ohm resistor, and picks the digit with pins 10 and 11.

Only one digit can be lit at a time. The sketch lights the tens digit for 5 ms, then the ones digit for 5 ms, over and over, and your eye sees both. Every 250 ms the count goes up by one, and it wraps from 99 to 00.

Parts list

10 parts, plus the jumper wires. They retail for about $28; 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
Two-digit seven segment, multiplexed pin DIG2Arduino Uno R3 pin 11
Two-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 2Two-digit seven segment, multiplexed pin E
Resistor, 220 Ω (4) pin 2Two-digit seven segment, multiplexed pin D
Resistor, 220 Ω (3) pin 2Two-digit seven segment, multiplexed pin C
Resistor, 220 Ω (7) pin 2Two-digit seven segment, multiplexed pin G
Resistor, 220 Ω (8) pin 2Two-digit seven segment, multiplexed pin DP
Resistor, 220 Ω (1) pin 2Two-digit seven segment, multiplexed pin A
Resistor, 220 Ω (6) pin 2Two-digit seven segment, multiplexed pin F
Resistor, 220 Ω (2) pin 2Two-digit seven segment, multiplexed pin B

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
// Two-digit counter: a bare two-digit display, multiplexed by the sketch.
//
//   segments A B C D E F G DP -> pins 2 to 9, each through its own 220 ohm
//   digits DIG1 and DIG2      -> pins 10 and 11
//
// Ten legs for two digits: each segment leg goes to that segment in both
// digits, and each digit has one common leg, so only one digit can be lit at
// a time. The sketch shows them in turn, five milliseconds each, and the eye
// sees both at once, each half as bright.
//
// Common cathode: a digit is selected by pulling its common LOW, and a
// segment lit by driving its leg HIGH.

const uint8_t SEGMENT_PINS[8] = {2, 3, 4, 5, 6, 7, 8, 9};
const uint8_t DIGIT_PINS[2] = {10, 11};

// Bit 0 is segment A, bit 6 is G, bit 7 the point.
const uint8_t FONT[10] = {0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07, 0x7F, 0x6F};

int count = 0;
unsigned long lastCount = 0;

void showDigit(uint8_t which, uint8_t pattern) {
  for (uint8_t i = 0; i < 2; i++) digitalWrite(DIGIT_PINS[i], HIGH);  // all off first: no ghost
  for (uint8_t s = 0; s < 8; s++) digitalWrite(SEGMENT_PINS[s], (pattern >> s) & 1);
  digitalWrite(DIGIT_PINS[which], LOW);
  delay(5);
}

void setup() {
  for (uint8_t i = 0; i < 8; i++) pinMode(SEGMENT_PINS[i], OUTPUT);
  for (uint8_t i = 0; i < 2; i++) {
    pinMode(DIGIT_PINS[i], OUTPUT);
    digitalWrite(DIGIT_PINS[i], HIGH);
  }
}

void loop() {
  if (millis() - lastCount >= 250) {
    lastCount = millis();
    count = (count + 1) % 100;
  }
  showDigit(0, FONT[count / 10]);
  showDigit(1, FONT[count % 10]);
}

Code walkthrough

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

showDigit sketch.ino

Shows one digit. It turns both digit pins HIGH first, so nothing ghosts, then sets each segment pin from one bit of the pattern. Last it pulls the chosen digit's pin LOW and waits 5 ms.

void showDigit(uint8_t which, uint8_t pattern) {
  for (uint8_t i = 0; i < 2; i++) digitalWrite(DIGIT_PINS[i], HIGH);  // all off first: no ghost
  for (uint8_t s = 0; s < 8; s++) digitalWrite(SEGMENT_PINS[s], (pattern >> s) & 1);
  digitalWrite(DIGIT_PINS[which], LOW);
  delay(5);
}

setup sketch.ino

Sets the eight segment pins and the two digit pins as outputs, and starts the digit pins HIGH so both digits are off.

void setup() {
  for (uint8_t i = 0; i < 8; i++) pinMode(SEGMENT_PINS[i], OUTPUT);
  for (uint8_t i = 0; i < 2; i++) {
    pinMode(DIGIT_PINS[i], OUTPUT);
    digitalWrite(DIGIT_PINS[i], HIGH);
  }
}

loop sketch.ino

Adds one to count every 250 ms, wrapping at 100. On every pass it calls showDigit for the tens digit, count / 10, and then the ones digit, count % 10, using patterns from FONT.

void loop() {
  if (millis() - lastCount >= 250) {
    lastCount = millis();
    count = (count + 1) % 100;
  }
  showDigit(0, FONT[count / 10]);
  showDigit(1, FONT[count % 10]);
}

Troubleshooting

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

  • Both digits show the same number This project
    The segment pins are shared, so only the digit pins pick one. Check DIG1 is on pin 10 and DIG2 on pin 11.
  • Ghost segments appear on the wrong digit This project
    Turn both digits off before changing segments. showDigit does this first.
  • The display flickers This project
    Keep the delay in showDigit short, around 5 ms, so each digit is refreshed often.
  • Both digits show the same number or ghost segments. Two-digit seven segment
    The digits share segment lines, so scan one digit at a time. Switch off both digits, set the segments, then enable one digit. Repeat quickly, over 50 times a second, to look steady.
  • Segments are dim or pins overheat. Two-digit seven segment
    Use a resistor on each segment line, about 220 to 330 ohms. Switch the common of each digit with a transistor if the total current exceeds a pin's limit. Match common anode or common cathode wiring.
  • 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.