Subscribe to Make Magazine Today!

Charlieplexing is an ingenius method for controlling many LEDs without using many microcontroller pins. You can turn on or off one LED at a time. To light more than one LED at a time, you can scan the LEDs by turning a sequence of them on and off really fast. The number of LEDs you can control is determined by this formula: N pins * (N pins – 1). For example, if you have 4 pins, you can control 12 LEDs (4 pins * 3 pins). If you have 2 pins, you can control two LEDs, which makes it a little silly to employ Charlieplexing, since you could simply connect each LED to an MCU pin and then to ground. Charlieplexing makes more sense for more than two LEDs. Nine pins will get you 72 LEDs!

Here is an ATmega328 on a custom PCB controlling 20 LEDs (the 21st is on its own pins) with just 5 pins:

Charlieplexing takes advantage of the fact that LEDs are diodes: Current flows in only one direction through an LED. Connect two LEDs in parallel with each but with opposite polarity so that only one conducts (lights up) at a time and that is the basis of Charlieplexing.

The ATmega328 pins can source upwards of 40 mA. The grand total of current from Vcc to GND in an ATmega328, however, is capped at 200 mA. Keep that in mind when pumping electrons through your Arduino or ATmega328. In this project, we’ll only ever have a single LED turned on at a time, so no more than roughly 20 mA will be running through the microcontroller’s pins at any time (not including what the MCU takes itself, of course).

In this project, we’ll set up a simple Charlieplexing circuit with 12 LEDs controlled by an Arduino that will look like this:

I’ll walk you through connecting 12 LEDs to four pins on your Arduino. The Arduino sketch will make the LEDs “chase” in a circle(ish). The breadboard set up for this gets nuttier and nuttier the more LEDs and pins you add. I’m going to stop at four pins, mostly because the breadboard starts to look crazy and four pins will get you going on your own quite easily.

I wrote the Arduino code to make it easy to add or remove LEDs. There is a simple function to call to turn on any given LED. You can nab the Arduino code for this project right here:

On a side note, the Arduino digitalWrite() and maybe even the pinMode() calls are heavyweights compared to the standard AVR C register macros for directly manipulating bits in the DDRx and PORTx registers of the ATmega328 (or any AVR chip, for that matter). The Arduino calls gobble up a quite a lot of clock cycles when you call them, whereas the DDRx and PORTx macros translate to one or maybe two assembly instructions (WAY faster). When it comes to scanning over the LEDs rapidly to make more than one at a time appear to be on, the fewer clock cycles in between each LED during each refresh (or, “frame” of animation), the brighter and less flickery the LEDs will appear to be. The optimum way to scan these LEDs, especially when there are many of them, is to use direct register manipulation calls, NOT digitalWrite() or pinMode(). There is a great replacement for the Arduino calls out on Google Code that provides digitalWriteFast() and others to help speed up those common calls. Here is a link to the Google Code page for that library.

On a side note to the above side note… Here is a gist showing code that directly manipulates the DDRx and PORTx registers to save on cycles when switching between LEDs:

This project will assume you know how a breadboard works, how to calculate the proper current limiting resistance for an LED running on 5 volts and what the cathode (ground/negative) and anode (positive) leads are on your LEDs.

StuffAndyMakes.com

StuffAndyMakes.com

25-year IT veteran by day, maker by night and weekend. Love little fiddly electronic bits and making useful AND useless things for fun and relaxation.


  • SkipF

    Can you use Common Anode or Common Cathode RGB LEDs?

    • http://StuffAndyMakes.com StuffAndyMakes.com

      I don’t see why Common [Anode|Cathode] RGB LEDs would not work. The trick there is that three LEDs would all go to the same INPUT pin for Common Cathode or to the same OUTPUT pin for Common Anode. But it’s really no different than what I describe above. Maybe a bit nuttier for keeping track of what LEDs go where, but no different. Two RGB LEDs opposite each other seems like a neat trick to me. Using PWM on them would be a bit more complex, if you’re looking to mix colors, but it should be possible.

      Just remember that switching between LEDs in your code, even if you bypass the Arduino digitalWrite() and pinMode() functions is kinda cycle-consuming, that is, pinging each LED in a large group of LEDs eats time away from the time any given LED is turned on. The LEDs will almost always appear dimmer than you would expect because there is housekeeping that has to go on between turning on LEDs. It’s a drawback to the method unless you’re using a swanky Charlieplexing IC like the ones from Maxim.

  • Matt

    This works great until I go to use 6 outputs. I can get A-E to work but not F. I added pinmode and digitalWrite for E and F but the ones on F do not light up. Says pinmode and digitalwrite for F is not correct but I dont know how to fix it any help would be great.

    • http://gravatar.com/stuffandymakesdotcom StuffAndyMakes.com

      Not sure what the problem is without seeing code or the physical wiring you’ve set up. While this method can scale, as you approach 6 or more pins it gets REALLY hairy. I’ve learned that a diagram like I use in the article is super helpful in keeping track of all of the pins and LED orientations. If my math is serving me correctly, you’re talking about 30 LEDs. That’s a lot of double-checking. At that level, in my experience experimenting with this method, making certain you have all the right combinations of LEDs in the proper directions is difficult and tedious at best. Wiring all that on a breadboard is messy and difficult to troubleshoot. Try posting some code and pictures if you haven’t figured it out, yet.

      • tushjambhekar

        biggest problem with charlieplexing is that it gets complicated exponentially with increasing channels. Instead I think it is better to have extra microcontrollers to do the job. also IOTrain makes it very simple(http://bit.ly/1dXDAFv). with IOTrain accessing outputs is as simple as arduino’s digitalWrite.

  • tchatow

    Where is the download link for the code?

  • Bratan

    Where’s the code??? :(