Tutorial – Arduino and MC14489 LED Display Driver
Learn how to use MC14489 LED display driver ICs with Arduino in chapter fifty-one of a series originally titled “Getting Started/Moving Forward with Arduino!” by John Boxall – A tutorial on the Arduino universe. The first chapter is here, the complete series is detailed here.
Updated 12/05/2013
Introduction
Recently we’ve been looking at alternatives to the MAX7219 LED display driver IC due to pricing and availability issues (stay tuned for that one) – and came across an old but still quite useful IC – the MC14489 from Motorola (now Freescale Semiconductor). The MC14489 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. Sourcing the MC14489 isn’t too difficult – it’s available from element14, Newark, Digikey, and so on – or if you’re not in a hurry, try the usual suspects like Futurlec.
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 - for example, Sparkfun part number COM-11405. 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 (click the image to enlarge):
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 (click image to enlarge):
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:
// 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.
You can download the demonstration sketch for the function – Example 51.2, and view the 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. And if you enjoy my tutorials, or want to introduce someone else to the interesting world of Arduino – check out my new book “Arduino Workshop” from No Starch Press.
In the meanwhile have fun and keep checking into tronixstuff.com. Why not follow things on twitter, Google+, subscribe for email updates or RSS using the links on the right-hand column? And join our friendly Google Group – dedicated to the projects and related items on this website. Sign up – it’s free, helpful to each other – and we can all learn something.
The 555 Precision Timer IC
Hello readers
Today we revisit one of the most popular integrated circuits ever conceived – the 555 timer IC. “Triple-five”, “five-five-five”, “triple-nickel” … call it what you will, it has been around for thirty-eight years. Considering the pace of change in the electronics industry, the 555 could be the constant in an ever-changing universe. But what is the 555? How does it work? How can we use it? And … why do we still use it? In this introductory article we will try to answer these questions. If you would like to see some examples, visit here.
What is the 555?
The 555 timer is the solution to a problem found by the inventor – Hans Camenzind. He saw the need through his radio work for a part that could act as an oscillator or a timer [1]; and working as a contractor for Signetics developed the 555. (Signetics was purchased by Philips in 1975, and their semiconductor division was spun off as NXP in 2006). The 555 has to be one of the most used ICs ever invented. It is used for timing, from microseconds to hours; and creating oscillations (which is another form of timing for the pedants out there). It is very flexible with operation voltage, you can throw from 4.5 to 18V at it; you can sink or source 200mA of current through the output; and it is very cheap – down to around nine cents if you order several thousand units. Finally, the 555 can achieve all of this with a minimum of basic components – some resistors and capacitors.
Here are some examples in the common DIP casing:
Furthermore a quick scan of suppliers’ websites show that the 555 is also available in surface-mount packages such as SOIC, MSOP and TSSOP. You can also source a 556 timer IC, which contains two 555 ICs. (What’s 555 + 555? 556…) Furthermore, a 558 was available in the past, but seems rather tricky to source these days.
How does the 555 work?
The 555 contains two major items:
- A comparator – a device which compares two voltages, and switches its output to indicate which is larger, and
- A flip-flop – a circuit that has two stable states, and those states can be changed by applying a voltage to one of the flip-flop’s inputs.
Here is the 555 functional diagram from the TI 555 data sheet.pdf:
… and the matching pin-out diagram:
Don’t let the diagrams above put you off. It is easier to explain how the 555 operates within the context of some applications, so we will now explore the three major uses of the 555 timer IC in detail – these being astable, monostable, and bistable operations, in theory and in practice.
Astable operation
Astable is an on-off-on… type of oscillation – and generates what is known as a square wave, for example:
There are three values to take note of:
- time (s) – the time for a complete cycle. The number of cycles per second is known as the frequency, which is the reciprocal of time (s);
- tm (s) – the duration of time for which the voltage (or logic state) is high;
- ts (s) - the duration of time for which the voltage (or logic state) is low.
With the use of two resistors and one capacitor, you can determine the period durations. Consider the following schematic:
Calculating values for R1, R2 and C1 was quite simple. You can either determine the length of time you need (t) in seconds, or the frequency (Hz) – the number of pulses per second.
t (time) = 0.7 x (R1 + [2 x R2]) x C1
f (frequency) = 1.4 / {(R1 + [2 x R2]) x C1}
Where R1 and R2 are measured in ohms, and C1 is measured in farads. Remember that 1 microfarad = 1.0 × 10-6 farads, so be careful to convert your capacitor values to farads carefully. It is preferable to keep the value of C1 as low as possible for two reasons – one, as capacitor tolerances can be quite large, the larger the capacitor, the greater your margin of error; and two, capacitor values can be affected by temperature.
How the circuit works is relatively simple. At the time power is applied, the voltage at pin 2 (trigger) is less than 1/3Vcc. So the flip-flop is switched to set the 555 output to high. C1 will charge via R1 and R2. After a period of time (Tm from the diagram above) the voltage at pin 6 (threshold) goes above 2/3Vcc. At this point, the flip-flop is switched to set the 555 output to low. Furthermore, this enables the discharge function – so C1 will discharge via R2. After a period of time (Ts from the diagram above) the voltage at pin 2 (trigger) is less than 1/3Vcc. So the flip-flop is switched to set the 555 output to high… and the cycle repeats.
Now, for an example, I want to create a pulse of 1Hz (that is, one cycle per second). It would be good to use a small value capacitor, a 0.1uF. In farads this is 0.0000001 farads. Phew. So our equation is 1=1.4/{(R1 + [2 x R2]) x C1}. Which twists out leaving us R1=8.2Mohm, R2=2.9MOhm and C1 is 0.1uF. I don’t have a 2.9MOhm resistor, so will try a 2.7MOhm value, which will give a time value of around 0.9s. C2 in astable mode is optional, and used if there is a lot of electrical noise in the circuit. Personally, I use one every time, a 0.01uF ceramic capacitor does nicely. Here is our example in operation:
Notice how the LED is on for longer than it is off, that is due to the ‘on’ time being determined by R1+R2, however the ‘off’ time is determined by R2 only. The ‘on’ time can be expressed as a percentage of the total pulse time, and this is called the duty cycle. If you have a 50% duty cycle, the LED would be on and off for equal periods of time. To alter the duty cycle, place a small diode (e.g. a 1N4148) over pins 7 (anode) and 2 (cathode). Then you can calculate the duty cycle as:
Tm = 0.7 x R1 x C1 (the ‘on’ time)
Ts = 0.7 x R2 x C1 (the ‘off’ time)
Furthermore, the 555 can only control around 200mA of current from the output to earth, so if you need to oscillate something with more current, use a switching transistor or a relay between the output on pin 3 and earth. If you are to use a relay, put a 1N4001 diode between pin 3 (anode) and the relay coil (cathode); and a 1N418 in parallel with the relay coil, but with the anode on the earth side. This stops any reverse current from the relay coil when it switches contacts.
Monostable operation
Mono for one – one pulse that is. Monostable use is also known as a “one-shot” timer. So the output pin (3) stays low until the 555 receives a trigger pulse (drop to low) on pin 2. The length of the resulting pulse is easy to calculate:
T = 1.1 x R1 x C1;
where T is time in seconds, R1 is resistance in ohms, and C1 is capacitance in farads. Once again, due to the tolerances of capacitors, the longest time you should aim for is around ten minutes. Even though your theoretical result for T might be 9 minutes, you could end up with 8 minutes 11 seconds. You might really need those extra 49 seconds to run away… Though you could always have one 555 trigger another 555… but if you were to do that, you might as well use a circuit built around an ATmega328 with Arduino bootloader.
Now time for an example. Let’s have a pulse output length of (as close as possible to) five seconds. So, using the equation, 5 = 1.1 x R1 x C1… I have a 10 uF capacitor, so C1 will be 0.00001 farads. Therefore R1 will be 454,545 ohms (in theory)… the closest I have is a 470k, so will try that and see what happens. Note that it you don’t want a reset button (to cancel your pulse mid-way), just connect pin 4 to Vs. Here is the schematic for our example:
How the monostable works is quite simple. Nothing happens when power is applied, as R2 is holding the trigger voltage above 1/3Vcc. When button S1 is pushed, the trigger voltage falls below 1/3Vcc, which causes the flip-flop to set the 555′s output to high. Then C1 is charged via R1 until the threshold voltage 2/3Vcc is reached, at which point the flip-flip sets the output low and C1 discharges. Nothing further happens until S1 is pressed again. The presence of the second button S2 is to function as a reset switch. That is, while the output is high the reset button, if pressed, will set the output low and set C1 to discharge.
Below is a video of my example at work. First I let it run the whole way through, then the second and subsequent times I reset it shortly after the trigger. No audio in clip:
Once again, we now have a useful form of a one-shot timer with our 555.
Bistable operation
Bistable operation is where the 555′s output is either high, or low – but not oscillating. If you pulse the trigger, the output becomes and stays high, until you pulse reset. With a bistable 555 you can make a nice soft-touch electronic switch for a project… let’s do that now, it is so simple you don’t need one of my quality schematics. But here you are anyway:
In this example. pressing S1 sets the voltage at pin 2 (trigger) to below 1/3Vcc, thereby setting the output to high – therefore we call S1 our ‘on’ switch. As pin 6 (threshold) is permanently connected to GND, it cannot be used to set the output to low. The only way to set the output back to low is by pressing S2 – the reset button, which we can call the ‘off’ switch. Couldn’t be easier, could it? And that output pin could switch a transistor or a relay on or off, who knows? Your only limit is your imagination. And here’s one more video clip:
And there you have it – three ways in which we can use our 555 timer ICs. But in the year 2011, why do we still use a 555? Price, simplicity, an old habit, or the fact that there are so many existing designs out there ready to use. There will be many arguments for and against continued use of the 555 – but as long as people keep learning about electronics, the 555 may still have a long and varied future ahead of it.
Well that is all we have time for in this instalment. Stay tuned for more about the 555 in the near future, including some example circuits and so on.
In the meanwhile have fun and keep checking into tronixstuff.com. Why not follow things on twitter, Google+, subscribe for email updates or RSS using the links on the right-hand column? And join our friendly Google Group – dedicated to the projects and related items on this website. Sign up – it’s free, helpful to each other – and we can all learn something.
References
[1] “The 555 Timer IC – An interview with Hans Camenzind” (Jack Ward – semiconductormuseum.com)
Various diagrams and images from the Texas Instruments NE555 data sheet.














