# How can I control many LED's with just a few pins on my micro?

I am using an Atmel ATTINY13 which has a 6-pin I/O. I'd like to control about 15 LED's but am unsure how to connect everything. Without multiplexing of any sort, it seems I'd only be able to control 6 LED's at a time. Am I limited to only 6 LED's because of the size of the microcontroller?

-
I had not seen. Possibly duplicated: electronics.stackexchange.com/questions/9860/… –  Daniel Grillo Mar 4 '11 at 19:36
Don't forget to compare your options against the cost of buying a slightly pinnier microcontroller. Also pay attention to the per-port and total current limits. –  joeforker Mar 4 '11 at 20:39
When I began working with micros a while ago, this is a question I wished had been easy to find with clear answers. I managed to learn about charlieplexing and successfully implement it, but I wanted to recreate the question here with the excellent quality of SE-community answers. –  JYelton Mar 4 '11 at 21:47
@joeforker You're right, the cost for a micro with more pins was pretty minimal, considering my project was a one-off. I thought at one point about using a micro with about 20 IO pins to accomplish the job, but one of my goals was a very small circuitboard footprint. Also, awesome adjective pinnier! –  JYelton Mar 4 '11 at 21:54
–  mjh2007 Mar 10 '11 at 21:01
show 1 more comment

There are several methods which can be used to drive large numbers of LEDs from a few IO pins.

The simplest is standard row/column display multiplexing. With this technique, you can drive $( n / 2 )^2$ LEDs with $n$ IO pins. Mathematically, the duty cycle is $1 / minimum(\text{unique row patterns, unique column patterns})$. This means that this technique has a duty cycle of 100% when all LEDs are lit (or all rows or all columns are identical) and a duty cycle of $1 / n$ when a diagonal line needs to be lit (or all the rows are different). You're only guaranteed 100% duty cycle when lighting every LED or one LED (or zero LEDs, but that doesn't really count for much).

Slightly more complex is Charlieplexing. With this technique, you can drive $n^2 - n$ LEDs with $n$ IO pins. Only $n - 1$ LEDs can be lit simultaneously with this technique. Mathematically, the duty cycle is $1/ (\text{minimum simultaneous sets})$, where a simultaneous set is a unique group of LEDs which has a common anode or common cathode. (This hasn't been proven, it's just what I arrived at after pondering the problem for a minute. If duty cycle is important to you, you'll want to look into this further.) This is a much more complex calculation both intellectually and computationally than the equivalent calculation for standard multiplexing. Effectively, you get a duty cycle of $1 / n$ when all LEDs are lit but some (only some) patterns of n-1 or fewer LEDs can have a duty cycle of 100%. You're only guaranteed 100% duty cycle when lighting 1 LED.

The last method I'll mention is to use a shift register or IO expander. With two pins (Either the raw data/clock interface, I2C, or unidirectional SPI), you can control an arbitrarily large number of LEDs. The duty cycle for any pattern is 100%, but the update rate is inversely proportional to the number of LEDs. This is the most costly method. For 15 LEDs, it will probably be cheaper to just upgrade to a micro with that many IO pins.

-
+1 for explaining a bit about the duty cycle aspect. In the second sentence about Charlieplexing, did you mean "drive n^2-n LED's with n IO pins? –  JYelton Mar 4 '11 at 21:52
Charlieplexing can be done very similarly to multiplexing, if one simply omits one light from each row. Actually, it may be possible to "regain" that light by adding a diode, though unless column drivers are constant-current outputs, making it match the brightness of the others may be difficult. –  supercat Mar 18 '11 at 15:40

Use Charlieplexing, you can directly drive n*(n-1) LEDs from n pins

Exemple:

Six LED's on 3 Pins

PINS        LEDS
0 1 2   1 2 3 4 5 6
0 0 0   0 0 0 0 0 0
0 1 Z   1 0 0 0 0 0
1 0 Z   0 1 0 0 0 0
Z 0 1   0 0 1 0 0 0
Z 1 0   0 0 0 1 0 0
0 Z 1   0 0 0 0 1 0
1 Z 0   0 0 0 0 0 1
0 0 1   0 0 1 0 1 0
0 1 0   1 0 0 1 0 0
0 1 1   1 0 0 0 1 0
1 0 0   0 1 0 0 0 1
1 0 1   0 1 1 0 0 0
1 1 0   0 0 0 1 0 1
1 1 1   0 0 0 0 0 0


-
Thank you for the output pin dataset as well as a helpful schematic. –  JYelton Mar 5 '11 at 2:15
Another way of drawing the schematic is as an NxN grid, but driving columns only, and replacing the primary diagonal with row-column shorts. –  supercat Mar 8 '11 at 16:10

Without multiplexing (direct drive) you are limited to 6 LEDs.

With charlieplexing you can drive n*(n-1) LEDs from n pins.

With I/O expanders or shift registers you can drive a virtually unlimited number of LEDs.
Example: MCP23008 8-bit I2C I/O Expander

-
Can you elaborate on what I/O expanders would be? –  JYelton Mar 4 '11 at 19:26
An I/O expander is external chip that contains I/O pins and registers. You can use standard communication bus like I2C or SPI to communicate with them. –  mjh2007 Mar 4 '11 at 19:32
+1 You can drive a lot of LEDs with TI's TLC594 (focus.ti.com/lit/ds/symlink/tlc5940.pdf), but it may be overkill for many jobs. search.digikey.com/scripts/DkSearch/… –  kenny Mar 4 '11 at 21:15
Thanks - I should design a project that makes use of I/O expanders to force my learning of their usage. –  JYelton Mar 4 '11 at 21:48

As @mjh2007 suggested with an I2C expander. But there are ones specifically for driving LEDs which will avoid the need for external current-limiting resistors.

-

Here's an example of charlieplexing that I have built.

It's a lighthouse beam simulator and uses a series of 12 LEDs charlieplexed to 4 GPIOs to sweep a beam of light around a disc. There's a video of it here.

The project is PIC based, I use a PIC12f683 which is also an 8pin uP and could be considered comparable to the 8pin AVRs.

The LED's intensity is driven by an interupt that provides a 32 step PWM at around 60Hz. Only two LEDs are allowed to be lit at any one time giving a 50% duty for each LED as that was all I needed. It also gives a good trade off of PWM refresh rate against resolution.

The coding for using charlieplexing as actually pretty simple if you stick to the "classic" method of only lighting a single LED at any one point in time at a very fast refresh rate. I work out the required PORT and TRIS (pic specific registers) first on paper then store the results in a static array. To light LED x the PIC just has to lookup the value at the array's index[x] and write them directly to the PORT (with a bit of masking to preserve the state of the other pins not used in the charliplex)

My project only has 12 LED not 15 or the maximum 20 the 5 GPIO will allow as I wanted to keep one GPIO spare for future development.

Anyway... I just thought it might be helpfull to have a working example similar to your request.

-