### Drive the multiplexed 4 digit 7-segment display

How to identify pins and drive 4 digit multiplexed 7 segment displays with Arduino development boards

Seven segment displays are widely used in clocks, meters and other devices that need to display numerical information. The elements of the display, which are usually made from LEDs, are lit in different combinations to represent Arabic numerals. They have a limited ability to display some characters because there are only 7 elements that compose the shape of the displayed figure. Seven segment displays are very easy to find and are the cheapest display type.

In the previous post I talked about the electrical connections of such displays and how they should be interfaced to a microcontroller (MCU). A 7-segment display requires current limiting resistors on each segment and transistor drivers for each digit. This time I will identify the pins of an unmarked display device, I will wire it on the breadboard to an Arduino Nano compatible board and I’ll attempt to write the software to drive it.

I got a display with 12 pins in a row. Most of what I’ve seen had 2 rows of 6 pins. Here is what you should do to identify pins. You need to know the segments. Get yourself a 5V supply and add a series resistor of 330 ohms on the supply line.

Testing the segments of the display

Nothing bad happens if you short the probes. Put one of the probes on a side pin. Touch each of the remaining pins with the other probe, one at a time (we’ll call the probe that you hold on a pin fixed probe while you test the remaining pins with the moving probe). No segment may turn on. Reverse probes. If no segment turns on, there’s something wrong with the display. When segments turn on, you will notice a pattern.

Placing the moving probe to various pins lights the same segment, but on different digits. This means the pin where you hold the fixed probe is the lit segment signal (A to G or P). The moving probe was on digit pins (D1 to D4) when the segment turned on. If moving probe is ground, the display is common cathode. Otherwise is common anode. Move the fixed probe to the next pin and test the others until you identify them.

The other pattern is when different segments of the same digit light when touching different pins with the moving probe. In this case, the fixed probe was on a digit pin (D1 to D4). Go ahead and take note of each segment pin. What’s left are the rest of common digit pins. If fixed probe is ground, the display is common cathode. Otherwise is common anode.

I found my display was common anode, therefore I had to use PNP driving transistors. It has no decimal point. However it had two points after first two digits, like clock displays do. The top point is wired to digit 2, while the bottom one to digit 3. Now that I know pinout, I wired everything according to my previous post (with 8 current limiting resistors for segments, 4 x 2N3906 driver transistors and 4 resistors for limiting transistor base current).

The pinout of my 7-segment display

The code is rather simple. You drive a digit pin active and set the segments. The 4 digits are activated sequentially one at a time. From what I have seen, if you cycle through them with at least 200 Hz, it appears as if all of them are active. I fact, a single digit stays on a quarter of the time.

For digit 5, the Arduino way of setting segments is (required pins are previously set as outputs):

digitalWrite(SEG_A, LED_ON);
digitalWrite(SEG_B, LED_OFF);
digitalWrite(SEG_C, LED_ON);
digitalWrite(SEG_D, LED_ON);
digitalWrite(SEG_E, LED_OFF);
digitalWrite(SEG_F, LED_ON);
digitalWrite(SEG_G, LED_ON);


It may be simple, but there is something even better: direct port writing. However, things get complicated because Arduino doesn’t expose a complete 8 bit port for general I/O. Digital pins D2 to D7 are from PORTD [2..7], but PORTD 0 and 1 pins are serial port pins. Digital pins D8 to D13 are from PORTB [0..5]. PORTC is the port with analog pins. If you are using an Arduino Pro (Mini) without USB-Serial adapter and if you don’t need serial port in your project, go ahead and use PORTD. Otherwise it isn’t the right way to set RXD (PORTD0) as output when it is connected to USB-Serial converter TX pin (output). Direct port writing simplifies code a lot. You assign a 8-bit number to every digit and pass it to output port register (encodings can be found on Wikipedia). An example could look like this:

PORTD = 0x6D;

This single line of code would do the same as the above 7 lines of code. If you’re using a different development board on which you have access to a full 8-bit port, then this is the way to go. It is also possible to drive the segments with a 74HC595 serial in – parallel out shift register. Instead of 7 pins needed to drive the each segment, you development board would only need 3 to send data to 74HC595.

There is also another method to simplify code while using Arduino API. Assuming you connect segments to succeeding pins (for example segment A to pin 2, segment B to pin 3, segment C to pin 4 and so on), you could use digitalWrite in for() loops. Then you can define segment encodings as bytes and display a digit by reading bits of an encoding byte. Here is an example:

byte digits[10] = {0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07, 0x7F, 0x6F};
for (byte i = 0; i < 7; i++)
digitalWrite(SEG_A + i, bitRead(digits[digit], i) ? LED_ON : LED_OFF);


The 7-Segment libraries I could find in Arduino IDE didn’t seem to work for me. So I wrote my own code without library. I wired everything on the breadboard and added a trimmer potentiometer on A0 pin. My display is common anode, so I had to use PNP transistors (2N3906). With the potentiometer I adjust digit update frequency from 1 to about 250 ms. The result can be seen in this video. The sketch for this breadboard example is 7segment_arduino_with_potentiometer and a better sketch, which uses AVR Timer 2 to update digit display every 4.8ms: 7segment_arduino_with_timer. Using a timer is a good way to deal with this situation because you can do whatever you want in loop(). The version which uses for loops when segments are connected to ascending pin numbers is 7segment_arduino_ordered_pins.

In the end, I got the best results with 7segment_arduino_with_potentiometer sketch. I was able to reduce segment "bleeding" to a minimum, by first turning off the 3 unused digits, then setting segments (the longest operation) and in the end turning on that digit. This is the sketch I recommend as a starting point for a project where you'll be using a 7-segment display.