Multiplexing
Multiplexing is a very common way of
driving LEDs, particularly when they are assembled as either a dot matrix
display or a number of seven-segment/numeric displays. Multiplexing relies on
the fact that if a light source is switched on and off fast enough, the human
eye perceives it as being continuously lit even though it is in fact only on
for a brief period.
Figure 16-2 shows a two-digit seven-segment display connected to an Arduino.
Note that the seven segments are connected directly to the Arduino output pins
and the “common cathode” of the display (all the LED cathodes) are connected
through a transistor to ground. These bases of the transistors are, in turn,
connected to an output pin on the Arduino.
In order to display two different numbers on each display, we use a procedure
much like the following:
repeat {
Set Outputs 3 to 9 as required for first digit;
Turn Output 1 On;
Delay;
Turn Output 1 Off;
Set Outputs 3 to 9 as required for second digit;
Turn Output 2 On;
Delay;
Turn Output 2 Off;
}
If we repeat this rapidly enough, our eye will perceive both displays as being
continually lit showing the digits we want. The general idea can, of course, be
expanded to more digits—four or six for a clock, for example, and this is
precisely how most LED clocks work.
Multiplexing doesn’t come entirely free. Because the LEDs aren’t on all the
time, they appear dimmer. In our example, the duty cycle (ratio of “on” time to
“off” time) for each display is 50%. For a four-digit display, it would be 25%,
and so on.
To get around this, we can increase the current being sent to each display,
this being where the peak current rating of the display becomes important. For
a typical seven-segment display, it’s likely to be acceptable to increase the
current to 50mA per segment. Higher than that, start checking datasheets and
doing some calculations to ensure you don’t overstress the devices. By driving
the LEDs with a higher peak current, they output more LED for the time they are
on so they appear brighter. They also have time to cool during the off time,
hence avoiding damage.
There is a caveat with driving LEDs at their peak, rather than constant,
current rating: it’s very important that your software doesn’t inadvertently
leave them on too long, or the device can be damaged. This can be problematic
during development/debugging if your code crashes with the LEDs in an on state.
It is prudent to do initial coding with the LED or display run with resistors
chosen to keep it at its constant current rating.
The next issue with multiplexing is that, of course, the ATMega must update the
state of the LED or display at regular intervals. This reduces the amount of
processor time available for other tasks. With careful design, the impact of
this can be minimized, but should be taken into account. Consider using a
periodic interrupt to do the display updates.
Charlieplexing
Charlieplexing is a technique
that can be used to maximize the number of LEDs or switches that a
microcontroller can address with a limited number of pins. It makes use of the
fact that a modern microcontroller (ATMega/Arduino obviously included) can
actually set its pins to one of three states: High, Low, or Input (“Hi-Z” as it
is sometimes called). We’ll confine our remarks here to driving LEDs. The
Practical Arduino web site has links for references on this topic, if you wish
to read up on more exotic setups, as well as links to the original articles on
the topic.
Figure 16-3 shows two LEDs connected between a pair of Arduino output pins
through a dropping resistor. Note that the LEDs are connected with opposite
polarity. Two pins to drive two LEDs is hardly remarkable, but bear with us a
moment and we’ll illustrate the basic principle.
To turn LED1
on, we would make Output1 High, and Output2 Low. For LED2 we’d do the opposite:
Output1 Low and Output2 High. To turn the LEDs off, we can either set the pins
to be inputs or the outputs to be the same state (both Low or both High)
Figure 16-4 shows a more interesting arrangement. Here we drive six LEDs from
just three pins by making use of the Arduino’s ability to set a pin to be an
input or an output in a high or low state.
Referring to the diagram, to turn LED1 on, we’d set DIO1 to be an output and to
be high, DIO2 to be an output and low, and DIO3 to be an input. LED2 would be
turned on by DIO1 being an output and set low, DIO2 being an output and set
high, DIO3 still being an input. Jumping around, LED4 you’d set DIO1 to be an
input, DIO2 to be low, and DIO3 to be high. LED6 would call for DIO1 to be low,
DIO2 to be an input, and DIO3 to be high, and so on. A bit of thought and careful
programming will allow you to create a general-case piece of code that can turn
on any LED required.
You’d be
correct to wonder why when LED6 is on, LED1 and LED3 aren’t. They’re connected
between the same pins, after all, and with the correct polarity. The answer
here is the forward voltage drop—there isn’t a high enough voltage across the
two LEDs when connected in series to allow them to light because it’s below the
threshold or Vf level.
If, as is often the case, you want to have more than one LED on at a time, you
can use a multiplexing arrangement, switching to each LED in turn in rapid
succession. Avoid the temptation to simply skip an LED that is off. If you do
so, then the brightness of any LED that is on will change depending on how many
LEDs are on at any one time. Of course, if the number of LEDs that are on is
constant—as would be the case for hands on a clock, say—that would be
acceptable. LEDs that are off can be skipped completely in such a case. As
noted in the previously, you’ll need to consider running the LEDs at higher
currents to keep the brightness up, and the same caveats about duty cycle come
into play.
Finally, note that the current-limiting resistors are half the value you’d
normally expect to use. This because the LED being driven is always being
powered by the Arduino through two pins and, hence, two dropping resistors.
If you’re curious, the general case for the number of LEDs that you can drive
from n pins is n2 – n. For example, eight DIOs yield 56 LEDs; 12 DIOs yield 132
LEDs; and so on. That’s a lotta LEDs!