Driving a 4-Digit 7-Segment Display

Draft. This tutorial has not been checked against the physical product yet. Confirm wiring, pin assignments and voltage limits against the product documentation before building it.
DifficultyIntermediate
CategoryDisplays
Supported boardsArduino Uno R3 and compatible ATmega328P boards
Time needed70 minutes
PrerequisitesMore Outputs with a Shift Register
Tested boardNot yet verified
Tested onNot yet verified
Arduino IDE versionNot yet verified
LibraryNot yet verified

What it does

Four digits, each made of seven bar-shaped LEDs plus a decimal point. It shows numbers, brightly, readable across a room, and it costs almost nothing.

What makes it interesting is that it cannot actually show four digits at once. The part does not have enough pins for that. Instead you light one digit at a time, very fast, and your eye assembles the four into a steady display. That technique is called multiplexing, and it is the real subject of this tutorial. Once you have built it by hand, every LED matrix and every display driver chip makes sense.

Before you begin

Required parts and tools

  • An Arduino Uno or compatible board.
  • One 4-digit 7-segment display. This is Siratek product 2469, marked SH5461AS.
  • Eight 220 ohm resistors, one per segment.
  • A breadboard and about twelve jumper wires.

Common cathode, which this one is

The Siratek part is SH5461AS, which is common cathode: all the LEDs in one digit share their negative leg, and you light a segment by driving its anode high while pulling that digit’s common low.

The visually identical SH5641AS is common anode and works the other way round. One character in the part number, opposite logic. If your display does nothing with the sketch below, read the number printed on its side before changing anything else.

Twelve pins, and what they are

Two rows of six along the top and bottom edges. Eight of them are segments, shared by all four digits, and four are the digit commons.

Pin Function
11, 7, 4, 2, 1, 10, 5 Segments a to g
3 Decimal point dp
12, 9, 8, 6 Digit commons, left to right

Pin numbering starts at the bottom left with the display the right way up, runs along the bottom, then continues along the top from right to left, exactly like a DIP chip.

The mapping above is for this part. Do not assume it — a quick continuity test with a multimeter on its diode range, touching one common and probing each other pin, lights one segment at a time and tells you your own display’s mapping in two minutes. Using a Multimeter covers that range.

One resistor per segment, on the segment side

Eight resistors, in the eight segment lines. Not four in the common lines.

Put them in the commons and the brightness of each digit changes with how many segments it has lit: a 1 with two segments would blaze while an 8 with seven looked dim, because they would share the same resistor. This is the same argument as one resistor per colour on the RGB LED, and it has the same visible consequence.

The pin cost, and why the next tutorial exists

Eight segments plus four commons is twelve pins. An Uno has fourteen digital pins, two of which you want for serial.

So this display, wired directly, uses essentially the whole board. That is fine for learning and impractical for a project, and it is exactly why the MAX7219 exists. Build this one to understand multiplexing; use a driver chip when you need the pins back.

Current, and why the resistors must not be too small

During multiplexing each digit is lit only a quarter of the time, so the display looks dimmer than a steady one. The tempting fix is smaller resistors.

Be careful. The peak current through the common pin is the sum of all lit segments at once, and an Arduino pin should not be sinking much more than 20 mA. With seven segments lit through 220 ohm resistors, the peak is already well beyond what one pin should carry.

For a first build on a bench this is survivable, and it is why the sketch below keeps the duty cycle modest. For anything permanent, drive the commons through transistors, or use the MAX7219, which is designed for exactly this.

Pin reference

Display pin Connect to Purpose
a (11) Uno D2 through 220 ohms Segment
b (7) Uno D3 through 220 ohms Segment
c (4) Uno D4 through 220 ohms Segment
d (2) Uno D5 through 220 ohms Segment
e (1) Uno D6 through 220 ohms Segment
f (10) Uno D7 through 220 ohms Segment
g (5) Uno D8 through 220 ohms Segment
dp (3) Uno D9 through 220 ohms Decimal point
Digit 1 (12) Uno D10 Common cathode, leftmost
Digit 2 (9) Uno D11 Common cathode
Digit 3 (8) Uno D12 Common cathode
Digit 4 (6) Uno D13 Common cathode, rightmost
A four-digit seven-segment display with eight segment lines each through a 220 ohm resistor, and four digit common lines driven directly, showing one digit lit at a time
Eight segments shared by four digits. Only one digit is lit at any instant.

Wiring steps

  1. Unplug the USB cable.
  2. Seat the display across the breadboard’s centre channel.
  3. Wire the four digit commons first: pins 12, 9, 8 and 6 to D10 to D13.
  4. Wire one segment, a, through a 220 ohm resistor to D2.
  5. Plug in and run the first sketch below. You should see the a segment march across the four digits. Prove this before wiring the other seven.
  6. Unplug, wire the remaining seven segments, and plug back in.

Step 5 is the difference between a pleasant hour and a miserable one. With one segment working you have proved the commons, the power and the sketch, and everything after that is repetition.

Software and libraries

No library is required, deliberately. Libraries exist that drive this part, and they hide the multiplexing, which is the only reason to build this circuit at all.

Minimal working example

// Siratek: prove the four digit commons with a single segment.

const int segmentA = 2;
const int digitPins[4] = {10, 11, 12, 13};

void setup() {
  pinMode(segmentA, OUTPUT);
  for (int i = 0; i < 4; i++) {
    pinMode(digitPins[i], OUTPUT);
    digitalWrite(digitPins[i], HIGH);   // HIGH is off on a common cathode
  }
}

void loop() {
  for (int i = 0; i < 4; i++) {
    digitalWrite(segmentA, HIGH);
    digitalWrite(digitPins[i], LOW);    // this digit on
    delay(300);
    digitalWrite(digitPins[i], HIGH);   // and off again
  }
}

On a common cathode display, a digit is on when its common is LOW. That inversion is the thing to hold on to: segments are driven high, commons are pulled low.

Four digits, multiplexed

// Siratek: a four-digit number, one digit lit at a time.

const int segmentPins[8] = {2, 3, 4, 5, 6, 7, 8, 9};   // a b c d e f g dp
const int digitPins[4] = {10, 11, 12, 13};

// Which segments make each numeral, in the order a b c d e f g.
const byte numerals[10] = {
  0b11111100,  // 0
  0b01100000,  // 1
  0b11011010,  // 2
  0b11110010,  // 3
  0b01100110,  // 4
  0b10110110,  // 5
  0b10111110,  // 6
  0b11100000,  // 7
  0b11111110,  // 8
  0b11110110   // 9
};

int showing = 0;

void showDigit(int position, int value) {
  // Everything off first, or the previous digit ghosts into this one.
  for (int i = 0; i < 4; i++) {
    digitalWrite(digitPins[i], HIGH);
  }

  byte pattern = numerals[value];
  for (int s = 0; s < 8; s++) {
    digitalWrite(segmentPins[s], bitRead(pattern, 7 - s));
  }

  digitalWrite(digitPins[position], LOW);
}

void setup() {
  for (int i = 0; i < 8; i++) {
    pinMode(segmentPins[i], OUTPUT);
  }
  for (int i = 0; i < 4; i++) {
    pinMode(digitPins[i], OUTPUT);
    digitalWrite(digitPins[i], HIGH);
  }
}

void loop() {
  int n = showing;

  for (int position = 3; position >= 0; position--) {
    showDigit(position, n % 10);
    n /= 10;
    delay(4);              // about 60 refreshes a second across four digits
  }

  if (millis() % 1000 < 5) {
    showing = (showing + 1) % 10000;
  }
}

Three things here are worth understanding rather than copying.

Everything goes off before the new pattern is set. Change the segments while a digit is still lit and that digit briefly shows the next digit’s pattern. The result is faint extra segments, called ghosting, and this one line is the fix.

The 4 millisecond delay sets the refresh rate. Four digits at 4 ms each is about 60 full refreshes per second. Much slower and you see flicker; much faster and the display dims, because each digit spends less of its time fully on.

numerals is the font. Each bit is one segment, in the order a to g then dp. If your display’s segment order differs from the table above, this array is the only thing you change.

Why delay() is acceptable here, and where it stops being

A multiplexed display must be refreshed constantly. The moment your sketch does something else for more than a few milliseconds, the display visibly stutters.

That is the honest limitation of doing this by hand: the display wants the processor’s attention all the time. The ways out are a timer interrupt, which keeps the refresh going while your code runs, or a driver chip that holds the image itself. The MAX7219 tutorial takes the second route, and the difference in what the rest of your sketch can do is dramatic.

Expected result

A steady four-digit number, counting up once a second, with no visible flicker and no faint ghost segments.

Wave your hand in front of it and you may see the digits separate into a dotted trail. That is the multiplexing becoming visible because your eye is moving, and it is a good way to prove to yourself that only one digit is ever lit.

Troubleshooting

Symptom Likely cause Check or fix
Nothing lights Common anode part, not cathode Check for 5641 rather than 5461
All four digits show the same Commons tied together Each needs its own pin
Faint extra segments Ghosting Blank all digits before setting the pattern
Visible flicker Refresh too slow Reduce the per-digit delay
Display dim Multiplexing, duty cycle Expected; do not simply fit smaller resistors
One digit brighter than others Resistors in the commons Put one resistor per segment instead
A segment never lights Wrong pin mapping Test with a multimeter on the diode range
Segments wrong for every numeral Segment order differs Change the numerals array
Display stutters when the sketch does other work Multiplexing needs constant attention Use a timer, or the MAX7219
Out of pins for anything else Twelve pins is the real cost That is why driver chips exist

Next steps

  • Easier first: More Outputs with a Shift Register, which can drive the eight segment lines.
  • Related: An 8×8 Dot Matrix with MAX7219, the same problem solved by a dedicated chip.
  • Next project: a clock, once you have added the DS3231 real time clock module.

Sources and attribution

All text, wiring guidance and code in this tutorial are original Siratek work.

  • The SH5461AS marking and the four-digit common cathode construction were read from the Siratek product photographs for item 2469.
  • ATmega328P datasheet for the per-pin current guidance that shapes the resistor advice.

Pin-to-segment mapping varies between displays, so this tutorial gives a multimeter procedure for confirming it rather than asking the reader to trust the table. No third-party tutorial text, diagrams, photographs or code has been reproduced here.

Product used in this tutorial: 4 Digits 7 Seven Segment 0.56″ inch LED Numeric Digital Display
Shop
Sidebar
0 Wishlist
0 Cart