What is Charlieplexing, and what can I do with it?

Charlieplexing is the ability to control multiple LED’s with fewer outputs than the number of LED’s. Charlieplexing is named after Charles Allen from Maxim Integrated who first proposed the idea in 1995.

Charlieplexing uses all three logic states of a microcontroller as well as the one-way conductivity of the LED’s to control a matrix. This can be useful if you are trying to show the status of different processes and do not want to take up more than a few microcontroller pins to do so.

Below is the simplest example of a set of Charlieplexed LED’s.
Charlieplexing2IO
Notice in the above example it uses a complementary set of LED’s. Based on how LED’s allow current to flow in one direction and block it in the other direction, it allows us to control both LED’s depending on how the input/outputs are set up. To use this example, you can control two LED’s with two pins by changing the output type of the pins. If you were to turn Pin 2 high and Pin 1 low, the L1 LED would turn on. If you set the Pin 1 high, and Pin 2 low, the L2 LED would turn on.
Below is how you would set this up in Arduino.

 void setup() {
  Serial.begin(9600);
  

}

void loop() {
   pinMode(1,OUTPUT);
   pinMode(2,OUTPUT);
  pinMode(3,INPUT);
 
digitalWrite(2,HIGH);
  digitalWrite(1,LOW);
  delay(1000);
 
Serial.println("1");

    pinMode(1,OUTPUT);
   pinMode(2,OUTPUT);
   pinMode(3,INPUT);
 
digitalWrite(1,HIGH);
  digitalWrite(2,LOW);
  delay(1000);
 
Serial.println("2");
  
}

Now looking at this schematic you may be thinking, “How can this be useful? We are only controlling two LED’s with two pins.” Let look at what happens when we add a third pin.
Below is how to set up the LED’s for 3 pins.

Charlieplexing3IO

As can see by this setup, you can control 6 LED’s with 3 pins. To control the LED’s in this setup, you will need to use all three states of the microcontroller. If you wanted to turn on the L1 LED and no others, you would have to set Pin 2 to HIGH, Pin 1 to LOW, and Pin 3 to an INPUT. The reason for the Pin 3 would have to be set to input, is to put this pin into a high impedance. This basically electrically disconnects the pin from the circuit. Also, If we set Pin 3 to LOW instead, LED L4 would also light up.
Now if you wanted to turn on the L2 LED, the user would set pin 1 to high, pin 2 to low and pin 3 to input. Notice again if we did not set Pin 3 to input, the L4 LED would turn on as well.
The user could then complete this process until they have successfully lit every one of the LED’s in order.
Below is one way that the code could be written if you wanted to do this with an Arduino.

void setup() {
  Serial.begin(9600);
  

}

void loop() {
   pinMode(1,OUTPUT);
   pinMode(2,OUTPUT);
  pinMode(3,INPUT);
 
digitalWrite(2,HIGH);
  digitalWrite(1,LOW);
  delay(1000);
 
Serial.println("1");

    pinMode(1,OUTPUT);
   pinMode(2,OUTPUT);
   pinMode(3,INPUT);
 
digitalWrite(1,HIGH);
  digitalWrite(2,LOW);
  delay(1000);
 
Serial.println("2");
  
    
pinMode(3,OUTPUT);
   pinMode(2,OUTPUT);
     pinMode(1,INPUT);
 
digitalWrite(3,HIGH);
  digitalWrite(2,LOW);
  delay(1000);
    Serial.println("3");
    
      
pinMode(3,OUTPUT);
   pinMode(2,OUTPUT);
   pinMode(1,INPUT);
 
digitalWrite(2,HIGH);
  digitalWrite(3,LOW);
  delay(1000);
   
Serial.println("4");

      
pinMode(1,OUTPUT);
   pinMode(3,OUTPUT);
   pinMode(2,INPUT);
  digitalWrite(3,HIGH);
  digitalWrite(1,LOW);
  delay(1000);
   
Serial.println("5");

       
pinMode(1,OUTPUT);
   pinMode(3,OUTPUT);
    pinMode(2,INPUT);
 
digitalWrite(1,HIGH);
  digitalWrite(3,LOW);
  delay(1000);
   
Serial.println("6");
}

Now that we have explored two and 3 pins, you can see how Charlieplexing can be a useful tool. Let’s go through one more setup for 4 input pins.
Before we show the setup of 4 inputs, can you guess how many LED’s we will be able to control?

You can figure out how many possible LED’s you can control by multiplying the number of I/O you want to use by that same number of I/O minus 1. So for example, if we wanted to use 4 I/O pins, we would multiply that number by 3 and that would let us know that we could control up to 12 LED’s with 4 I/O.

Below is how you would set up the LED’s for 4 I/O.

Notice I have color-coded the connection on this one to make the connection a little clearer. As you can see by adding one more pin to the schematic, we can add 6 more LED’s. To control the LED’s, this setup works the same as 3 Pins, however, in this case, we will have 2 pins set as inputs. Below is the Arduino code to step through all 12 LED’s.

void setup() {
  Serial.begin(9600);


}

void loop() {
  pinMode(1, OUTPUT);
  pinMode(2, OUTPUT);
  pinMode(3, INPUT);
  pinMode(4, INPUT);
  digitalWrite(2, HIGH);
  digitalWrite(1, LOW);
  delay(1000);
 
Serial.println("1");

  pinMode(1, OUTPUT);
  pinMode(2, OUTPUT);
  pinMode(3, INPUT);
  pinMode(4, INPUT);
  digitalWrite(1, HIGH);
  digitalWrite(2, LOW);
  delay(1000);
 
Serial.println("2");

  pinMode(3, OUTPUT);
  pinMode(2, OUTPUT);
  pinMode(1, INPUT);
  pinMode(4, INPUT);
  digitalWrite(3, HIGH);
  digitalWrite(2, LOW);
  delay(1000);
 
Serial.println("3");

  pinMode(3, OUTPUT);
  pinMode(2, OUTPUT);
  pinMode(1, INPUT);
  pinMode(4, INPUT);
  digitalWrite(2, HIGH);
  digitalWrite(3, LOW);
  delay(1000);
 
Serial.println("4");

  pinMode(1, OUTPUT);
  pinMode(3, OUTPUT);
  pinMode(2, INPUT);
  pinMode(4, INPUT);
  digitalWrite(3, HIGH);
  digitalWrite(1, LOW);
  delay(1000);
 
Serial.println("5");

  pinMode(1, OUTPUT);
  pinMode(3, OUTPUT);
  pinMode(2, INPUT);
  pinMode(4, INPUT);
  digitalWrite(1, HIGH);
  digitalWrite(3, LOW);
  delay(1000);
 
Serial.println("6");

  pinMode(3, OUTPUT);
  pinMode(4, OUTPUT);
  pinMode(2, INPUT);
  pinMode(1, INPUT);
  digitalWrite(3, HIGH);
  digitalWrite(4, LOW);
  delay(1000);
 
Serial.println("7");

  pinMode(3, OUTPUT);
  pinMode(4, OUTPUT);
  pinMode(1, INPUT);
  pinMode(2, INPUT);
  digitalWrite(4, HIGH);
  digitalWrite(3, LOW);
  delay(1000);
 
Serial.println("8");

  pinMode(2, OUTPUT);
  pinMode(4, OUTPUT);
  pinMode(1, INPUT);
  pinMode(3, INPUT);
  digitalWrite(4, HIGH);
  digitalWrite(2, LOW);
  delay(1000);
 
Serial.println("9");

  pinMode(2, OUTPUT);
  pinMode(4, OUTPUT);
  pinMode(1, INPUT);
  pinMode(3, INPUT);
  digitalWrite(2, HIGH);
  digitalWrite(4, LOW);
  delay(1000);
 
Serial.println("10");

  pinMode(1, OUTPUT);
  pinMode(4, OUTPUT);
  pinMode(2, INPUT);
  pinMode(3, INPUT);
  digitalWrite(4, HIGH);
  digitalWrite(1, LOW);
  delay(1000);
 
Serial.println("11");

  pinMode(1, OUTPUT);
  pinMode(4, OUTPUT);
  pinMode(2, INPUT);
  pinMode(3, INPUT);
  digitalWrite(1, HIGH);
  digitalWrite(4, LOW);
  delay(1000);
 
Serial.println("12");
}

As you can see this can be a useful tool if you are only limited to a few I/O pins.

If you would like to see other options of Charlieplexing, there are several cool projects out there that use Charlieplexing on YouTube. One of the most common projects I see that uses Charlieplexing is a LED cube. If you search on YouTube for Charlieplexed LED cube you will see several different builds.

1 Like