Now that we can drive a single 7-segment LED, let’s try a double!
|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.
First, some background reading. It’s a good idea to understand…
- 7-Segment LED. Read through my previous post on a single-digit 7-segment LED.
- The Wire library. Arduino provides an I2C library called ‘Wire’. We’ll be using it extensively.
- Interfacing the Arduino to the MCP23016 I/O Expander by Lewis Loflin. Great introduction to this family of I/O Expanders, using an Arduino.
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.
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;
i2c_address = ( _address & B111 ) | I2C_MCP23018;
// 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)
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.
// Set all 1's, turns the display off by default
// 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
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.