Charlieplexing.

Hope someone finds this stuff useful...

Cut and paste the following into the Arduino Editor, read the comments for details on wiring up the LEDs.

==========================================
/*
This program toggles the state of 4 leds through 16 combinations
using only 3 pins (without exclusive ground). This project was a proof of concept for implementation
of "charlieplexing"; multiplexing using dynamic use of anode and cathode- resulting in
efficient utilisation of pins for driving LED displays in a multiplexed mode.

Only one LED is on at any one time. The LEDs are flashed
alternately at a rate that achieves persistence of vision.

Known problems: This version of the program results in minor residual LED illumination
arising from sync issues during the switching phase.

Connect four LED's to your Arduino...
LED1: Cathode to pin 6, Anode to pin 5
LED2: Cathode to pin 5, Anode to pin 6
LED3: Cathode to pin 7, Anode to pin 6
LED4: Cathode to pin 6, Anode to pin 7

Todo: Rewrite in assembly, using timer interrupt to service LED sequencing.

Written by Hoastey, October 2007
*/

int ledPina=5;
int ledPinb=6; /* Use pins 5, 6 and 7 */
int ledPinc=7;

const int dly=100; /* delay time /
const int mpxdly=1; /
multiplexed delay time */

void setup()
{
pinMode(ledPina, OUTPUT); /* Set the Arduino pins for output */
pinMode(ledPinb, OUTPUT);
pinMode(ledPinc, OUTPUT);
}

void loop() /* Sequence through all the LED combinations */
{
state(0,0,0,0,dly); // zero
state(0,0,0,1,dly); // one
state(0,0,1,0,dly); // two
state(0,0,1,1,dly); // three
state(0,1,0,0,dly); // four
state(0,1,0,1,dly); // five
state(0,1,1,0,dly); // six
state(0,1,1,1,dly); // seven
state(1,0,0,0,dly); // eight
state(1,0,0,1,dly); // nine
state(1,0,1,0,dly); // ten
state(1,0,1,1,dly); // eleven
state(1,1,0,0,dly); // twelve
state(1,1,0,1,dly); // thirteen
state(1,1,1,0,dly); // fourteen
state(1,1,1,1,dly); // fifteen
}

/*
Set LED state.

Accepts status for led1, led2, led3 and led4 (1=on, 0=off) and period (length of display)
*/

void state(boolean led1, boolean led2, boolean led3, boolean led4, int period)
{
for(int i=0; i<period; i++)
{
if (led1==1) {
digitalWrite(ledPina, HIGH);
digitalWrite(ledPinb, LOW);
digitalWrite(ledPinc, LOW);
}
else {
digitalWrite(ledPina, LOW);
digitalWrite(ledPinb, LOW);
digitalWrite(ledPinc, LOW);
}
delay(mpxdly);
if (led2==1) {
digitalWrite(ledPina, LOW);
digitalWrite(ledPinb, HIGH);
digitalWrite(ledPinc, HIGH);
}
else {
digitalWrite(ledPina, LOW);
digitalWrite(ledPinb, LOW);
digitalWrite(ledPinc, LOW);
}
delay(mpxdly);
if (led3==1) {
digitalWrite(ledPina, HIGH);
digitalWrite(ledPinb, HIGH);
digitalWrite(ledPinc, LOW);
}
else {
digitalWrite(ledPina, LOW);
digitalWrite(ledPinb, LOW);
digitalWrite(ledPinc, LOW);
}
delay(mpxdly);
if (led4==1) {
digitalWrite(ledPina, LOW);
digitalWrite(ledPinb, LOW);
digitalWrite(ledPinc, HIGH);
}
else {
digitalWrite(ledPina, LOW);
digitalWrite(ledPinb, LOW);
digitalWrite(ledPinc, LOW);
}
delay(mpxdly);
}
}

Regards,
Hoastey.

Pretty cool, rhoaste.

But you didn't really catch the idea of Charlieplexing. Doing so, you could control six LEDs with your three output lines. With four output lines, you could drive 12 LEDs, 20 for five output lines (I think), etc.

In a Charlieplexing arrangement of any given number of pins, you add a pair of back to back LEDs between all possible pin combinations. The number rapidly mounts as you add more pins. (Yes, there's a formula for the maximum number of LEDs you can handle with any given number of pins, but I've forgotten what it is, and am too tired to derive it right now.)

Edited to add: Google is a tired man's best friend. Well, Google and coffee, I guess. The formula for the number of LEDs vs number of lines is #LEDs = #lines * (#lines - 1)

The strategy is to hold all pins in the high impedance input state except the two pins you wish to use to drive a particular LED. Set those two as outputs, and set them to the proper states required to turn on your particular LED.

Here's an example using your three pins and six LEDs.

Lets's say you have three LED control lines. Call them A, B, and C. Connect a pair of back-to-back LEDs between A and B, between B and C, and between A and C. (It might help to draw yourself a little sketch to follow the switching.)

Now initialize by setting pins A and B as outputs, and C as an input.

Turn on LED AB1 by sending a high on pin A and a low on pin B. Turn on LED AB2 by reversing the polarities of A and B.

Set pin B as an input and leave A as an output. Set pin C as an output.

Turn on LED AC1 by sending a high on A and a low on C. Turn on LED AC2 by reversing the polarities of pins A and C.

Set pin A as an input, and B as an output. Leave pin C as an output.

Turn on LED BC1 by sending a high on B and a low on C. Turn on LED BC2 by reversing the polarities of pins B and C.

And so forth.

For current limiting resistance, add 1/2 the normal value between each pin and the LED network. For each LED you turn on, two and only two resistors will be in series with the LED. For a 5 volt circuit where you'd normally use a single 330 ohm resistor for current limiting, you'd place something like a 150 ohm resistor on each pin.

HTH,

Tom

There are a couple "Instructables" on Charlieplexing:

my own: http://www.instructables.com/id/How-to-drive-a-lot-of-LEDs-from-a-few-microcontrol/
And also:
http://www.instructables.com/id/Charlieplexing-LEDs--The-theory/
http://www.instructables.com/id/Charlieplexing-7-segment-displays/

Thanks Tom,

I did some thinking after my initial post and did see that A-C was also a possible combination enabling the control of 6 LEDs, but I didn't really understand how I could achieve any other states without interfering with the other 4 LEDs. Thank you for bringing up the solution of using input state pins, and illustrating the possible combinations! That's really cool!

Regards,
Hoastey.

http://www.instructables.com/id/Charlieplexing-7-segment-displays/

7 SEGMENT DISPLAYS??? You just knocked my socks off!

Thanks, westfw. That's just amazing.

Tom

Hi everyone

I'm building a charlieplexed circuit.
I still have a problem with two led's lighting up at the same time, when only 1 should. I've tried multiple resistors but that would not make any difference. I have 18 LED's on 5 pins. When I set pin 12 on HIGH and 11 on LOW, it seems like pin 10 is LOW as well, even though I've programmed it as INPUT.

Are there things I could be missing? It is a very important project for school, so any help would be appreciated.

Thanks
Andreas (the Netherlands)

(my code is attached as well)

/*
To do:
 -leds aandoen invoeren
 */

# define STATUS_OFF 0x80
# define BEGIN_NOTE 0x2d


# define UNDEFINED 5

# define PIN_1 6
# define PIN_2 7
# define PIN_3 8
# define PIN_4 9
# define PIN_5 10
# define PIN_6 11
# define PIN_7 12

# define STATUS_LED 13


void setup()
{
 pinMode(PIN_1,INPUT);
  pinMode(PIN_2,INPUT);
  pinMode(PIN_3,INPUT);
  pinMode(PIN_4,INPUT);
  pinMode(PIN_5,OUTPUT);
  pinMode(PIN_6,INPUT);
  pinMode(PIN_7,OUTPUT);


  pinMode(STATUS_LED,OUTPUT);



  digitalWrite(STATUS_LED,LOW);
  delay(1);
  digitalWrite(STATUS_LED,HIGH);
  delay(500);
  digitalWrite(STATUS_LED,LOW);
}

void loop()
{
  digitalWrite(PIN_7,LOW);
  digitalWrite(PIN_5,HIGH); 
}

Are you getting confused by your numbering?

That code is controlling digital pins 10 and 12, not digital pin 11

Oh yeah, that should be 6 and 7 but that was just a mistake in my post. With every combination I make, two LED's light up. Hm.. :-/

I could not resist linking to my library: Arduino Playground - Charlieplex Library

But, implementing a charlieplexed network is a very good exercise :slight_smile:

can you show us your circuit or describe it carefully?

can you show us your circuit or describe it carefully?

Andreas, in addition to setting pins to INPUT, I recommend you also specify that they be set HIGH or LOW to start them in a known state.

See the recommendation for input pins at http://arduino.cc/en/Tutorial/DigitalPins.

If you think one of your input pins is low and it shouldn't be, use the following in setup()

pinMode(pin, INPUT);           // set pin to input
digitalWrite(pin, HIGH);       // turn on pullup resistors

The code you posted doesn't show where you manipulate the input pins, so maybe you set it somewhere before it is a problem, I can't tell.