Double 7-Segment LED With IO Expander

Double Seven LED V1 Photo

Now that we can drive a single 7-segment LED, let’s try a double!



Qty Vendor Part# Description Price Comment
1 Mouser 696-LDD-A514RI 2-digit c/a LED Display $2.17 Datasheet
1 Mouser 579-MCP23018-E/SP I/O Expanders, Repeaters & Hubs 16B I/O Expander I2C interface $1.58 Datasheet
2 Mouser 652-4116R-1LF-1K Resistor Networks & Arrays 16pin 1Kohms Isolated Low Profile $0.60 Datasheet


The LDD-A514RI unit features two 7-segment LED digits put together. It operates just like two separate single-digit, except it’s physically a single unit. I’ve also chosen a common-anode version for this test, but common-cathode units are available as well. Where the single digit had a single +5V pin plus seven segment pins, this needs +5V on one pin and FOURTEEN pins to control each segment.

Fourteen pins is a lot. While we could theoretically control it with an Arduino’s pins, it wouldn’t leave much space left over for whatever else we’d want to do with the Arduino someday. So this is a good time to involve an I/O Expander as well. This unit controls 16 I/O pins using the I2C bus. The basic idea is that it accepts two bytes of data, and pushes out each bit to a separate I/O pin. That’s perfect for our purposes.

As with the single-digit, we need resistors, only this time we need TWO of these guys.

Background Reading

First, some background reading. It’s a good idea to understand…


This absolutely can be laid on out a breadboard, although it involves a ton of wires: 28 for just the segments. Too bad I never took a picture when it was on a breadboard.

Double Seven LED V1.sch

Arduino to I/O Expander

This is a very simple connection. We simply wire up:

  • 1/VSS: GND
  • 11/VDD: +5V
  • 12/SCL: A5
  • 13/SDA: A4
  • 15/ADDR: GND
  • 16/RESET: +5V

I/O Expander to 2-digit LED

We wire these up via the resistor array.

  • 3-10/GPB0-7: Digit 2, GPB0 to ‘A’ segment, up to GPB6 to ‘G’ segment
  • 20-27/GPA0-7: Digit 1, GPA0 to ‘A’ segment, up to GPA6 to ‘G’ segment

It would actually be better to connect GPx0 to the ‘G’ segments instead, because the ledCharSet font indicates the ‘G’ segment in the lowest bit. As it is, I have since baked this design into a PCB, so I am stuck with this now until the next rev.


I/O Expander Library

See the entire library on github:libraries/MCP23018.

Because I expect the I/O expander to be useful again, I’ve put the code to drive it in a library. The library does not use the full functionality of the chip–it’s just enough to get through this. Here are the basics needed to get going. Please refer to the code on Github for the line-by-line details.

The constructor sets up the actual address of the chip, based on how it the ADDR pin was wired. It sets all the pins to be outputs.

// MCP23018 address on I2C bus

const uint8_t I2C_MCP23018 = B0100000;

// MCP23018 registers

const uint8_t IODIRA = 0x0;
const uint8_t IODIRB = 0x1;
const uint8_t GPIOA = 0x12;

MCP23018::MCP23018(uint8_t _address)
i2c_address = ( _address & B111 ) | I2C_MCP23018;

void MCP23018::begin(void)
// Set all port 'A' pins to outputs

// Set all port 'B' pins to outputs

The main function to set the output values is SetPorts, which writes both values to the GPIOA & GPIOB registers.

void MCP23018::writePairToRegister(uint8_t address, uint8_t first_data, uint8_t second_data)

void MCP23018::SetPorts(uint8_t _a, uint8_t _b)

Display Example

See the entire sketch on github:Double Seven LED Test.

Once the I/O expander functionality is abstracted away, it’s a simple matter to display the digits. The simple example counts from 00 to FF, and displays the high nibble in digit 1, and the low in digit 2.

Once we retrieve the character from the ledCharSet font, it’s a simple matter to send digit 1 to port A and digit 2 to Port B. The trick in this case is that I wired the segments backward from the way the font is laid out, so I have to reverse them. Also, the font has a ‘1’ for segments that are on, but to turn off a segment we have to send a ‘0’ to the I/O Expander.

void setup(void)

// Set all 1's, turns the display off by default

uint8_t value;

void loop()
// Send the current value to the chip, high nibble to 'A', low nibble 'B'
pex.SetPorts(ledCharSet[value >> 4],ledCharSet[value & 0xf]);

// Next value. Note that this will wrap around from 0xff back to 0 with no additional
// work needed because it is an 8-bit value.

// ...and wait

Circuit Board

It’s quite handy to have a little 2-digit display to add to other projects which only requires power, ground, and I2C pins. So I designed a small PCB using Eagle and sent it out for fab with Laen’s DorkbotPDX PCB Order.

Double Seven LED V1-laen

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 )

Twitter picture

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

Facebook photo

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

Google+ photo

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

Connecting to %s