Four-Digit 7-Segment LED

Four Seven LED Test V1 Photo

Now that we can drive a single 7-Segment LED, and we can use an I/O Expander to drive a Double 7-Segment LED, what’s the obvious next step? A Four-segment model! In the picture above, I’m driving it with an Arduino Pro Mini sitting on a little connector board I made, though anything that can supply power and I2C will work.



Qty Vendor Part# Description Price Comment
1 Mouser 638-MSQC6912C LED Displays 0.56in Hi Eff Red 4Digit Clock Ca $4.24 Datasheet
1 Mouser 579-MCP23018-E/SP 16B I/O Expander I2C interface $1.58 Datasheet
1 Mouser 652-4116R-1LF-100 16pin 100ohms Isolated Low Profile Resistor Network $0.60 Datasheet
4 Mouser 512-2N3904BU Bipolar Small Signal NPN Transistor General Purpose $0.10 Datasheet


The way this part is wired, only a single digit can be on at any time. The trick is to set one digit, and then quickly move on to the next digit. Each digit is on for 1/4 of the time, but that’s enough to imprint it on your mind and so you see them all. They call that ‘Multiplexing’. Fancy!

As with my other LED’s, I have chosen a ‘Common Anode’ part for consistency.


Four Seven LED V1.sch

Once again, I will use an I/O Expander to drive the ports. That is not strictly necessary if it’s the ONLY thing in a project. However, it enables me to make a board that communicates only with an I2C bus connector and frees the Arduino up for other things.

The 8 pins of the ‘B’ port are connected to the digits themselves. This is exactly the same as with the earlier Double 7-Segment unit, only this time I reversed the A-G legs so that the font I have works correctly.

Four pins of the ‘A’ port control which digit is getting power at any time, by connecting with each digit’s common anode. Only one of these will ever be ‘on’ at once. To connect power to the anode, I use a transistor connected to the power supply.

Multiplexing with Interrupts

The cleanest way to handle multiplexing is with interrupts. This ensures that the digits always get displayed with the correct timing, and that your program logic can do whatever it wants as its primary focus. To multiplex, we set a single digit’s value, and then quickly move on to the next digit. Each digit is on for 1/4 of the time, but that’s enough to imprint it on your mind and so you see them all. This is accomplished with the 8-bit Timer2 interrupt.

This setup code listed down below enables the 8-bit Timer2 at an 1/1024 prescalar. This means that every 1024 clock cycles, the timer counter will increment. When the counter overflows from 0xFF to 0x00, the interrupt fires. By setting the counter to 256-50, the interrupt will fire every 50 * 1204 clock cycles, or 312.5Hz. This will refresh the entire display every 78.125Hz, which I have found optimal.

Background Reading

I found these articles helpful in learning how to do this:


See the entire library on github:libraries/MSQC6XX2C.

There are two basic functions that the driver library for this 4-digit display needs to do:* Manage interrupts* Display numbers

Manage Interrupts

// 50 ticks @ 15.625kHz = 3.2msec delay = 312.5Hz update per digit /4 = 78.125Hz total update cycle
const uint8_t tick_reset = 256-50;

void MSQC6XX2C::begin(void)

...Other setup code omitted...

// Setup interrupts

// Prescaler = FCPU/1024 = 16MHz/1024 = 15.625kHz
TCCR2A = 0;
TCCR2B = 1<<CS22 | 1<<CS21 | 1<<CS20;

//Enable Overflow Interrupt Enable
TIMSK2 = 1<<TOIE2;

//Initialize Counter
TCNT2 = tick_reset;

// Enable interrupts

void MSQC6XX2C::isr(void)
if (instance)

// Multiplex LED digits on the interrupt

// Enable interrupts so that the Wire library can work


//Capture the current timer value. This is how much error we
//have due to interrupt latency and the work in this function

//Reload the timer and correct for latency.

Display Numbers

The new thing to learn when displaying these numbers is how to drive the transistors which enable power on each digit. When we want to display a digit, we will send current out to the base of the transistor. The only problem is that the MCP23018 is an ‘open drain’ I/O expander, so it is capable of sinking current, but not sourcing current. Fortunately, this chip is built with internal pull-up resistors. When we enable those, and write a ‘1’ to the port, the pull-up resistor will connect the line to power. That’s enough to open the transistor and enable full current flow to the digit.

// Initial display state
uint8_t values_init[] = { 0,1,2,3 };

void MSQC6XX2C::begin(void)
// Ports A0-A4 drive transistors for the digits
// They need to be pulled up to Vcc so that a '1' will
// Send current out to the resistor's base.

...Other setup code omitted...


Callers will give us 4 numbers to display, and we will copy them to our internal buffer.

void MSQC6XX2C::set(uint8_t* _values)

Then every time the interrupt fires, we display one of the digits.

void MSQC6XX2C::update(void)
bitval >>= 1;
if ( ++values_display_current >= values_display_end )
values_display_current = values_display;
bitval = B1000;

Display Example

This sample code simply loops through 4 digits at a time, 1234, 2345, 3456, etc…

#include <Wire.h>
#include <MCP23018.h>
#include <MSQC6XX2C.h>

MCP23018 pex(0);
MSQC6XX2C display(&pex);

void setup()

uint8_t values[] = { 0,1,2,3,4,5,6,7,8,9,0,1,2,3,4 };
uint8_t* values_end = values + 10;
uint8_t* values_current = values;

void loop()
// Send the current 4 values to the display

// Increment to the next set of values, or wrap around to
// the start
if ( ++values_current >= values_end )
values_current = values;

// Wait

Circuit Board

Four Seven LED V1-laen

More photos

On a breadboard

Here’s what it looked like during prototyping…

Four Seven LED Test V1 Breadboard Photo

The backside

What the little display board looks like from underneath…

Four Seven LED Test V1 Backside Closeup Photo


Leave a comment

Filed under 7-Segment, Arduino

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s