The LEDactus is my version of a dry climate niche dweller like a cactus. LEDactus is immobile and attempts to survive by creating a pleasant display. This is of course in the hopes that passersby will be so entranced that they will build the LEDactus' progeny.
Initial generations create a simple but pleasing display. Later generations attempt to produce more complex and mesmerizing displays. Finally, in the latest generations, a sense of touch is added to allow the LEDactus to interact with passersby.
In LEDactus I wanted to control a significant number of LEDs. Conventional wisdom says that it requires one I/O line to control one LED. Since the 18F1320 has only 16 I/O lines this could seriously cramp an inventor's style. The figure below illustrates the standard approach to controlling an LED. In the first case a logic 1 on B0 turns the LED on, and a logic 0 turns it off. The second figure inverts the logic so that a logic 1 on B0 turns off the LED and a logic 0 turns it on. This schematic assumes that, like the 18F1320, the I/O pins are current limited to a value that won't destroy the LED. If not, you'll need to insert a series current limiting resistor.
Fortunately a clever fellow called Charlie Allen, an engineer at Maxim, thought of a way to control more LEDs with the same number of I/O lines. When an I/O line is configured as an output it sources or sinks current. Since microcontroller I/O lines can be reprogrammed to function as inputs, this adds a third state. This third state is like disconnecting the I/O port from the LED.
In practice, if you have N I/O pins to work with, you can control N x (N-1) LEDs. So a standard 8 bit port could control (8x7) 56 LEDs. With 16 I/O pins you could control (16x15) 240 LEDs.
The method controls LEDs in banks of N-1. Any LEDs in the active bank can be turned on independently. To turn on LEDs in another bank, the first bank is turned off. This means that LEDs are never full on. The fraction of time the LEDs are on, or duty cycle, is (1 / Number of Banks Used). Fortunately, an LED's brightness does not drop linearly with the duty cycle. Even at 50% duty cycle (half on-half off) the LEDs retain nearly 80% of their perceived brightness.
How Charlieplexing Works
The following diagram illustrates how charlieplexing works with 3 I/O ports.
In this example, I/O ports B0, B1 and B2 are used as bank select lines. We select a bank by setting one of these I/O lines as an output and setting it low (0).
If, for example, we set B0 to low, we use B1 and B2 to control LEDs 1 and 2. If we set either or both of B1 and B2 to high (1), the corresponding LEDs turn on. To turn off the LEDs we cannot however set B1 or B2 to low. This is the bank select condition and might cause LEDs in other banks to turn on as well. Instead, to turn off an LED in a bank we reprogram the controlling I/O line to be an input.
LEDactus uses 3 banks of 7 LEDs. The circuit could be expanded to control 56 LEDs if I wanted but 21 seemed sufficient for now.
Below you can see the PCB pattern and parts layout that you can use to make your own LEDactus. The full size pattern omits showing the parts so you can create your own PCB.
Hover over the image above and use "Save Link As" (Firefox) or "Save Target As" (MSIE) to save the full size PCB layout to your computer.
Next Section: LEDactus - First Code