June 23, 2011

GUI Controlled LED Matrix



I recently got an Arduino Uno, and it quickly became my favorite toy.  After learning the basics of how the platform operates, I became interested in interfacing the Arduino with personal computers.  After seeing a large number of LED matrix projects on Instructables and the rest of the web, the LED matrix seemed like a perfect project to attempt to interface with a computer.  






I chose to build a 3 x 3 matrix, because I thought it would be best to start small (and I did not have enough LED's for a larger one).  Also, 3 x 3 is about the largest size it is safe to power directly from the Arduino, without using an external power supply.  However, the design for the matrix and the software in this Instructable should be fairly easy to scale up to 8 x 8 or so, by using an external power supply and some transistors.




Unlike most of my projects, this one is not very hardware focused, so the materials list is not too long.  If you have played with an Arduino before, you will likely have all of these parts on hand.

To build the matrix, you will need:

  • Arduino microcontroller:  I used an Arduino Uno, but pretty much any will work.
  • 9 LED's:  Any sort should work.  I had some left over from my bicycle's spoke lights
  • 3 resistors:  These are to prevent the pins/LED's from burning out.  I used the 330 Ohm variety, but anything around there should work
  • A breadboard
  • 1 Foot of thin gauge electrical wire:  To connect the negative ends of the matrix to the breadboard
  • 6 breadboard jumpers
  • Soldering materials
To run the software:
  • A Mac or PC with the Arduino IDE and Python 2.6/2.7.  Unfortunately, I could not get Python 3 to talk to the Arduino, so you'll have to use python 2.

The matrix itself is fairly simple to build, and if you are building one as small as 3 x 3, it can be built without any sort of jig to align the LED's or circuitboard to hold the components.

To start out, bend the anodes (the longer leads) of all 9 LED's to a 90 degree angles, perpendicular to the plane the leads are on.  Then bend the cathodes (the shorter leads)  to 90 degree angles parallel to the plane of the leads.  Make sure the leads extend farther out of the LED before bending on the cathodes than the anodes.
Building the Matrix

Next, divide the LED's into groups of three.  Solder the cathodes of all three LED's together, so that the LED's form a chain.  The anodes of the chain should all stick out in the same direction.  Once you have done this three times, you will have three chains of three LED's.  Then you can solder the anodes of each chain to the anodes of the next chain.  If all your bends are 90 degrees, and you secure the LED's while you solder them, the LEDs' leads should form a nice grid.

Building the Matrix

Building the Matrix

Building the Matrix

Building the Matrix

Building the Matrix

Once all the LED's are soldered together, solder a resistor to the three anode leads that are not connected to other LED's.  Finally, solder a short length of wire to each of the three cathode leads protruding from the matrix.
For ease of construction and disassembly, I hooked the matrix up to my Arduino using a mini breadboard and breadboard jumpers.  I simply plugged the matrix into the breadboard by the three anode pins.  To attach them to the breadboard, I soldered solid metal leads to the ends of the cathode wires.  I used the leads that I clipped off the resistors.

I attached the leads to the Arduino in the following order:

  • Left anode:             Pin 2
  • Center anode:       Pin 3
  • Right anode:          Pin 4
  • Top cathode:          Pin 5
  • Middle cathode:     Pin 6
  • Bottom cathode:    Pin 7
Attaching the Matrix

Attaching the Matrix

Attaching the Matrix

The advantage of building the matrix to be controlled by rows and columns is that you do not need a pin to control every single LED.  The downside, however, is that certain LED's cannot be displayed simultaneously without lighting up other unwanted LED's.  To prevent unwanted LED's from lighting, the display must be multiplexed, wich takes advantage of an effect called persistance of vision (POV).    To use this effect, the Arduino will actually only light one row of LED's at a time, but it will cycle through the rows so quickly that the image will look solid.

Now, I do not know if there is a standard for how LED displays cycle through the rows/columns, but I wrote my POV controlling program from scratch.  If you go down to the basics, it works like this:

The Arduino's code contains a set of arrays (one could also use a single 2D array), one for each row, that indicates which LEDs in the row are activated.  The program scans through these arrays one at a time, and the Arduino lights only the LED's which are indicated in the one row.  It lights the LED's in the row by setting the pin for the row to "LOW" and the pins for the lit LED's to "HIGH."  Every cycle, the program also runs a function which gathers input over a serial connection.  Inputs are in the form of integers, which correspond to an LED on the matrix.  The matrix is arranged as such:

[0, 1, 2]
[3, 4, 5]
[6, 7, 8]
If the code receives the number "6" over serial, the state of the bottom left LED in the array is switched.
You can download the code for the Arduino here:

I programmed the program and GUI that control the LED matrix in Python, using the built-in Tkinter  graphics module.  The design of the GUI is very simple.  It contains nine buttons, each representing one LED.  When the buttons are clicked, they turn orange, and when they are clicked again they turn white.  As the buttons are clicked, they update the LED matrix in real-time.

In order for Python to communicate with the Arduino, it needs the Pyserial module.  Once this is installed, you can read and write to the Arduino over the serial connection.

In my program, whenever a button is clicked, the button calls a function which writes the number of the button to the Arduino.  Using that number, the Arduino figures out which LED the number corresponds to, and switches the state of that LED.

 When running it, there are a few things to note:

If you run the file in Windows, it is advisable to simply double click the file instead of opening it in IDLE (the python IDE) and running it from there.  Also, you will have to set the serial port to use within the code.  By default, it is set to 2, which corresponds to COM3 on Windows.
Mac users:  I have not tested the program on a mac.  Please let me know if there are any problems with it, so I can try to fix them.  Python sometimes behaves differently on Macs, especially when dealing with graphics stuff.


You can view or download the Python code here:


Programming the User Interface

Programming the User Interface

To test the matrix, plug it in to your computer, and download the program to it from the Arduino IDE.  Then run the Serial Monitor.  You can use the number keys, 0-8, to test each LED and make sure the program is running correctly.  Then you can run the Python GUI program.  Before you do so, make sure you have closed the Serial Monitor in the Arduino IDE, or the Python will not be able to connect over Serial, since the port is already in use.  When you quit the GUI, you can go ahead and connect to it in the Arduino IDE again, because the GUI closes its connection when it quits.

Have fun playing with your GUI controlled LED matrix!  I have found that it is almost infinitely entertaining to small children.  If you build your matrix with different color LED's, you can easily change the color of the buttons in the GUI to match your LED's, using hexadecimal color codes.  The section of the code that must be changed is clearly commented.

I would like to create a much larger 8x8 version of this matrix.  8x8 is the largest size you can build on an Arduino Uno without using shift registers or other controlling circuitry, other than some transistors for the power.  If you build one of these, please post pictures, and I will post them in this last step.  The construction of the matrix actually very little work.  Programming it took far longer, and I have already done that part for you. 

Using the Matrix, Conclusion

6 comments:

  1. Hey Ben, Did you happen to notice that your LEDs are not as bright as they would be if they were "statically" lit? I had built a test 2x3 matrix (just to test the water) and am finding that because I am flipping on and off my columns that the LEDs (to simulate what you call "POV") are not as bright. I think it has to do with how my approach is for the code.

    ReplyDelete
  2. The LEDs on mine are pretty much just as bright as when statically lit. Are you sending any information to over serial each cycle, for example using the Serial.println() function? Those commands seem to eat a lot of CPU time, which would significantly dim the display. Also, it may help to put a very small delay (5 milliseconds or so) between each cycle.

    ReplyDelete
  3. Nope, no serial as of yet. My loop looks like so (I'm still new to this, so take it easy! ;-) )--

    for(int i = 0; i < COL_COUNT; i++) {
    for(int j = 0; j < ROW_COUNT; j++) {
    if(patterns[0][j][i] == true) {
    digitalWrite(PIN_OFFSET + i, HIGH);

    digitalWrite((PIN_OFFSET + COL_COUNT) + j, LOW);
    }

    digitalWrite((PIN_OFFSET + COL_COUNT) + j, HIGH);
    }

    digitalWrite(PIN_OFFSET + i, LOW);
    }

    ReplyDelete
  4. Here is a general flow of this logic--

    - Loop through columns.

    - Loop through rows.

    - If the current LED is 1 (or "on") turn my anode high and my cathode low to allow flow for the LED to light up.

    - Immediately set the cathode to high to break flow (still same result if I break this out into it's own "turn all LEDs off" loop).

    - Set the anode to low to complete the column phase, next "i" loop iteration will be the next column to process.

    As I typed this out, I have a feeling that my issue has to do with how I am flipping the state of my leds. I can't exactly pinpoint it though :-(

    ReplyDelete
  5. Correct me if I''m wrong, but it looks like you are only lighting one LED at a time with that code. Rather than lighting one at a time, light an entire row (or column). I linked to the Instructable where I uploaded my code above, but here's the breakdown of how the loop flows. In mine, anodes = columns and cathodes = rows:

    For each row, it does the following, and then iterates through the rows:

    - For each LED per row, if it is supposed to be ON, set column pin HIGH. If supposed to be OFF, set column pin LOW.

    - Set the previous row pin to HIGH (if row 1 is the current one, the previous would be row 3. This turns off all the previously lit LEDs)

    - Set the current row pin to LOW (lighting all the LEDs set in the first step)

    - .005s Delay. (This helps a bit with the brightness. Also, you can set it to about .1s for diagnostic purposes, as at that speed you can see the progression.)

    Hope that helps!

    ReplyDelete
  6. Hey Ben,
    Thanks. I had to play around with the placement of the row phasing and the delay, but am able to get what I was looking for. Here is what I ended up with--

    void loop() {
    for(int i = 0; i < ROW_COUNT; i++) {
    int prevRow = ((i == 0) ? ROW_COUNT - 1 : i - 1);

    digitalWrite((PIN_OFFSET + COL_COUNT) + prevRow, HIGH);

    for(int j = 0; j < COL_COUNT; j++) {
    digitalWrite(PIN_OFFSET + j, patterns[0][i][j] == 1 ? HIGH : LOW);
    }

    digitalWrite((PIN_OFFSET + COL_COUNT) + i, LOW);

    delay(5);
    }

    ReplyDelete