Introduction: Charlieplexing 7-segment Displays
I have been experimenting using the Arduino to drive a seven-segment display (SSD). When ganging several together to form a multi-digit display, a common design is to wire a matrix and use multiplexing to reduce the number of control pins. The typical formula to determine the required number of pins is one for each segment LED plus one for each SSD. Thus, a four-digit display would require twelve pins - eight segment select lines (including the decimal point LED) and four SSD select lines.
Recently, I learned of a multiplexing technique called charlieplexing. The term applies to managing a matrix of LEDs with fewer control pins than the obvious approach. Charlieplexing is most advantageous in situations where each anode and cathode can be separately connected into the matrix. Unfortunately, SSDs are manufactured with either all the segment anodes or cathodes in common. Even with this interconnect constraint, it's still possible to control SSDs with fewer than the obvious number of pins using an arrangement that timeshares the use of the segment and SSD selects. Thus, from one to eight SSDs can be controlled with only nine pins. Obviously, the more SSDs in the display, the greater the charlieplexing advantage. In this test case using four SSDs, the savings are only three pins - but that's enough for a demonstration.
I couldn't find an online example that used the inexpensive SSD available from Radio Shack and the programs accompanying the examples I did find were too large and slow for what was being accomplished. The entire Arduino was being monopolized just driving the display! Acceptable as a demo but unusable for any purpose more complicated than an expensive digital clock. I thought it should be possible to have the display as an adjunct to a sketch with a different primary purpose. I constructed this as a proof of concept and thought it might help someone else if I published it.
Charlieplexing is actually exceptionally easy to accomplish with the Arduino. This demo sketch is less than 2K and leaves plenty of processor time for my main project.
Recently, I learned of a multiplexing technique called charlieplexing. The term applies to managing a matrix of LEDs with fewer control pins than the obvious approach. Charlieplexing is most advantageous in situations where each anode and cathode can be separately connected into the matrix. Unfortunately, SSDs are manufactured with either all the segment anodes or cathodes in common. Even with this interconnect constraint, it's still possible to control SSDs with fewer than the obvious number of pins using an arrangement that timeshares the use of the segment and SSD selects. Thus, from one to eight SSDs can be controlled with only nine pins. Obviously, the more SSDs in the display, the greater the charlieplexing advantage. In this test case using four SSDs, the savings are only three pins - but that's enough for a demonstration.
I couldn't find an online example that used the inexpensive SSD available from Radio Shack and the programs accompanying the examples I did find were too large and slow for what was being accomplished. The entire Arduino was being monopolized just driving the display! Acceptable as a demo but unusable for any purpose more complicated than an expensive digital clock. I thought it should be possible to have the display as an adjunct to a sketch with a different primary purpose. I constructed this as a proof of concept and thought it might help someone else if I published it.
Charlieplexing is actually exceptionally easy to accomplish with the Arduino. This demo sketch is less than 2K and leaves plenty of processor time for my main project.
Step 1: Theory of Operation
I’ll not state here the basic information about SSDs, the segment-naming convention or the concept of ordinary SSD multiplexing and why it works; all of which can be easily found in existing resources.
Assuming an understanding of this background, here is the schematic using the pinout of the Radio Shack common cathode SSD part 276-0075. Carefully observe how the twelve SSD LED connections (eight anodes each and the four common cathodes) are connected to the nine select (Sel) lines. For example, note that the common cathode of SSD0 (the “ones” position of the four-digit display) and the anodes of segment “a” of the other three SSDs share select line Sel0.
What states do the Sel lines have to be in to cause the digit “1” to be displayed on just SSD0? Only segments “b” and “c” are to be illuminated, so Sel2 and Sel3 must be high (H) with Sel1, Sel4, Sel5, Sel6, Sel7 and Sel8 low (L). The common cathode of SSD0 is connected to Sel0, so Sel0 must also be L. Under these conditions, a "1" will indeed be displayed on SSD0.
Charlieplexing is not without complications. At this point, note that the cathodes of SSD2 and SSD3 are H because they are also connected to Sel2 and Sel3 respectively. The segment "a" LED's anodes are connected to Sel0 which is currently L. Thus, the segment "a" LEDs are reversed-biased. Although that condition does not cause them to illuminate, it's important to understand that the LEDs are subjected to (and must be rated for) the maximum possible reverse voltage. The Arduino H is +5V and that is also the maximum reverse voltage rating given for the 276-0075.
But a problem remains. Rather than being unlit, SSD1 will also display "1"! This is a conundrum. Sel1 must be L to keep segment “a” from being illuminated but, because Sel1 is also connected to the common cathode of SSD1, it must be H or both SSD0 and SSD1 will be active.
Clearly a select pin cannot be both L and H simultaneously. However, if we disconnect Sel1 we get the desired result. A disconnected line is neither H nor L – it’s in a third "open-circuit" state which causes all the attached LEDs to be off. A disconnected Sel1 supplies no current to the segment "a" anodes and also provides no return path to ground for the common cathode of SSD1. Great! So how do we disconnect pins selectively?
Here’s where the Arduino makes this easy. Each Arduino pin can be programmed as either an output or an input. As an input, it can neither source nor sink current. We’re not using the pin for its input properties; merely for the fact that an input pin is not an output pin and is therefore “disconnected” from the LED matrix. This dependence upon tristate pins is a hallmark of charlieplexing. So the programming rules are straightforward: set the select pins H for the segments to be displayed, set the remaining segment select pins as inputs and set the SSD select pin L.
Assuming an understanding of this background, here is the schematic using the pinout of the Radio Shack common cathode SSD part 276-0075. Carefully observe how the twelve SSD LED connections (eight anodes each and the four common cathodes) are connected to the nine select (Sel) lines. For example, note that the common cathode of SSD0 (the “ones” position of the four-digit display) and the anodes of segment “a” of the other three SSDs share select line Sel0.
What states do the Sel lines have to be in to cause the digit “1” to be displayed on just SSD0? Only segments “b” and “c” are to be illuminated, so Sel2 and Sel3 must be high (H) with Sel1, Sel4, Sel5, Sel6, Sel7 and Sel8 low (L). The common cathode of SSD0 is connected to Sel0, so Sel0 must also be L. Under these conditions, a "1" will indeed be displayed on SSD0.
Charlieplexing is not without complications. At this point, note that the cathodes of SSD2 and SSD3 are H because they are also connected to Sel2 and Sel3 respectively. The segment "a" LED's anodes are connected to Sel0 which is currently L. Thus, the segment "a" LEDs are reversed-biased. Although that condition does not cause them to illuminate, it's important to understand that the LEDs are subjected to (and must be rated for) the maximum possible reverse voltage. The Arduino H is +5V and that is also the maximum reverse voltage rating given for the 276-0075.
But a problem remains. Rather than being unlit, SSD1 will also display "1"! This is a conundrum. Sel1 must be L to keep segment “a” from being illuminated but, because Sel1 is also connected to the common cathode of SSD1, it must be H or both SSD0 and SSD1 will be active.
Clearly a select pin cannot be both L and H simultaneously. However, if we disconnect Sel1 we get the desired result. A disconnected line is neither H nor L – it’s in a third "open-circuit" state which causes all the attached LEDs to be off. A disconnected Sel1 supplies no current to the segment "a" anodes and also provides no return path to ground for the common cathode of SSD1. Great! So how do we disconnect pins selectively?
Here’s where the Arduino makes this easy. Each Arduino pin can be programmed as either an output or an input. As an input, it can neither source nor sink current. We’re not using the pin for its input properties; merely for the fact that an input pin is not an output pin and is therefore “disconnected” from the LED matrix. This dependence upon tristate pins is a hallmark of charlieplexing. So the programming rules are straightforward: set the select pins H for the segments to be displayed, set the remaining segment select pins as inputs and set the SSD select pin L.
Step 2: Construct the Hardware
The bill of materials from Radio Shack is short:
4 - 276-0075 7-segment LED Digital Display 1.99 ea.
1 - 276-002 6” breadboard 16.49
1 - 271-1313 5-pack 220 ohm 1/4 watt resistor 1.19
1 - 276-173 Solderless Jumper Wire Kit 6.99
And, of course, your Arduino. I used the Uno Rev. 3 but it shouldn't matter. If you have an Arduino starter kit of some sort, such as the MakerSHED “Getting Started With Arduino Kit” (available from Radio Shack), you already have all the wires and resistors you will need.
The SSD is the DIP form factor and the pinout is on the packaging. They’ll have to be arranged vertically on the specified breadboard (as shown) instead of the normal horizontal orientation; weird but not fatal - this is a proof of concept, not a product. The "ones" position (SSD0) is at the bottom. The group of rows that are attached to the Arduino are top-to-bottom Sel0 - Sel5 then Sel8, Sel7 and Sel6.
Although not shown on the schematic, the breadboard wiring shows a current-limiting resistor in series with each common cathode. Although multiple LEDs sharing a single resistor is considered bad engineering practice, the purpose is merely to protect the SSDs from mistakes during development. Once the sketch performs properly, the “on” time of each LED is so short that the forward current stays well within the maximum rating and the resistors can be replaced with wire jumpers to increase display brightness.
There's nothing special about the use of the Arduino's analog pins except they were otherwise unused by my main project. Their analog capabilities are not exploited and they're programmed as digital pins.
4 - 276-0075 7-segment LED Digital Display 1.99 ea.
1 - 276-002 6” breadboard 16.49
1 - 271-1313 5-pack 220 ohm 1/4 watt resistor 1.19
1 - 276-173 Solderless Jumper Wire Kit 6.99
And, of course, your Arduino. I used the Uno Rev. 3 but it shouldn't matter. If you have an Arduino starter kit of some sort, such as the MakerSHED “Getting Started With Arduino Kit” (available from Radio Shack), you already have all the wires and resistors you will need.
The SSD is the DIP form factor and the pinout is on the packaging. They’ll have to be arranged vertically on the specified breadboard (as shown) instead of the normal horizontal orientation; weird but not fatal - this is a proof of concept, not a product. The "ones" position (SSD0) is at the bottom. The group of rows that are attached to the Arduino are top-to-bottom Sel0 - Sel5 then Sel8, Sel7 and Sel6.
Although not shown on the schematic, the breadboard wiring shows a current-limiting resistor in series with each common cathode. Although multiple LEDs sharing a single resistor is considered bad engineering practice, the purpose is merely to protect the SSDs from mistakes during development. Once the sketch performs properly, the “on” time of each LED is so short that the forward current stays well within the maximum rating and the resistors can be replaced with wire jumpers to increase display brightness.
There's nothing special about the use of the Arduino's analog pins except they were otherwise unused by my main project. Their analog capabilities are not exploited and they're programmed as digital pins.
Step 3: Software Design
I used the Arduino 1.0.1 IDE so the sketch is an .ino file. This sketch uses TimerOne, so you will need to install that library if it's not already part of your IDE. Even if you do not actually build this project, reviewing the sketch in conjunction with the schematic should be informational. At first glance, the sketch may look imposing, but there are actually more comment lines than functional statements. The idea is that by reading the comments, not only will you understand how the program operates, but that you will be exposed to some techniques that might be applicable to your future sketches.
The fact that there are eight anodes in the SSD and eight bits in a byte was too obvious to ignore, so the entire design is informed by this association. Using an interrupt was required to allow the Arduino to be doing something else between SSD refreshes. This means that all of the select pin decisions occur in the timer's Interrupt Service Routine function. ISRs have to be as efficient as possible so as to take a minimal amount of time to execute. If the ISR execution time is not substantially shorter than the timer period, little progress will be made executing the statements in the loop() function. You will see comments in the ISR function about avoiding time-consuming jumps (e.g. “if” statements) wherever possible. Realize that only one SSD is serviced during each interrupt and it’s active from the end of the ISR until the next timer tick.
Part of the hardware design was made with the programming in mind. For example, there’s no hardware reason to choose one select line in favor of another to connect to a particular SSD's common cathode. However, it's a simplification that the first four select lines, the SSD common cathodes and the first three segments have positionally-interdependent relationships.
The resulting ISR is small and fast enough without resorting to using the port registers. The programming would have been a lot more complicated and inefficient if it was required to accommodate an arbitrary wiring design. So when thinking about your projects, pay attention to the symbiosis between hardware and software and look for appropriate trade-offs.
Charlieplexing is a great technique to have in your bag of tricks.
The fact that there are eight anodes in the SSD and eight bits in a byte was too obvious to ignore, so the entire design is informed by this association. Using an interrupt was required to allow the Arduino to be doing something else between SSD refreshes. This means that all of the select pin decisions occur in the timer's Interrupt Service Routine function. ISRs have to be as efficient as possible so as to take a minimal amount of time to execute. If the ISR execution time is not substantially shorter than the timer period, little progress will be made executing the statements in the loop() function. You will see comments in the ISR function about avoiding time-consuming jumps (e.g. “if” statements) wherever possible. Realize that only one SSD is serviced during each interrupt and it’s active from the end of the ISR until the next timer tick.
Part of the hardware design was made with the programming in mind. For example, there’s no hardware reason to choose one select line in favor of another to connect to a particular SSD's common cathode. However, it's a simplification that the first four select lines, the SSD common cathodes and the first three segments have positionally-interdependent relationships.
The resulting ISR is small and fast enough without resorting to using the port registers. The programming would have been a lot more complicated and inefficient if it was required to accommodate an arbitrary wiring design. So when thinking about your projects, pay attention to the symbiosis between hardware and software and look for appropriate trade-offs.
Charlieplexing is a great technique to have in your bag of tricks.