Lately I was playing with my dual color LED matrix from Sparkfun. It is a matrix of 8 by 8 dual color (red and green) LEDs that measures 5 cm by 5 cm. I just had some sprites flickering across the matrix as the magnifying glass of my “third hand” came in the way. I realized, that, if in the right distance, it will project the sprites on the ceiling. Although the projection is not very bright, it works, if the room is dark enough. Disco, here I come.
So here is, what you need to build one:
- Arduino, Boarduino from Adafruits for the breadboard
- Dual color LED matrix from Sparkfun
- 2 * 74HC595 shift register
- 1 * ULN2803 darlington sink driver
- 16 * 100R resistors
- 1 * 10kR potentiometer
- magnifying glass
The matrix is orgranized in 8 rows and 16 columns (8 red and 8 green). To address a single LED in the matrix, you have to set one of the 16 column bits and enable the coresponding row. Note that there is always only a single row active. If every row is activated fast enough, a steady picture comes into being. The shift registers are used to provide column data. 16 bits are are loaded serially and put out parallely.
The rows are handled by an ULN2803, an array of darlington transistors. This chip is used to sink the current of the activated row. If every LED in a single row is activated, the current for this row will sum up to 320 mA (16 * 20 mA). Definately too much for a single pin of a microcontroller. The ULN2803 is able to sink up to 500 mA per channel and cheap (about 30 euro cent).
To generate a steady picture, we have to provide 16 bit of data, at least every 2.5 msÂ (50 Hz * 8 rows). For this purpose the timer 2 of the ATMega168 is used. This timer normally controlls PWM channels 3 and 11 for Arduinos, so they are no longer accessible. The ISR (Interrupt Service Routine) for this timer takes the 16 bits for the current row and shifts them out. Next time it is called, it will output the data for the next row. Take a look at the great uc Hobby tutorial on Arduino interrupts for more details.
The sprites are organized in 8 bytes (8 * 8 bits). So every sprite can cover the whole matrix for a single color. The screen memory is organized as 16 bytes, 8 bytes for red and green. That way you can print a sprite in red or green. If you print it in red and green, the result is orange.
To control the sprites, I hacked a tiny script language. The scripts are arranged in small sequences. Every sequence consists of commands of one or two bytes. Available commands are:
- select page (none, red, green, orange)
- select sprite
- move sprite (up, down, left, right)
- print selected sprite and selected page
- call sub sequence
With the possibility to structure commands in sequences and subsequences it is possible to create more complex animation as with simple frame by frame animation. That may be handy if the memory is limited as it is for the ATMega168 with 16kB SRAM.
As you can see, the projection is not bright enough to show up on my camera. So I had to switch to “night mode”. That worked but lacked the speed of the animation. It looks much better in real.