Four-digit counter on an Arduino Uno
A bare four-digit seven-segment display on twelve pins, multiplexed: one digit at a time, four milliseconds each, and the eye sees all four. 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 40 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.
Step by step, with the wiring and the common mistakes: Arduino 4 Digit 7 Segment Display: Wiring and Code
What you'll learn
- Multiplexing: sharing pins by showing one digit at a time
- Common cathode displays and digit select lines
- Font tables: one bit per segment
- Persistence of vision
- Splitting a number into digits with division and modulo
- Difficulty: Advanced
- Time: About 40 minutes
- Board: Arduino Uno R3
- Parts: 11
How it works
A four-digit seven-segment display has only 12 pins for 32 LEDs. The segment legs are shared by all four digits, so only one digit can light at a time.
The sketch shows the digits one after another, 4 ms each. Your eye blends them, so you see all four at once, each a bit dimmer than if it was alone.
The display counts tenths of a second, from 000.0 to 999.9, with the point lit on the third digit. Segments run on pins 2 to 9 through 220 ohm resistors. Digits are chosen with pins 10 to 13.
Parts list
11 parts, plus the jumper wires. They retail for about $33; on Mokxi they're free.
- 1 × Arduino Uno R3In Starter Kit, Claw Machine Kit, Vending Machine Kit.
- 1 × Full-size breadboard
- 1 × Four-digit seven segment, multiplexed
- 8 × Resistor, 220 ΩIn Starter Kit, Claw Machine Kit, Halloween Prop Kit.
Kits that can build it
These 8 starter kits have every part in the circuit. Each kit's page lists what else it can build.
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 |
|---|---|
| Four-digit seven segment, multiplexed pin DIG4 | Arduino Uno R3 pin 13 |
| Four-digit seven segment, multiplexed pin DIG3 | Arduino Uno R3 pin 12 |
| Four-digit seven segment, multiplexed pin DIG2 | Arduino Uno R3 pin 11 |
| Four-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 | Four-digit seven segment, multiplexed pin E |
| Resistor, 220 Ω (4) pin 2 | Four-digit seven segment, multiplexed pin D |
| Resistor, 220 Ω (8) pin 2 | Four-digit seven segment, multiplexed pin DP |
| Resistor, 220 Ω (3) pin 2 | Four-digit seven segment, multiplexed pin C |
| Resistor, 220 Ω (7) pin 2 | Four-digit seven segment, multiplexed pin G |
| Resistor, 220 Ω (2) pin 2 | Four-digit seven segment, multiplexed pin B |
| Resistor, 220 Ω (6) pin 2 | Four-digit seven segment, multiplexed pin F |
| Resistor, 220 Ω (1) pin 2 | Four-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.
// Four-digit counter: a bare 5641AS 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 to DIG4 -> pins 10 to 13
//
// Twelve legs for four digits: each segment leg goes to that segment in all
// four digits, and each digit has one common leg. So only one digit can be
// shown at a time, and the sketch shows them in turn, four milliseconds each,
// fast enough that the eye sees all four at once, each a quarter as bright.
//
// The display is common cathode: a digit is selected by pulling its common
// LOW, and a segment lit by driving its leg HIGH. Every common goes off before
// the next digit's segments change, or the old digit shows a faint ghost of
// the new one. Try moving that line and look closely.
//
// The count is tenths of a second, 000.0 to 999.9, with the point lit on the
// third digit.
const uint8_t SEGMENT_PINS[8] = {2, 3, 4, 5, 6, 7, 8, 9};
const uint8_t DIGIT_PINS[4] = {10, 11, 12, 13};
// 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};
void setup() {
for (uint8_t i = 0; i < 8; i++) pinMode(SEGMENT_PINS[i], OUTPUT);
for (uint8_t i = 0; i < 4; i++) {
pinMode(DIGIT_PINS[i], OUTPUT);
digitalWrite(DIGIT_PINS[i], HIGH); // common cathode: HIGH is off
}
}
static void show(uint8_t digit, uint8_t pattern) {
for (uint8_t d = 0; d < 4; d++) digitalWrite(DIGIT_PINS[d], HIGH); // all off first
for (uint8_t s = 0; s < 8; s++) {
digitalWrite(SEGMENT_PINS[s], (pattern >> s) & 1 ? HIGH : LOW);
}
digitalWrite(DIGIT_PINS[digit], LOW); // then this one on
delay(4);
}
void loop() {
unsigned long tenths = (millis() / 100) % 10000;
show(0, FONT[tenths / 1000]);
show(1, FONT[tenths / 100 % 10]);
show(2, (uint8_t)(FONT[tenths / 10 % 10] | 0x80));
show(3, FONT[tenths % 10]);
}
Code walkthrough
The key functions of the sketch, and what each one does.
setup sketch.ino
Makes the eight segment pins and four digit pins outputs. It sets every digit pin HIGH, which is off for a common cathode display.
void setup() {
for (uint8_t i = 0; i < 8; i++) pinMode(SEGMENT_PINS[i], OUTPUT);
for (uint8_t i = 0; i < 4; i++) {
pinMode(DIGIT_PINS[i], OUTPUT);
digitalWrite(DIGIT_PINS[i], HIGH); // common cathode: HIGH is off
}
}show sketch.ino
Shows one digit. First it turns all four digits off. Then it sets the eight segment pins from the bits of pattern. Last it pulls that digit's pin LOW and waits 4 ms. Turning everything off first stops ghost images of the old digit.
static void show(uint8_t digit, uint8_t pattern) {
for (uint8_t d = 0; d < 4; d++) digitalWrite(DIGIT_PINS[d], HIGH); // all off first
for (uint8_t s = 0; s < 8; s++) {
digitalWrite(SEGMENT_PINS[s], (pattern >> s) & 1 ? HIGH : LOW);
}
digitalWrite(DIGIT_PINS[digit], LOW); // then this one on
delay(4);
}loop sketch.ino
Counts tenths from millis() / 100, wrapping at 10000. Then it calls show four times, picking each digit with division and modulo and looking its pattern up in FONT. The third digit gets 0x80 added to light the decimal point.
void loop() {
unsigned long tenths = (millis() / 100) % 10000;
show(0, FONT[tenths / 1000]);
show(1, FONT[tenths / 100 % 10]);
show(2, (uint8_t)(FONT[tenths / 10 % 10] | 0x80));
show(3, FONT[tenths % 10]);
}Troubleshooting
The usual mistakes with this circuit, and the fix for each.
- Some segments never light, or the wrong ones do This project
Each segment leg needs its own resistor to its own pin. A to pin 2 up to DP to pin 9, in order. - Digits appear in the wrong places This project
DIG1 goes to pin 10 and DIG4 goes to pin 13. The leftmost digit is DIG1. - Faint ghosts of one digit show on the next This project
Keep the line inshowthat turns all digits off before the segments change. - 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.