Introduction: Spectrometer/LED Array Using Charlieplexed LED's

About: I am interested in a wide range of things as shown in my list of interests. Almost anything creative is fun and worth trying.

In this instructable we construct an array of LED's which can then be controlled with an Arduino, or any other AVR based microcontroller, or Raspberry Pi, or whatever you like. We are simply building the tool here and you can apply it as you wish.

The idea is to `Charlieplex' together an array of LED's which can then be turned on and off individually via a small number of inputs. In the present case we are using 7 input wires which then control 42 separate LED's. You can find many different instructables and websites that explain how Charlieplexing works and so I won't repeat it here. Suffice to say that each input lead is connected to all of the others via an LED. Since an LED is a diode, current will flow in only one direction and so the net result is that there will be numerous paths between any two input leads, each path containing various LED's along the way. All of these paths except for one will have multiple LED's (or some LEDs oriented the wrong way) and hence the current going through them will be less than the amount needed to cause them to glow (i.e. the current will be in the `no glow' region of these LED's.) The path that has only a single LED on it will have enough current flow to cause it to glow and so connecting those two leads will light up only this LED. If you then reverse the polarity so the 5V is on the other lead and the GND on the first, a different LED will glow due to a different path being taken. I find a good way to think of it is that each of the vertical bars will be at the same potential, I put one of them at 5V, a different one at 0V, and the rest are disconnected from the source. You can now trace the potential as it follows a path noting that if you come to a bar that is disconnected from the input leads it will simply act like a wire in your circuit and take on whatever is the potential at that point coming from my connected leads. In any case, the net result of all this is that, for N leads pairwise connected to all of the others via two polarities each, you can control 2*(N choose 2) LED's. In other words: #LEDS = 2*N!/[2! (N-2)!] = N*(N-1).

I eventually want a 10 by 9 array containing 90 LEDs but to start out, in the case we are building here, we have 7 input leads and so we can individually control 7*6 = 42 LEDs. I think you will see that it is obvious and straight forward to make this as big as you like.

So lets build it.

You will need:

-- a perfboard

-- a bunch of LED's

-- a female header

-- 7 resistors, around 220 to 320 ohm

-- some wire, solder, soldering iron, etc.

Step 1:

The first thing to do is attach all of the LED's to the board. I arranged them so that each LED takes up a 2x2 square of holes on the board with the legs of the LED on a diagonal. Also they should be arranged so that all of the anodes are lined up vertically in each vertical row. In other words always orient the LEDs in exactly the same way with the short wire going through a hole and the long wire going through the next hole diagonal to the first.

I used three different colors, 14 of each, since I am anticipating using it to analyze sound frequencies and volumes at some point in the future (I have some other cool plans for this but I don't want to ruin the surprise just yet.)

Once all of the LEDs are soldered onto the board and the excess wire clipped off you can turn to the next step.

Step 2: Now Hook All of the Anodes Together

Now simply take a piece of wire, strip the insulation off of it, and then solder it down a vertical row. This attaches all of the anodes together of the 6 LED's in that row. Repeat this for each of the 7 rows.

Step 3: Now Hook Up the Cathodes in a Diagonal Pattern

In the first picture you can see a diagram in my notebook of what we are constructing. You want to start at a vertical bar and then solder all of the cathodes together on a diagonal. This is a bit tricky to solder since you need to jump over each vertical bar as you go across. I have found the best way, as shown in the second picture, is to strip your wire so there are enough little pieces of insulation to insulate each time you go over a bar.You solder, then slide a piece of insulation over, then solder the next cathode, and so on.

When you are finished you should have all of the anodes soldered together in vertical columns and all of the cathodes soldered together along diagonals. Note that if you are having trouble imagining how this works for any of them other than the main diagonal, just follow a given smaller diagonal you will see that it starts on a cathode, jumps from cathode to cathode and ends on a vertical bar, then follow that bar all the way up and then continue hopping along the diagonal until you reach the final cathode.

Step 4: Attach a Header to the Board

Now solder a header onto the board so that you can conveniently plug in leads from your microcontroller.

Attach resistors to each pin of the headers. I would use from 220 ohm to 320 ohm or so in order to make sure your LEDs function correctly.

Then wire it so that each of the vertical bars is wired to a separate resistor (which is itself wired to a header pin.) Make sure you wire them in order so that it is easier to code (i.e. you can then use for loops and the like to loop through the rows and columns in a convenient fashion.)

Once the headers are all hooked up you are done!

You should now take a multmeter set to the diode function and test it. Or you could take an arduino, write a quick bit of code to turn on pin 13 for example (like `blink' without the blinking part) and then take a wire from pin 13 and a wire from GND and stick them in the header slots and see if you can get each LED to turn on separately. If more than one comes on or none comes on at any point then you may have a short somewhere in your soldering job.

Now that you know they all work you could attach each of the 7 leads to a different digital output of your microcontroller and then write some code to turn them on and off.

For example, to turn on the bottom left hand corner (green LED in my set up) you would need 0V going to the first header slot, 5V going to the second one, and all the others are DISCONNECTED. This means that those other pins must be set as INPUT pins on your arduino or other microcontroller. I.e.

pinMode(2, OUTPUT);

digitalWrite(2, LOW);

pinMode(3, OUTPUT);

digitalWrite(3, HIGH);

for(int i = 4; i <=8; i++) pinMode(i, INPUT);

Step 5: Videos Showing a Test Program

The first video shows a test program I wrote for an Arduino where I have the header leads connected to digital pins 2 through 8 and I loop through them in such a way to show that I can control each LED individually.

The second video is the same thing only I am using an Atmega329p chip on a breadboard to control the LEDs.

I should mention that the usual way that you see people doing Charlieplexing and my verticals/diagonals method are topoligically equivalent... I leave the proof as an exercise for the reader :)

Step 6: Sample Code and Final Video

Here is a sample library that will map to x and y coordinates so that you can more easily code stuff and then you can use it for a multitude of applications like mapping sound frequencies and volumes to the x and y coordinates to make a graphic equalizer, or as I have done in my sample code below you can scroll a message across the screen like one of those signs you see everywhere, or anything else you can dream up.


// This is a function called led(x,y,z) which will turn on or off
// the led at coordinates (x,y) on my spectrum array. For example
// map(1,1,0) will turn off the LED at grid position x=1 and y=1.
// filename: array_pinmap.h
// First define which board pins you connected to the 
// spectrum array header. From left to right.
#define PIN_1 2
#define PIN_2 3
#define PIN_3 4
#define PIN_4 5
#define PIN_5 6
#define PIN_6 7
#define PIN_7 8
void led( int x, int y, int z) {
    int Y = 0;
    if (z == 1) z = OUTPUT;
    else z = INPUT;
    switch(x){
    case 1:
        pinMode(PIN_1, z);
        digitalWrite(PIN_1, 0x0);
        break;
    case 2:
        pinMode(PIN_2, z);
        digitalWrite(PIN_2, 0x0);
        break;
    case 3:
        pinMode(PIN_3, z);
        digitalWrite(PIN_3, 0x0);
        break;
    case 4:
        pinMode(PIN_4, z);
        digitalWrite(PIN_4, 0x0);
        break;
    case 5:
        pinMode(PIN_5, z);
        digitalWrite(PIN_5, 0x0);
        break;
    case 6:
        pinMode(PIN_6, z);
        digitalWrite(PIN_6, 0x0);
        break;
    case 7:
        pinMode(PIN_7, z);
        digitalWrite(PIN_7, 0x0);
        break;
    default:
        break;
    }
    if((x-y) == 0) Y = 7;
    else if((x-y) > 0) Y = x-y;
    else Y = 7-y+x;
    switch(Y){
    case 1:
        pinMode(PIN_1, z);
        digitalWrite(PIN_1, 0x1);
        break;
    case 2:
        pinMode(PIN_2, z);
        digitalWrite(PIN_2, 0x1);
        break;
    case 3:
        pinMode(PIN_3, z);
        digitalWrite(PIN_3, 0x1);
        break;
    case 4:
        pinMode(PIN_4, z);
        digitalWrite(PIN_4, 0x1);
        break;
    case 5:
        pinMode(PIN_5, z);
        digitalWrite(PIN_5, 0x1);
        break;
    case 6:
        pinMode(PIN_6, z);
        digitalWrite(PIN_6, 0x1);
        break;
    case 7:
        pinMode(PIN_7, z);
        digitalWrite(PIN_7, 0x1);
        break;
    default:
        break;
    }
}

And here is a sample implementation of the above which will cause a circular target to move across the led array. Note that you will have to modify it to run on your arduino if you are using the java IDE. I think it will be pretty clear how to do it. I have attached a video showing the result of running the code. I think if you have gotten this far you can see that there are limitless ways to use this tool and it is quite easy to modify everything to make one that is smaller or larger.

#include "./array_pinmap.h"
#define DELAY 2     // number of milliseconds to turn on each LED
int main(void) {
  while(1){
        for(int j = 12; j>=1; j--){
                if(j>6){
                    led(j-5,4,1);        
                    _delay_ms(DELAY);
                    led(j-5,4,0);        
                    led(j-5,3,1);        
                    _delay_ms(DELAY);
                    led(j-5,3,0);        
                }
                if(j>5 && j<12){
                    led(j-4,5,1);        
                _delay_ms(DELAY);
                    led(j-4,5,0);        
                    led(j-4,2,1);        
                _delay_ms(DELAY);
                    led(j-4,2,0);        
                }
                if(j>4 && j<11){
                    led(j-3,6,1);        
                _delay_ms(DELAY);
                    led(j-3,6,0);        
                    led(j-3,4,1);        
                _delay_ms(DELAY);
                    led(j-3,4,0);        
                    led(j-3,3,1);        
                _delay_ms(DELAY);
                    led(j-3,3,0);        
                    led(j-3,1,1);        
                _delay_ms(DELAY);
                    led(j-3,1,0);        
                }
                if(j>3 && j<10){
                    led(j-2,6,1);        
                _delay_ms(DELAY);
                    led(j-2,6,0);        
                    led(j-2,4,1);        
                _delay_ms(DELAY);
                    led(j-2,4,0);        
                    led(j-2,3,1);        
                _delay_ms(DELAY);
                    led(j-2,3,0);        
                    led(j-2,1,1);        
                _delay_ms(DELAY);
                    led(j-2,1,0);        
                }
                if(j>2 && j<9){
                    led(j-1,5,1);        
                _delay_ms(DELAY);
                    led(j-1,5,0);        
                    led(j-1,2,1);        
                _delay_ms(DELAY);
                    led(j-1,2,0);        
                }
                if(j<8){
                    led(j,4,1);        
                _delay_ms(DELAY);
                    led(j,4,0);        
                    led(j,3,1);        
                _delay_ms(DELAY);
                    led(j,3,0);        
                }
        _delay_ms(50);   // delay between frames as you move across the screen.
        }
    }
    return(0);
}
Microcontroller Contest

Participated in the
Microcontroller Contest

Tech Contest

Participated in the
Tech Contest

Make it Glow!

Participated in the
Make it Glow!