Introduction: Charlieplexing LEDs- the Theory

This instructable is less a build you're own project and more a description of the theory of charlieplexing. It's suitable for people with the basics of electronics, but not complete beginners. I've written it in response to the many questions I've gotten in my previously published Instructables.

What is 'Charlieplexing'? It is driving lots of LEDs with only a few pins. In case you're wondering Charlieplexing is named after Charles Allen at Maxim who developed the technique.

This can be useful for lots of things. You may need to display status information on a small microcontroller, but only have a few pins spare. You may want to show a fancy dot matrix or clock display but don't want to use lots of components.

Some other projects demonstrating charlieplexing you may want to look at are:
How to drive a lot of LEDs from a few microcontroller pins.
by Westfw :- https://www.instructables.com/id/ED0NCY0UVWEP287ISO/
And a couple of my own projects,
The Microdot watch:- https://www.instructables.com/id/EWM2OIT78OERWHR38Z/
The Minidot 2 clock:- https://www.instructables.com/id/E11GKKELKAEZ7BFZAK/
Another cool example of the use of charlieplexing is at:
http://www.jsdesign.co.uk/charlie/

The Minidot 2 clock introduces an advanced charlieplexing scheme for fading/dimming which won't be discussed here.

UPDATE 19 August 2008 : I've added a zip file with a circuit that may be able to exploit the matrix charliplexing for high power LEDs discussed (at length :) ) in the comments section. It has a pushbutton + position encoder to do a user interface, plus circuitry for either USB or RS232 computer control. Each of the high side voltage rails can be set to one of two voltages, say 2.2V for RED LEDs and 3.4V for green/blue/white. The voltage for the high side rails can be set by trimpot. I'd envisage that a 20wire IDC ribbon cable be plugged into the board, and 20pin IDC connectors added along the length of the ribbon, each LED board having links to whatever wires in the matrix are desired. The circuit is in Eagle Cad and rendered in the sub image below. The high side circuit is implemented by using optocouplers which I think might be suitable.

I haven't actually tested this circuit nor written any software because of lack of time, but have put it up for comment, I'm particularly interested in the optocoupler implementation. Anyone brave enough to give it a go...please post your results.

UPDATE 27th August 2008: For those not using EagleCad....added below is a pdf of the schematic

Step 1: Some LED Theory

Charlieplexing relies on a number of useful aspects of LEDs and modern microcontrollers.

Firstly what happens when you connect an LED to electricity.

The main diagram below shows what is called the If v Vf curve of a typical 5mm low power LED.
If stands for 'forward current'
Vf stands for 'forward voltage'
The vertical axis in otherwords shows the current that will flow through an LED if you put the horizontal axis voltage across it's terminals. It works the other way around as well, if you measure that the current is of some value, you can look across to the horizontal axis and see the voltage the LED will present across it's terminals.
The second diagram shows a schematic representation of an LED with If and Vf labelled.

From the main diagram I've also labelled areas of the graph that are of interest.
- The first area is where the LED is 'off'. More accurately the LED is emitting light so dimly you won't be able to see it unless you had some sort of super-duper image intensifier.
- The second area has the LED just slightly emitting a dim glow.
- The third area is where an LED is usually operated and is emitting light at the manufacturers rating.
- The forth area is where an LED is operated beyond it's operating limits, is probably glowing very brightly but alas for only a short time before the magic smoke inside escapes and it won't operate again......ie in this area it burns out because too much current flows through it.

Note that the If/Vf curve or operating curve of the LED is a 'non-linear' curve. That is, it is not a straight line...it has a bend or kink in it.

Lastly this diagram is for a typical 5mm red LED designed to operate at 20mA. Different LEDs from different manufacturers have different operating curves. For example in this diagram at 20mA the forward voltage of the LED will be approximately 1.9V. For a blue 5mm LED at 20mA the forward voltage might be 3.4V. For a high power white luxeon LED at 350mA the forward voltage might be around 3.2V. Some LEDs packages might be several LEDs in series or in parallel, changing the Vf/If curve again.

Typically a manufactuer will specify an operating current which is safe to use the LED at, and the forward voltage at that current. Usually (but not always) you get a graph similiar to below in the datasheet. You need to look at the datasheet for the LED to determine what the forward voltage is at different operating currents.

Why is this graph so important? Because it shows that when a voltage is across the LED, the current that will flow will be according to the graph. Lower the voltage and less current will flow.....and the LED will be 'off'. This is part of the theory of charlieplexing, which we'll get to in the next step.



Step 2: The Laws (of Electronics)

Still not yet at the magic of charlieplexing yet....we need to go to some basics of electronics laws.

The first law of interest states that the total voltage across any series of connected components in an electrical circuit is equal to the sum of the individual voltages across the components. This is shown in the main diagram below.

This is useful when using LEDs because your average battery or microcontroller output pin will never be exactly the right voltage to run your LED at the recommended current. For example a microcontroller will typically run at 5V and it's output pins will be at 5V when on. If you just connect an LED to the output pin of the micro, you'll see from the operating curve in the previous page too much current will flow in the LED and it will get hot and burn out (probably damaging the micro as well).

However if we introduce a second component in series with the LED we can subtract some of the 5V so that the voltage left is just right to run the LED at the proper operating current.

This is typically a resistor, and when used in this way is called a current limiting resistor. This method is used very commonly and leads to what is called 'ohms law'....so named after Mr Ohm.

Ohms law follows the equation V = I * R where V is the voltage that will appear across a resistance R when a current I is flowing through the resistor. V is in volts, I is in amps and R is in ohms.

So if we have 5V to spend, and we want 1.9V across the LED to get it to run at 20mA then we want the resistor to have 5-1.9=3.1V across it. We can see this in the second diagram.

Because the resistor is in series with the LED, the same current will flow through the resistor as the LED, ie 20mA. So rearranging the equation we can find the resistance we need to make this work.

V = I * R
so
R = V / I
substituting the values in our example we get:
R = 3.1 / 0.02 = 155ohms
(note 20mA = 0.02Amps)

Still with me so far...cool. Now look at diagram 3. It has the LED sandwiched between two resistors. According to the first law mentioned above, we have the same situation at the second diagram. We have 1.9V across the LED so it is running according to it's spec sheet. We also have each resistor subtracting 1.55V each (for a total of 3.1). Adding the voltages together we have
5V (the microcontroller pin) = 1.55V (R1) + 1.9V (the LED) + 1.55V (R2) and everything balances out.
Using ohms law we find the resistors need to be 77.5 ohms each, which is half the amount calculated from the second diagram.

Of course in practice you'd be hard pressed to find a 77.5ohm resistor, so you'd just substitute the nearest available value, say 75ohms and end up with a little more current in the LED or 82ohms to be safe and have a little less.

Why on earth should we be doing this resistor sandwhich to drive a simple LED.....well if you have one LED it's all a bit silly, but this is an instructable on charlieplexing and it comes in handy for the next step.

Step 3: Introducing 'complementary Drive'

Another name that is more accurate to describe 'charlieplexing' is 'complementary drive'.

In your average microcontroller you can in firmware tell the micro to set an output pin to be either a '0' or a '1', or to present a 0V voltage at the output or a 5V voltage at the output.

The diagram below now shows the sandwiched LED with a reversed partner....or a complement LED, hence complementary drive.

In the first half of the diagram, the micro is outputting 5V to pin A, and 0V to pin B. The current will thus flow from A to B. Because LED2 is oriented backwards to LED1 no current will flow through it and it will not glow. It's what is called reverse biased. We have the equivalent of the situation in the previous page. We can basically ignore LED2. Arrows show the current flow.

An LED is essentially a diode (hence Light Emitting Diode). A diode is a device that allows current to flow in one direction, but not in the other. The schematic of an LED sort of shows this, current will flow in the direction of the arrow......but is blocked the other way.

If we instruct the micro to now output 5V to pin B and 0V on pin A we have the opposite. Now LED1 is reverse biased, LED2 is forward biased and will allow current flow. LED2 will glow and LED1 will be dark.

Now might be a good idea to look at the schematics of the various projects mentioned in the introduction. You should see a whole lot of these complementary pairs in a matrix. Of course in the example below we are driving two LEDs with two microcontroller pins....you could say why bother.

Well the next section is where we get to the guts of charlieplexing and how it makes an efficient use of a microcontrollers output pins.

Step 4: Finally....a Charlieplex Matrix

As mentioned in the introduction, charliplexing is a handy way of driving lots of LEDs with only a few pins on a microcontroller. However in the previous pages we've not really saved any pins,driving two LEDs with two pins....big whoop!

Well we can extend the idea of complentary drive into a charlieplex matrix. The diagram below shows the minimum charlieplex matrix consisting of three resistors and six LEDs and using only three microcontroller pins. Now do you see how handy this method is? If you wanted to drive six LEDs in the normal way....you'd need six microcontroller pins.

In fact with N pins of a microcontroller you can potentially drive N * (N - 1) LEDs.
For 3 pins this is 3 * (3-1) = 3 * 2 = 6 LEDs.
Things stack up quickly with more pins. With 6 pins you can drive 6 * (6 - 1) = 6 * 5 = 30 LEDs....wow!

Now to the charlieplexing bit.

Look at the diagram below. We have three complementary pairs, one pair between a each combination of micro output pins. One pair between A-B, one pair between B-C and one pair between A-C.

If you disconnected pin C for now we'd have the same situation as before. With 5V on pin A and 0V on pin B, LED1 will glow, LED2 is reverse biased and will not conduct current. With 5V on pin B and 0V on pin A LED2 will glow and LED1 is reverse biased.

This follows for the other micro pins.

If we disconnected pin B and set pin A to 5V and pin C to 0V then LED5 would glow. Reversing so that pin A is 0V and pin C is 5V then LED6 would glow.
Same for the complementary pair between pins B-C.

Hang on, I hear you say. Lets look at the second case a bit more closely.
We have 5V on pin A and 0V on pin C. We've disconnected pin B (the middle one).
OK, so a current flows through LED5, current isn't flowing through LED6 because it is reverse biased (and so are LED2 and LED4)....but there is also a path for the current to take from pin A, through LED1 and LED3 isn't there? Why are these LEDs not glowing as well.

Here is the heart of the charlieplexing scheme. Indeed there is a current flowing both LED1 and LED3, however the voltage across the both of these combined is only going to be equal to the voltage across LED5. Typically they would have half the voltage across them that LED5 has. So if we have 1.9V across LED5, then only 0.95V will be across LED1 and 0.95V across LED3.

From the If/Vf curve mentioned at the beginning of this article we can see that the current at this half voltage is much much lower than 20mA.....and those LEDs will not glow visibly.
This is known as current stealing.

Thus most of the current will flow though the LED we want, the most direct path through the least number of LEDs (ie one LED), rather than any series combination of LEDs.

If you looked at the current flow for any combination of putting 5V and 0V on any two drive pins of the charlieplex matrix, you'll see the same thing. Only one LED will glow at a time.
As an exercise, look at the first situation. 5V on pin A and 0V on pin B, disconnect pin C. LED1 is the shortest route for the current to take, and LED 1 will glow. A small current will also pass through LED5, then back up LED4 to pin B.....but again, these two LEDs in series will not be able to syphon enough current compared to LED 1 to glow brightly.

Thus the power of charlieplexing is realised. See the second diagram which is the schematic for my Microdot watch.....30 LEDs, with only 6 pins. My Minidot 2 clock is basically an expanded version of the Microdot....same 30 LEDs arranged in an array.
To make a pattern in the array, each LED to be illuminated is briefly switched on, then the micro moves to the next. If it is scheduled to be illuminated it is switched on again for a brief time. By quickly scanning through the LEDs fast enough a principle called 'persistance of vision' will allow an array of LEDs to show a static pattern. The Minidot 2 article has a bit of an explanation on this principle.

But wait.....I've seemingly glossed over a bit in the description above. What's this 'disconnect pin B', 'disconnect pin C' business. Next section please.

Step 5: Tri-states (not Tricycles)

In the previous step we mentioned a microcontroller can be programmed to output a 5V voltage or a 0V voltage. To make the charlieplex matrix work, we select two pins in the matrix, and disconnect any other pins.

Of course manually disconnecting the pins is a bit difficult to do, particularly if we are scanning things very quickly to use the persistance of vision effect to show a pattern. However a microcontroller output pins can also be programmed to be input pins as well.

When a micro pin is programmed to be an input, it goes into what is called 'high-impedence' or 'tri-state'. That is, it presents a very high resistance (of the order of megaohms, or millions of ohms) to the pin.

If there is a very high resistance (see diagram) then we can essentially regard the pin as being disconnected, and so the charliplex scheme works.

The second diagram shows the matrix pins for each combination possible to illuminate each of the 6 LEDs in our example. Typically a tri-state is denoted by an 'X', 5V is shown as a '1' (for logical 1) and 0V as a '0'. In the micro firmware for a '0' or '1' you'd program the pins to be an output and it's state is well defined. For tri-state you program it to be an input, and because it's an input we don't actually know what the state may be....hence the 'X' for unknown.

Although we might allocate a pin to be tri-state or an input, we don't need to read it. We just take advantage of the fact an input pin on a microcontroller is high impedence.

Step 6: Some Practical Matters

The magic of charlieplexing relies on the fact the individual voltage presented across multiple LEDs in series will always be less than that across one single LED when the single LED is in parrallel with the series combination. If the voltage is less, then the current is less, and hopefully the current in the series combination will be so low that the LED will not light.

This isn't always the case however.

Lets say you had two red LEDs with a typical forward voltage of 1.9V in your matrix and a blue LED with a forward voltage of 3.5V (say LED1=red, LED3=red, LED5=blue in our 6 LED example). If you lit up the blue LED, you would end up with 3.5/2 = 1.75V for each of the red LEDs. This may be very close to the dim operating area of the LED. You might find the red LEDs will glow dimly when the blue is illuminated.

It is a good idea therefore to make sure the forward voltage of any different coloured LEDs in your matrix are roughly the same at the operating current, or else use the same coloured LEDs in a matrix.
In my Microdot/Minidot projects I didnt have to worry about this, I used high efficiency blue/green SMD LEDs which fortunately have much the same forward voltage as the reds/yellows. However if I implemented the same thing with 5mm LEDs the result would have more problematical. In this case I would have implemented a blue/green charlieplex matrix and a red/yellow matix seperately. I'd have needed to use more pins....but there you go.

Another issue is to look at your current draw from the micro and how bright you want the LED. If you have a big matrix, and are rapidally scanning it, then each LED is on for only a brief time. This it will appear relatively dim compared to a static display. You can cheat by increasing the current through the LED by reducing the current limiting resistors, but only to a point. If you draw too much current from the micro for too long you'll damage the output pins.
If you have a slowly moving matrix, say a status or cyclon display, you could keep the current down to a safe level but still have a bright LED display because each LED is on for a longer time, possibly static (in the case of a status indicator).

Some advantages of charlieplexing:
- uses only a few pins on a microcontroller to control many LEDs
- reduces component count as you don't need lots of driver chips/resistors etc
Some disadvantages:
- your micro firmware will need to handle setting both voltage state and input/output state of the pins
- need to be careful with mixing different colours
- PCB layout is difficult, because the LED matrix is more complex.

Step 7: References

There are lots of references about charlieplexing on the web.
In addition to the links at the front of the article, some of them are:

The original article from Maxim, this has a lot to say about driving 7 segment displays which is also possible.
http://www.maxim-ic.com/appnotes.cfm/appnote_number/1880

A wiki entry
http://en.wikipedia.org/wiki/Charlieplexing

Comments

author
JonBush (author)2016-02-25

Excellent tutorial on Charlieplexing. You explained it so well that even a guy like me could fully understand it. I appreciate you taking the time to publish this Instructable, not to show off your project, but further the understanding of others. Great work.

author
mushroom glue (author)2012-12-18

Is it possible to use diodes instead of LEDs, and get logic signals from a charliplexed matrix?

author
UnusualTravis (author)2012-10-03

I really don't know why someone would build a Manual switched 20 LED charlieplexed box, But I did!

DSC_0501.JPG
author
Dusk Shadows (author)2012-05-26

that looks really cool!

author
maikmuc (author)2011-11-29

hi
I would like to make a chain of LED lights for the x-mas tree out of it, pulsing and blinking in different modes. I also want to use 6 pins to be able to use 30 LED's in a total lenght of 3 meters...
Will this work? or will the LED's are too dim?

author
ebeccarayray (author)2011-10-01

Thank you so much for posting this! I am working on my electrical engineering senior design project which is going to be a bicycle with a lighting system along with other features. I am looking into Charlieplexing the taillight which is made up of 3 premade LED matrices.

My main question is, what is the actual time that each LED is lit up? I understand that the human eye takes in a new image 25 time per second, so I'm wondering how long should each LED stay lit for.

I'm also concerned that with the LED matrix I'm using, I won't actually be able to wire all of them up in the way that you've shown. This is the part I'm using: http://www.futurlec.com/LED/LEDM88RGCA.shtml

Check out http://litebike.info for more information about our project!

Thanks again.

author
Tail_wag (author)2011-09-08

Simply an excellent article. Can you confirm that we cannot turn on all LED's in the matrix at the same time using this method? Thanks.

author
rgbphil (author)Tail_wag2011-09-08

You should only keep one LED on at a time if you have no buffering on your micro, or else the current draw will exceed the micro design tolerances.

However if you read the front page, there is quite a thread on lighting several LEDs at once with a charlie matrix. It is possible, but you should really buffer the control lines.

Check out the comments on this and follow the links back to the bloke who put me right in this regard.....he's got some great examples of more advanced charliplexing on his pages and probably a better explanation than I could have done.

author
Eliche (author)2011-08-13

Excellent explanation, very easy to follow and very helpful.

author
budabob07 (author)2011-03-31

If you were to set pin A to high and pin C to low, led 5 would light up. But wouldnt leds 1 and 3 also light up (dimly) This is what happened to me when i tried the circuit

author
rgbphil (author)budabob072011-03-31

Yes...check the comments in the text. The amount would depend on the type of LEDs, their forward voltages, minimum operating current and the voltage/current you are putting across the grid.
I suspect either you have some really cool low current LEDs, the voltage is too high or the current limit resistors being used are too small.

author
lavert31 (author)2010-07-10

hey, if instead if disconnecting pin B you will put it in HIGH you'll get the same effect. current wont go through LED 1 due to zero voltage difference. i say that because i wonder how can you disconnect and reconnect pins in the microcontroller? you can either put it on 1 or 0 no?

author
Rob Cranfill (author)lavert312010-10-12

Good question. That is addressed in the next "step", "Tri-states".

author
Rob Cranfill (author)2010-10-12

Typo: In the 6th paragraph, last sentence,

// With 5V on pin B and 0V on pin A LED1 will glow.

should be "LED2", right?

- rob

author
rgbphil (author)Rob Cranfill2010-10-12

Yep, thanks, should be updated now.

author
WVvan (author)2010-08-17

A most excellent article. Couldn't be more clear.

author
Vick Jr (author)2010-08-04

OK. I understand the theory completely, even the math for computing how many leds can be controlled with x many io pins. If that schematic for a charlieplex matrix were expanded, it would be fractal. It's pretty cool actually. Now to turn theory into practice. I'm trying to make a charlieplexed led cube that's 4x4x4 (64 leds) which could theoretically be controlled with 9 io pins, but I can't wrap my head around mapping a 2d fractal charlieplex schematic into a 3d circuit. I already have all the wows done, with all the cathodes on a row connected and the anodes unconnected for now. How do i complete it? Any help would be appreciated. I plan to control it with an arduino, and may make it into an instructible. (if people aren't tired of led cubes, that is) My backup plan is to just have a pin corresponding to each of the 4 levels and each of the 16 columns. Thats 20 io pins needed. The arduino has 13 regular digital pins, 6 analogue pins that can also be used as digital io, so it's 1 pin short. I'd have to leave something off.

author
rgbphil (author)Vick Jr2010-08-04

Heres how I did mine; https://www.instructables.com/id/3D-LED-Charlieplex-Cube-from-Chrismas-Tree-Lights/ I had grids or meshs forming the charlieplex array. Note, my array was very sparse, so I was using more signal lines than I really needed. This was mostly for mechanical convenience than anything else. Phil

author
Vick Jr (author)rgbphil2010-08-04

Ahhhh, I see what you did. I actually got the idea to use xmas tree leds from you, but I was constructing it according to this and didn't alternate the polarity of the leds with the layers, which I think is the key to your method. No matter, I have plenty of xmas lights and plenty of time. I can make 2 cubes (or one giant stack!) There might also be a way to charlieplex one or two places in my configuration. I only need to reduce the number of io pins by 1 to work with the ardiuno. Thanks for your help, and how's your next cube with the "proper charlieplex driving scheme" coming along? Try making a template to put your leds in, then overlay the chicken wire or whatever (I used paperclips) and solder it in. That would be a good way to get the leds and their support structure as exact as possible.

author
rgbphil (author)Vick Jr2010-08-05

Glad to be any help. I honestly haven't had time for any more charlieplexing cubes....although I have been thinking of alternatives....why not have a hex structure, each LED is in the vertex of a 3d hex shape rather than a cube so they are all equidistant.....a bit different (more net interest), plus higher LED density. Another alternative may be to do away with the lattice (cube or hex) altogether. Instead have a charliplexed string driven from below without any cross connections at all. Eg three pins, gives 6 LEDs, 4 gives 12 LEDs high. Then just arrange the strings vertically into whatever shape you want, cube, cylinder, sphere etc. You could also make a charlieplex chandelier if they hang freely. You can be flexible, test as you go and build as you go as well. This would probably require more io pins, I've been wracking my brain how to share io between strings on this setup. Note charlieplexing with fewer io pins means lower individual brightness because only one LED can be easily lit at a time (scrummage through the comments below, there is a solution for making several lit at a time...albeit at an increase in wiring complexity). More io pins used on a sparse charlieplex matrix increases the brightness. Good luck, please experiment and if you have time write up an instructable (linking to any reference sources of course) for others to enjoy and learn from. I've gotten quite a buzz from all the happy campers who've read this instructable and learnt something. phil

author
Vick Jr (author)rgbphil2010-08-06

I like the hex idea-sortof like an led ball or sphere. As for the string idea, check out this project for charlieplexed string of 12.

If and when I make an instructable, I'll be sure to refer to yours. I'm having problems getting my cube to work with my arduino though. When I test it with a battery, connecting positive and negative to the correct wires, the correct led lights up, but when I use the ardiuno, some leds work fine, but others will not light up, or have other leds light up with them. If the cube works, then it must be a problem with my arduino or with my program.

Is it possible that there's some sort of interference or something between the pins that makes them not behave as expected?

Here's my code (sorry if formatting is undone.)

It's pretty well commented. The cube is set up like yours, with alternate rows as complimentary drives. I use all the io pins except 13 and 19 (analogue 5).  T light up an led first disconnect all pins (set as input), then set it's poll and level as input and apply voltage and ground (digital out HIGH/digital out LOW) appropriately.

/*
This program controls a 4x4x4 semi-charlieplexed LED cube using 18 io pins
Alternate rows of the cube have leds with opposite poles, and are complimentary drives.
pins are refereed to by row, column, and layer (r,c,l), going front-to-back,left-to-right, and bottom-to-top.
The rows and columns are connected to poles that go through the layers.
*/

//array mapping led rows and columns to arduino pins
int gridPinMap[4][4]=
{
{0,1,2,3},
{4,5,6,7},
{11,10,9,8},
{14,15,16,12}
};

//ints mapping cube levels to arduino pins
int levels01pin = 17;
int levels23pin=18;

void setup(){
Serial.begin(9600);// initialize serial communications at 9600 bps:
allOff();
pinMode(13, INPUT);//we don't use 13 b/c it has a built-in resistor but just in case, disconnect it
}

void loop(){//main loop
//this simple program turns each pin on for a second successivly
for (int r=0;r<4;r++){
for (int c=0;c<4;c++){
for (int l=0;l<4;l++){
LEDON(r,c,l);
delay(1000);
allOff();
delay(1000);
}
}
}
}

//this function disconnects all the io pins we are using, so nothing should be on at all.
void allOff(){
Serial.print("\nOFF" );
//set everything to output by default
for (int r=0;r<4;r++){
for (int c=0;c<4;c++){
pinMode(gridPinMap[r][c], INPUT);
}
}
pinMode(levels01pin, INPUT);
pinMode(levels23pin, INPUT);
}

//this function turns on the led at (r,c,l)
void LEDON(int r, int c, int l){
Serial.print("\n(");
Serial.print(r);
Serial.print(c);
Serial.print(l);
Serial.print(")");

//if the led to light is in row 0 or 2, it's column needs a ground (digital out LOW), and the level needs a positive voltage (digital out HIGH).
//Vice-versa if on levels 1 or 3

switch (l) {
case 0://bottom level
//disconnect the other two columns so no other pins go on
//pinMode(levels23pin, INPUT);
//send ground to column of pin
pinMode(gridPinMap[r][c], OUTPUT);
digitalWrite(gridPinMap[r][c],LOW);
//send voltage to row of pin
pinMode(levels01pin, OUTPUT);
digitalWrite(levels01pin,HIGH);
break;
case 1://first level up
//pinMode(levels23pin, INPUT);
pinMode(gridPinMap[r][c], OUTPUT);
digitalWrite(gridPinMap[r][c],HIGH);
pinMode(levels01pin, OUTPUT);
digitalWrite(levels01pin,LOW);
break;
case 2://second level up
//pinMode(levels01pin, INPUT);
pinMode(gridPinMap[r][c], OUTPUT);
digitalWrite(gridPinMap[r][c],LOW);
pinMode(levels23pin, OUTPUT);
digitalWrite(levels23pin,HIGH);
break;
case 3://top level
//pinMode(levels01pin, INPUT);
pinMode(gridPinMap[r][c], OUTPUT);
digitalWrite(gridPinMap[r][c],HIGH);
pinMode(levels23pin, OUTPUT);
digitalWrite(levels23pin,LOW);
break;
}
}

author
rgbphil (author)Vick Jr2010-08-06

Hi, I've got a few things on my plate today...so I haven't had a thorough read of the code sorry. So based on this: Some possibilities: - I'm guessing all the LEDs are the same colour, if not see the instructable about the issue where the forward voltage difference between colours can result in a problem. - check your digitalWrite and PinMode routines don't have the read/modify/write issue common to PICs (I'm not familiar with Arduino code ). In PICs a bit change on a port can sometimes be unreliable for various reasons, it's usually better to use a shadow port register and write the whole port register at once from this or use a r/c/l coordinate to locate a bit mask as in my code. Instead of setting each r/c/l to INPUT individually, just set the whole port register or registers to INPUT at once in the allOff routine. It'll be faster as well without an array sweep. If you check my code I stored the port register input/output bit masks as well as the output register bit masks and outputted those. Try changing the code to simply run through a couple of LEDs then stop. Then use a multimeter to see if multiple I/O pins are being set to low or high. You should only have two lines active either low or high, the rest should be tri-state or input. You can use a large pull up/pull down resistor sitting on the multimeter probe to check if the line is tri-state. If you can pull it up and down then it's set to an input. If it sticks at high or low, then it is an output. Phil

author
Vick Jr (author)rgbphil2010-08-07

The LEDs are the same type, but they are ripped from an old string of xmas lights. They are bleached from sunlight, some are rusty, but they seem to work.

The regular arduino language is a high level C-like library with functions for pin manipulation, but I did find this page on directly manipulating pins . It should be helpfull. I'll try it in a bit.

author
lavert31 (author)2010-07-10

Ohhhh o.k! now i answered myself! putting pin B in an HIGH state will cause LED 3 to glow... the only solution is to disconnect pin B . thanks for this very comprehensive tutorial! Etay

author
lavert31 (author)2010-07-10

:-) o.k now you actually answered my question about disconnect pins. but still, instead of disconnect you can put it on HIGH no?

author
tonysofla (author)2010-06-23

I made a 12 led Charlieplexed with softwarebased 8bit PWM
http://www.youtube.com/watch?v=8apRaZQbv5w

author
rgbphil (author)tonysofla2010-06-25

nice work, it's pretty hard getting good PWM on charlieplex unless you're throwing lots of cycles at it so hats off. I look forward to a fancied up instructable of your own detailing the innards of the software.

author
codongolev (author)2010-04-05

man.... that explained it so well. thanks!

author
RobbMeex (author)2010-01-16

I just put this thing together!! Thanks a bunch. I was looking for a simple two digit display for a GPS speedometer.

author
haooken (author)2009-10-22

Excellent explanation. I'll definitely have to give this a try.

author
ricecooker7654 (author)2009-08-20

i first i was slightly intimidated by ur explanation but after reading it, i feel like i can teach my electronics teacher this concept. thanks -drew

author
michaeletompkins (author)2009-08-10

Thanks a lot!

author
Koolraap (author)2009-05-30

It's such an easy to understand explanation, i totally graped the concept with one read :)

author
ian25 (author)Koolraap2009-08-03

I have never understood this "charlieplexing" thing, but after reading this I understood it completely. 5 *'s

author
rgbphil (author)ian252009-08-03

Thanks for the compliment...and to all the other people the instructable has helped and taken the time to comment.

author
aolinger (author)2009-04-06

I've got it, and I'm a complete new to to microcontrollers and electronics! Thanks for this great explanations! Alex

author
51fordf2 (author)2009-03-18

Thanks, about the easiest to understand explanation I have seen. R

author
geeklord (author)2009-03-01

In step two, don't you want 3.2-3.8 volts across an LED?

author
rgbphil (author)geeklord2009-03-01

No, if you read closely you find I looked at my forward operating region for the LED from my graph and it was 1.9V, I wanted 3.1V shared between the two resistors. For combined red/green/blue LED matrices I made a note in step six to be careful about mixing different colours as they might have different forward voltages. In practice I found with the LEDs I had for my clock the green/blue LEDs lit up nicely at 1.9V, presumably because they were low power SMD devices or I was just luck ...so I didn't have to worry, however you do need to check this first. Other LEDs may well have higher forward voltages and in that case green/blue LEDs will need a separate matrix.

author
geeklord (author)rgbphil2009-03-02

thank you, that was helpful

author
UziMonkey (author)2009-01-25

Thanks, this was really helpful.

author
yourcat (author)2008-12-05

Thanks for posting this!

author
Carlos Marmo (author)2008-10-30

Wonderful Work! Congratulations!

author
electric_destruction (author)2008-08-26

NICE!!! i havent been able to get an account 4 a while, but i hav been reading instructables for monthes. urs really helped me out with a problem i had 2 solve. AWSOME!!!

author
McLaren (author)2008-06-15

Please forgive the typo' in the previous post. Obviously I meant to say; This improves overall brightness by increasing duty cycle.

I suspect there's a few chaps scratching their heads trying to figure out how to drive that 6 pin 30 LED matrix example in my previous post so I've attached a driver example in C.

Basically, it uses a 6 element array, one element for each column, with the least significant five bits in each element corresponding to the five LEDs in each column. Your main program simply sets or clears those bits to turn the corresponding LEDs on or off. The ISR driver uses periodic timer 2 interrupts and lights the LEDs in a single column during each interrupt interval so it takes six interrupt intervals to refresh the entire matrix.

The driver may not seem very intuitive at first but if you look at the LEDs on the RB5 row in the drawing (link) in my previous post and think of RB5 as a "floating" row, the method may make more sense.

Have fun. Regards, Mike

K8LH Charlieplexed Driver Example

author
rgbphil (author)McLaren2008-06-15

Hi Mike, I've had a very quick look at the code, can you answer a couple of questions though. If you are only using 6 interrupt intervals, then how can you provide an arbitrary pattern for 30 LEDs without illuminating several LEDs at once? This might be your purpose however, so please excuse me if that is the case. From what I understand you are doing a bargraph/bardot display. In that case, this is a reasonable method for such displays. For the minidot/microdot clocks however I wanted an arbitrary pattern for the 30LEDs (see pics on these instructables).....not sure that this would help in that case. If you have a look at the minidot/microdot code, I've had to have a lookup table for each LED and put the tris/port values out for each possible combination. I suppose the 'all possible combination' method is the generic method for pur charlieplex arrays, and this method is better suited as you've noted for seven segment displays or bar graphs where either only one LED is illuminated, or an ordered number of LEDs (ie a bar) is illuminated. I might be missing something, if you can do another more efficient algorithm for arbitrary patterns please post it. Again, I mentioned I've only had a quick look. On any particular iteration through the 6 interrupt cycles, do you have several LEDs on at once? If so, then you might have a problem with varying brightness if say on cycle one you want one LED, cycle two four LEDs etc because the cummulative forward voltage of several LEDs being illuminated will change the current. Thanks for adding to the instructable though, I think it illustrates the different cases for charlieplex arrays. Phil

author
rgbphil (author)rgbphil2008-06-15

>>>>>RETRACTION<<<<<<<

Sorry!!!!! I must do a bit of back paddling here. I didn't look at the solution you've come up with properly.

I didn't refer to the below circuit diagram when making the above comments.
I see now how you can have several LEDs on at once and still have an arbitrary pattern.

Lets see if I can explain properly.
First, because the diagram has no LEDs numbers lets assume a numbering convention where L11 means LED at row 1, column 1 , top left hand corner and L61 means LED at row 6, column 1 (bottom right hand corner. Of course LED11, LED22, LED33 etc don't actually exist in the matrix.

You can set an arbitrary pattern for column 1, eg L21, L31, L41 by setting tris/port values tris=xx110000 and port=xxx10001 (where x means don't care).
This sets RB0 to high to turn on the column driver, and RB1,2,3 to LOW to turn on LEDs L21,L31 and L41. RB4 and RB5 are tri-state.
This would be the first interrupt cycle.

Next pattern for column 2 eg L21, L23, L26 by setting
tris=xx010100 and port=xx0x0x10

and so on. You can see that for each column in your arrangement there will be the same number of zeros in the port setting as the number of LEDs in that column you want to illuminate, plus a 'one' to set the output column driver. In the tris, there will be the number of desired LEDs+1 zeros to enable the output lines (all others to tri-state).

Apologies for jumping the gun before....this is a great method for reducing the number of interrupt cycles to control the array. With the extra time saved, PWM can be used to do brightness control.

My original concern was that the current sinking capability of the micro wasn't enough to handle several LEDs at one, however I can see now that each current sink line, only sinks one LED worth of current, and the transistors source the needed current.

Hats off....thanks for helping the charliplex community out. I can see the validity of this method now. You do need extra components....but that could be handled by a single transistor array chip (eg ULN 2800 for PNP drivers, ULN2803 of NPNs if you arrange it the other way).

When I extract my finger, I'll be using this method on my little LED cube. I was worried about getting PWM brightness control for a 5x5x6=125 LED array.

Phil

author
McLaren (author)rgbphil2008-06-16

You've almost got it Phil. The PORT reg' can only have a single '1' bit at any time (xx100000, xx010000, xx001000, xx000100, xx000010, or xx000001) to turn on a single column driver transistor. That's the purpose of the colpos ring-counter variable in the driver. We also use this '1' bit in colpos to determine when an individual led bit in our display array variable matches one of those invalid col/row positions (rb0/rb0, rb1/rb1, etc.) and needs to be "floated" onto the RB5 "float" row. If you physically slide those RB5 "float" row LEDs into the holes in the matrix above then your display array will match your LED numbering scheme.

Yes, you can still PWM the LEDs with this method (with improved duty cycle).

Yes, you could use a UDN2981 sourcing driver IC for CA columns or a ULN2803/2804 sinking driver IC for CC columns but adding an IC almost defeats the purpose of Charlieplexing (grin). I guess for some reason I don't think adding 5 transistors is 'cheating' (grin).

BTW, during my Charlieplexing experiments several years ago I observed higher brightness when the PIC pins sink current to LED cathodes rather than source current to LED anodes and so that's why you'll notice common anode column drivers in most of my projects.

Have fun.

Mike, K8LH (Michigan, USA)

Clock-1v2.jpgClock-BCD.PNG
author
dforsyth (author)McLaren2008-06-19

what simulator are the product pictures from?

author
McLaren (author)dforsyth2008-06-19

Those drawings are Microsoft Excel spreadsheets (using the drawing tools). Mike

About This Instructable

168,109views

349favorites

License:

Bio: update later
More by rgbphil:3D LED Charlieplex Cube from Chrismas Tree LightsCharlieplexing LEDs- The theoryMinidot 2 - The holoclock
Add instructable to: