Multiplexing seven segment displays on an Arduino

I’ve made a few projects that use 7 segment displays with methods involving both using a chain of shift registers and multiplexing using the sevenseg library. In my most recent project I’d used 4x shift registers to drive 4 displays which worked well but was a pain to connect up and needlessly complicated. I have used multiplexed methods before but for only 2 or 3 digits but in my recent project that uses 5 digits the display became unacceptably dim.

This is down to how the displays are scanned – in the one shift register per digit method the data is sent to the registers and the latch enabled. 220 ohm resistors were used giving a current for each segment of around 16mA for the LED modules I’d used. For multiplexing only one shift register is used and the digits turned on and off again in sequence but done so fast the eye does not notice. This is a simpler solution and cuts down on components but it does have some things to bear in mind.

I noticed whilst looking on the internet hobbyists are having problems with dim displays and / or blown LED modules. I also noticed a lot of example schematics with LED modules directly connected to an Arduino with no current limiting resistors whatsoever. Whilst this may work well in some cases (more on this later) it’s a bad idea.

Let me explain…

Basically first of all to normally calculate a current limiting resistor for an LED be it a standalone LED or a segment of a 7 segment display you would go by the DC current through the LED which for modern LED’s is typically 8-10mA with an absolute maximum of 20mA. With a 220 ohm resistor and an LED with 2V forward voltage this would give you 13.6mA through your LED. With multiplexing on a 4 digit display however that 13.6mA would be divided by 4 as only one LED module is on for 25% of the time which results in a dimmer than expected display. Increasing the multiplexing frequency can help with the brightness but this can damage the Arduino. However if you get that average current through the display low enough it won’t burn anything out but unless you have an LED that is bright enough at 3mA max it won’t be good enough.

Take for example the excellent sevenseg library which comes with a comprehensive instruction manual. The library is designed to drive a number of 7 segment displays directly connected to the Arduino via current limiting resistors. There’s a good section describing why the display gets dimmer as more digits are used. Basically the 13.6mA of current for a single digit is shared amongst the total number of digits giving an average current of 3.4mA. Now this probably won’t be enough for a display requiring 10mA.

Now why this is a bad idea is that with a directly driven display showing the number 8 13.6mA X7 = 95.2mA would flow through the common anode or common cathode pin. Now I’ve seen lots of schematic examples showing a single LED display with no resistors. Even with 220 ohm resistors that 95.2mA would destroy the pin the common anode or cathode is connected to. Please don’t do this! Even with 1K resistors giving 3mA per segment would put 42mA through that Arduino pin…

Multiplexing is the answer here BUT as I mentioned above you would end up with a dim display in most cases. The proper solution is to use a transistor on the digit pins to sink / source the total current of the segments through it rather than the Arduino. Simple if you are using a single non multiplexed LED. However for a 4 digit display you need to calculate the resistor value for the required current several times higher than required than it would be for a single digit. In other words those 220 ohm resistors needs to be around 56 ohms. This will give an average current of around 13mA per segment with a refresh rate of 100hz and duty cycle of 100%. You would absolutely need to use transistors on the digit pins. The caveat here is that the required current (13mA x 4 digits) should not be higher than the Arduino pin can sink / source so in reality without using a driver chip 100 ohm resistors should be used for the segment pins and transistors on the digit pins. This will give an average current of around 7.5mA per segment which should be bright enough for a modern LED display.

For 6 digits or more you should use an IC such as the ULN2803 or UDN2982 (sink / source respectively) between the Arduino and the segment pins & transistors (or transistor array IC) on the digit pins. This requires modification of the sevenseg library as below.

In my example I’m using PNP transistors on the common anode digit pins and have the cathodes connected to the Arduino via 47 ohm resistors. I’m using a 5 digit display and chose to not use a sink driver on the segment pins as the current is low enough to be handled by the Arduino pins.

I changed:-

void SevenSeg::setCommonAnode(){
_digOn=HIGH;
_digOff=LOW;
_segOn=LOW;
_segOff=HIGH;

to

void SevenSeg::setCommonAnode(){
_digOn=LOW;
_digOff=HIGH;
_segOn=LOW;
_segOff=HIGH;

This is because PNP transistors invert the logic i.e logic low turns the transistor on and a logic high turns it off. By default the LED would be connected to the Arduino directly. To light a segment you set the common anode high and the segment low. If using a PNP transistor you need to set both the segment and digit pins low. The 5V would be sourced by the transistor instead. For common cathode displays you would need to make both digit and segment pins high in the common cathode function & use NPN transistors.

This is a much better and safer way of connecting LED’s for a permanent project. Instead of using transistors you could use a darlington array such as the ULN2803 for larger numbers of digits. Whilst the sevenseg library will work as-is for small number of digits (say 3 maximum) and the use of low current high brightness displays it isn’t good enough for larger numbers of digits that need more current.

One other thing to be aware of is that during development you should use temporary resistors the same value as they would for a single digit e.g 220 ohms. This is because if you hit a breakpoint or your program stops working the multiplexing stops and if any segments are lit they will burn out. Once the program is verified to be working go ahead and use resistors of a smaller value to get acceptable brightness.

In the final example it is common practice for multiplexed displays to be pulsed on and off at a current rating much higher than the DC rating. For example I have a 7 LED module that has an absolute maximum DC current of 25mA but yet can handle 140mA at 1/10 duty cycle. For this to work with the sevenseg library you would set the refresh rate to 1000hz and the duty cycle to 1/10 BUT you would need to use a digit and segment driver & choose resistors that can give you that higher current. With a 5V system you are looking at resistors of 22 ohms to give 136mA. The Arduino is rated at 40mA absolute maximum per pin with 20mA recommended max current…

So to sum up don’t always trust those schematics found on the web. You do need current limiting resistors in all cases to prevent damaging your Arduino. Pay attention to datasheets for your LED modules and the current ratings. In a single digit application with no current limiting resistor at all it would damage the arduino. The only case where this could work is kind of like multiplexing; you would simply pulse the display on and off (called duty cycle) but again it would have to be very low and would likely flicker. I wouldn’t recommend this and just use current limiting resistors.