Perhaps you’ve seen them, those displays that use light emitting diodes (LEDs) to illuminate some kind of graphic or message. Commonly seen at stadiums, stock exchanges, on top of buses, etc. Well, it’s really easy to make one of your own, which is the goal of this project. Here’s version 1:
Of course, it doesn’t have the resolution of commercially made ones – this one only measures 8 LEDs x 8 LEDs. You can still do some interesting things with it.
So how does it work? We’ll illustrate the principle by taking a small subset of the display, say a 3×3 portion:
How would you control this? Well you could say that you’ll simply connect each LED to an IO pin on your controller. So it would take 9 IO pins to drive just that portion of the display. Sure, that’s well and good for this example, but as soon as this project gets any bigger, you’ll realize you’ll quickly run out of pins. The Atmega328p has 13 digital out pins, clearly not enough for my 8×8 display, so how can we get around this? What if we let each row and each column be connected to a pin, something like this (and let’s make it more official looking):
How this will work is that when a column pin is ON, it will source current to that entire column. When a row pin is ON, it will allow that row to sink current (how it will do this will be explained in the schematic later). This is called multiplexing. If you give this a coordinate system, turning on a particular (row, column) pin combination completes the circuit at location (row, column) on the display.
Note that in this configuration, you can light a selection of LEDS on a particular row by turning on the respective columns, and turning on that row, OR you can light a selection of LEDS on a particular row by turning on the respective rows, and turning on that column, but you could not do both. At least not at the same time. It will also be hard to drive an entire column from one pin, since that means sourcing current an entire column. Suppose a maximum of 20mA per LED, a pin must somehow supply 20×3 = 60mA for a column, so we’ll want to avoid this.
Because a pin either sinks an entire row or sources an entire column, there is no way to simultaneously reference multiple rows and multiple columns, but what if we could make it LOOK like it? Here’s the basic idea:
Since you can’t drive the display as a whole, you can at best drive parts of it. We’ll assume that you drive multiple columns at a time, and only sink one row at a time. In our first image, we turn on columns 1 and 3, and we turn on row 1. Some split second later, we turn on column 2 and row 2. Yet another split second later, we turn on column 1 and 3 again, but row 3 this time. We repeat this many, many times, and if you do this fast enough, it will appear as if you are looking at the fourth image, though if you grab an oscilloscope or increase the delay, you’ll see this is clearly not the case. This is a result of a phenomenon called persistence of vision (http://en.wikipedia.org/wiki/Persistence_of_vision). In short, our eyes are not a perfect analog device. An image could last for a brief moment on our retinas. If the moment an LED is off is imperceptible to us, it will appear as if we are looking at the display as a whole.
You’ll notice in addition to the uC (an ATmega328p) there are two shift registers. Shift registers are an excellent option for increasing the number of IO pins on your controller. At a cost of a little delay, you can effectively drive 8 outputs with 3 pins. Each register controls a column/row set.
* I had to make a change to my schematic post construction. Each register has 8 outputs, QA through QH. The original schematic mapped the top register’s output like this:
output | H | G | F | E | D | C | B | A
column | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8
I did not pay attention when I was soldering, and I soldered the wrong columns to the wrong outputs. This is reflected on the diagram. It’s of minor consequence, but the original reason for the above mapping is so that you could write a function that would take 8 binary bits that directly correspond to the which columns you wanted on, and each digit would correspond to a column, e.g 10010011 means columns 1, 4, 7, and 8 are on. The mistake requires a software fix.
As for the registers that control the rows. A register pin can’t sink much more than ~35mA of current, so each pin routes each row to ground through a 3904 transistor. When a row register pin is high, it turns on the transistor and opens a path to ground. In software, the row register does nothing but repeatedly cycle through the rows 1-8. Another way to achieve this is through an IC called a decade counter, which has 10 pins, only 1 of which will be on at a time.
As a bonus, here is the display running some Game of Life (http://en.wikipedia.org/wiki/Conway%27s_Game_of_Life) simulations:
An 8×8 display is rather limiting, so this isn’t much good for anything other than a learning experience. I plan to make another one, at least several characters in length, more appropriate for a marquee. It will incorporate some user input so you could play some games on it, and FTDI so any user could send it a character string to display. I had fun with this, I hope people find this interesting as well.