As an increasing number of people enjoy experimenting with retro-hardware and electronics – especially stuff with numerical LED displays – they have discovered the classic MC14489 LED display driver.

The MC14489 (originally from Motorola) can drive five seven-segment LED numbers with decimal point, or a combination of numbers and separate LEDs. You can also daisy-chain more than one to drive more digits, and it’s controlled with a simple serial data-clock method in the same way as a 74HC595 shift register.

Although it’s an older part, sourcing the MC14489 isn’t too difficult – you can order them from PMD Way in a blink.

For the purpose of the tutorial we’ll show you how to send commands easily from your Arduino or compatible board to control a five-digit 7-segment LED display module – and the instructions are quite simple so they should translate easily to other platforms. Once you have mastered the single module, using more than one MC14489 will be just as easy. So let’s get started.

Hardware

Before moving forward, download the data sheet (pdf). You will need to refer to this as you build the circuit(s). And here’s our subject in real life:

For our demonstration display we’ll be using a vintage HP 5082-7415 LED display module. However you can use almost any 7-segment modules as long as they’re common-cathode. If you’re using a four-digit module and want an extra digit, you can add another single digit display.

If you want a ruler, the design files are here.

Connecting the MC14489 to an LED display isn’t complex at all. From the data sheet consider Figure 9:

Each of the anode control pins from the MC14489 connect to the matching anodes on your display module, and the BANK1~5 pins connect to the matching digit cathode pins on the display module. You can find the MC14489 pin assignments on page 1 of the data sheet. Seeing as this is chapter fifty-one – by now you should be confident with finding such information on the data sheets, so I will be encouraging you to do a little more of the work.

Interesting point – you don’t need current-limiting resistors. However you do need the resistor Rx – this controls the current flow to each LED segment. But which value to use? You need to find out the forward current of your LED display (for example 20 mA) then check Figure 7 on page 7 of the data sheet:

To be conservative I’m using a value of 2k0 for Rx, however you can choose your own based on the data sheet for your display and the graph above. Next – connect the data, clock and enable pins of the MC14489 to three Arduino digital pints – for our example we’re using 5, 6 and 7 for data, clock and enable respectively.

Then it’s just 5V and GND to Arduino 5V and GND – and put a 0.1uF capacitor between 5V and GND. Before moving on double-check the connections – especially between the MC14489 and the LED display.

Controlling the MC14489

To control the display we need to send data to two registers in the MC14489 – the configuration register (one byte) and the display register (three bytes). See page 9 of the data sheet for the overview.

The MC14489 will understand that if we send out one byte of data it is to send it the configuration register, and if it receives three bytes of data to send it to the display register. To keep things simple we’ll only worry about the first bit (C0) in the configuration register – this turns the display outputs on or off. To do this, use the following:

digitalWrite(enable, LOW); shiftOut(data, clock, MSBFIRST, B00000001); // used binary for clarity, however you can use decimal or hexadecimal numbers digitalWrite(enable, HIGH); delay(10);

and to turn it off, send bit C0 as zero. The small delay is necessary after each command.

Once you have turned the display on – the next step is to send three bytes of data which represent the numbers to display and decimal points if necessary. Review the table on page 8 of the data sheet. See how they have the binary nibble values for the digits in the third column.

Thankfully the nibble for each digit is the binary value for that digit. Furthermore you might want to set the decimal point – that is set using three bits in the first nibble of the three bytes (go back to page 9 and see the display register). Finally you can halve the brightness by setting the very first bit to zero (or one for full brightness).

As an example for that – if you want to display 5.4321 the three bytes of data to send in binary will be:

1101 0101 0100 0011 0010 0001

Let’s break that down. The first bit is 1 for full brightness, then the next three bits (101) turn on the decimal point for BANK5 (the left-most digit). Then you have five nibbles of data, one for each of the digits from left to right. So there’s binary for 5, then four, then three, then two, then one.

digitalWrite(enable, LOW); shiftOut(data, clock, MSBFIRST, B11010101); // D23~D16 shiftOut(data, clock, MSBFIRST, B01000011); // D15~D8 shiftOut(data, clock, MSBFIRST, B00100001); // D7~D0 digitalWrite(enable, HIGH); delay(10);

To demonstrate everything described so far, it’s been neatly packaged into our first example sketch:

// Example 51.1 // Motorola MC14489 with HP 5082-7415 5-digit, 7-segment LED display // 2k0 resistor on MC14489 Rx pin // John Boxall 2013 CC by-sa-nc // define pins for data from Arduino to MC14489 // we treat it just like a 74HC595 int data = 5; int clock = 6; int enable = 7; void setup() { pinMode(data, OUTPUT); pinMode(enable, OUTPUT); pinMode(clock, OUTPUT); displayOn(); // display defaults to off at power-up } void displayTest1() // displays 5.4321 { digitalWrite(enable, LOW); // send 3 bytes to display register. See data sheet page 9 // you can also insert decimal or hexadecimal numbers in place of the binary numbers // we're using binary as you can easily match the nibbles (4-bits) against the table // in data sheet page 8 shiftOut(data, clock, MSBFIRST, B11010101); // D23~D16 shiftOut(data, clock, MSBFIRST, B01000011); // D15~D8 shiftOut(data, clock, MSBFIRST, B00100001); // D7~D0 digitalWrite(enable, HIGH); delay(10); } void displayTest2() // displays ABCDE { digitalWrite(enable, LOW); // send 3 bytes to display register. See data sheet page 9 // you can also insert decimal or hexadecimal numbers in place of the binary numbers // we're using binary as you can easily match the nibbles (4-bits) against the table // in data sheet page 8 shiftOut(data, clock, MSBFIRST, B10001010); // D23~D16 shiftOut(data, clock, MSBFIRST, B10111100); // D15~D8 shiftOut(data, clock, MSBFIRST, B11011110); // D7~D0 digitalWrite(enable, HIGH); delay(10); } void displayOn() // turns on display { digitalWrite(enable, LOW); shiftOut(data, clock, MSBFIRST, B00000001); digitalWrite(enable, HIGH); delay(10); } void displayOff() // turns off display { digitalWrite(enable, LOW); shiftOut(data, clock, MSBFIRST, B00000000); digitalWrite(enable, HIGH); delay(10); } void loop() { displayOn(); displayTest1(); delay(1000); displayTest2(); delay(1000); displayOff(); delay(500); }

… with the results in the following video:

Now that we can display numbers and a few letters with binary, life would be easier if there was a way to take a number and just send it to the display.

So consider the following function that takes an integer between 0 and 99999, does the work and sends it to the display:

void displayIntLong(long x) // takes a long between 0~99999 and sends it to the MC14489 { int numbers[5]; byte a=0; byte b=0; byte c=0; // will hold the three bytes to send to the MC14489 // first split the incoming long into five separate digits numbers[0] = int ( x / 10000 ); // left-most digit (will be BANK5) x = x % 10000; numbers[1] = int ( x / 1000 ); x = x % 1000; numbers[2] = int ( x / 100 ); x = x % 100; numbers[3] = int ( x / 10 ); x = x % 10; numbers[4] = x % 10; // right-most digit (will be BANK1) // now to create the three bytes to send to the MC14489 // build byte c which holds digits 4 and 5 c = numbers[3]; c = c << 4; // move the nibble to the left c = c | numbers[4]; // build byte b which holds digits 3 and 4 b = numbers [1]; b = b << 4; b = b | numbers[2]; // build byte a which holds the brightness bit, decimal points and digit 1 a = B10000000 | numbers[0]; // full brightness, no decimal points // now send the bytes to the MC14489 digitalWrite(enable, LOW); shiftOut(data, clock, MSBFIRST, a); shiftOut(data, clock, MSBFIRST, b); shiftOut(data, clock, MSBFIRST, c); digitalWrite(enable, HIGH); delay(10); }

So how does that work? First it splits the 5-digit number into separate digits and stores them in the array numbers[]. It then places the fourth digit into a byte, then moves the data four bits to the left – then we bitwise OR the fifth digit into the same byte. This leaves us with a byte of data containing the nibbles for the fourth and fifth digit.

The process is repeated for digits 2 and 3. Finally the brightness bit and decimal point bits are assigned to another byte which then has the first digit’s nibble OR’d into it. Which leaves us with bytes a, b and c ready to send to the MC14489.

Note that there isn’t any error-checking – however you could add a test to check that the number to be displayed was within the parameter, and if not either switch off the display (see example 51.1) or throw up all the decimal points or … whatever you want.

Here’s our final demonstration sketch (example 51.2)

// Example 51.2 // Motorola MC14489 with HP 5082-7415 5-digit, 7-segment LED display // 2k0 resistor on MC14489 Rx pin // John Boxall 2013 CC by-sa-nc // define pins for data from Arduino to MC14489 // we treat it just like a 74HC595 int data = 5; int clock = 6; int enable = 7; long i; void setup() { randomSeed(analogRead(0)); pinMode(data, OUTPUT); pinMode(enable, OUTPUT); pinMode(clock, OUTPUT); displayOn(); // display defaults to off at power-up } void displayOn() // turns on display { digitalWrite(enable, LOW); shiftOut(data, clock, MSBFIRST, B00000001); digitalWrite(enable, HIGH); delay(10); } void displayOff() // turns off display { digitalWrite(enable, LOW); shiftOut(data, clock, MSBFIRST, B00000000); digitalWrite(enable, HIGH); delay(10); } void displayIntLong(long x) // takes a long between 0~99999 and sends it to the MC14489 { int numbers[5]; byte a=0; byte b=0; byte c=0; // will hold the three bytes to send to the MC14489 // first split the incoming long into five seperate digits numbers[0] = int ( x / 10000 ); // left-most digit (will be BANK5) x = x % 10000; numbers[1] = int ( x / 1000 ); x = x % 1000; numbers[2] = int ( x / 100 ); x = x % 100; numbers[3] = int ( x / 10 ); x = x % 10; numbers[4] = x % 10; // right-most digit (will be BANK1) // now to create the three bytes to send to the MC14489 // build byte a which holds the brightness bit, decimal points and digit 1 a = B10000000 | numbers[0]; // full brightness, no decimal points // build byte b which holds digits 3 and 4 b = numbers [1]; b = b << 4; b = b | numbers[2]; // build byte c which holds digits 4 and 5 c = numbers[3]; c = c << 4; // move the nibble to the left c = c | numbers[4]; // now send the bytes to the MC14489 digitalWrite(enable, LOW); shiftOut(data, clock, MSBFIRST, a); shiftOut(data, clock, MSBFIRST, b); shiftOut(data, clock, MSBFIRST, c); digitalWrite(enable, HIGH); delay(10); } void loop() { i = random(0,100000); displayIntLong(i); delay(200); }

…which results in the following video:

You can also display the letters A to F by sending the values 10 to 15 respectivel to each digit’s nibble. However that would be part of a larger application, which you can (hopefully) by now work out for yourself. Furthermore there’s some other characters that can be displayed – however trying to display the alphabet using 7-segment displays is somewhat passé. Instead, get some 16-segment LED modules or an LCD.

Finally, you can cascade more than one MC14489 to control more digits. Just run a connection from the data out pin on the first MC14889 to the data pin of the second one, and all the clock and enable lines together. Then send out more data – see page 11 of the data sheet. If you’re going to do that in volume other ICs may be a cheaper option and thus lead you back to the MAX7219.

Conclusion

For a chance find the MC14489 is a fun an inexpensive way to drive those LED digit displays. We haven’t covered every single possible option or feature of the part – however you will now have the core knowledge to go further with the MC14489 if you need to move further with it.

This post brought to you by pmdway.com – everything for makers and electronics enthusiasts, with free delivery worldwide.

To keep up to date with new posts at tronixstuff.com, please subscribe to the mailing list in the box on the right, or follow us on twitter @tronixstuff.