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.
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.
- 1 × Arduino Uno R3In Starter Kit, Claw Machine Kit, Vending Machine Kit.
- 1 × Two-digit seven segment, multiplexed
- 8 × Resistor, 220 ΩIn Starter Kit, Claw Machine Kit, Halloween Prop Kit.
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 pin | Connects to |
|---|---|
| Two-digit seven segment, multiplexed pin DIG2 | Arduino Uno R3 pin 11 |
| Two-digit seven segment, multiplexed pin DIG1 | Arduino Uno R3 pin 10 |
| Resistor, 220 Ω (8) pin 1 | Arduino Uno R3 pin 9 |
| Resistor, 220 Ω (7) pin 1 | Arduino Uno R3 pin 8 |
| Resistor, 220 Ω (6) pin 1 | Arduino Uno R3 pin 7 |
| Resistor, 220 Ω (5) pin 1 | Arduino Uno R3 pin 6 |
| Resistor, 220 Ω (4) pin 1 | Arduino Uno R3 pin 5 |
| Resistor, 220 Ω (3) pin 1 | Arduino Uno R3 pin 4 |
| Resistor, 220 Ω (2) pin 1 | Arduino Uno R3 pin 3 |
| Resistor, 220 Ω (1) pin 1 | Arduino Uno R3 pin 2 |
| Resistor, 220 Ω (5) pin 2 | Two-digit seven segment, multiplexed pin E |
| Resistor, 220 Ω (4) pin 2 | Two-digit seven segment, multiplexed pin D |
| Resistor, 220 Ω (3) pin 2 | Two-digit seven segment, multiplexed pin C |
| Resistor, 220 Ω (7) pin 2 | Two-digit seven segment, multiplexed pin G |
| Resistor, 220 Ω (8) pin 2 | Two-digit seven segment, multiplexed pin DP |
| Resistor, 220 Ω (1) pin 2 | Two-digit seven segment, multiplexed pin A |
| Resistor, 220 Ω (6) pin 2 | Two-digit seven segment, multiplexed pin F |
| Resistor, 220 Ω (2) pin 2 | Two-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.
// 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.showDigitdoes this first. - The display flickers This project
Keep the delay inshowDigitshort, 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.