Thursday, September 22, 2005

Fun With an RGB LED!


So I bought this RGB LED (Red,Green,Blue Light Emitting Diode) from Digikey, one of the better online electronics suppliers. It comes in a rather interesting package a 6-pin DIP instead of the typical elongated hemisphere normally associated with LEDs. There are three cathodes and three anodes making each LED entirely independent from the other electrically, yet they share a common space physically, allowing for more flexibility electronically but also for good mixing of the colors.

This is all well and good, and a very interesting little piece of electronics, but - what good is it? Well - you may recall that the primary colors of light are Red, Green, and Blue - which, not coincidentally are the colors in this LED. So, by varying the intensity of the three elements of the LED, any visible color can be created. I decided that the best way (or, should I say the easiest...) to accomplish this feat would be to use three of the digital output lines of the parallel port of a PC. This works well for turning each element on and off, but does not allow for different intensities - remember, it's a digital output port. How to accommodate this feature then? Three words: pulse-width modulation (PWM). Basically - you can simulate different intensities by moving the LED from high to low really really fast. This is where we move from the hardware side to the software side.

For software, I just used my old standby for DOS programming, Microsoft QuickBASIC 4.5. Please, hold the laughter if you know about this "language" already - it works fairly well for doing this sort of thing and allows for reasonably rapid testing using the interpreter. This does, however, lead to some speed limitation, as the interpreter and even the compiled output are not terribly fast even on a good machine. Due to this limit, I can only do about 32 different levels per segment for a total of 32x32x32=32,768 different colors. I think that using a different language, such as C++ and inline assembly code I could take this a little higher and provide smoother looking output from the LED - as it is, you can definitely see some blinking going on in the lower intensities from the PWM.

Here's the code for a program that causes the LED to go through a few of the colors it is capable of - the visible spectrum in one intensity:

DECLARE SUB led (r, g, b)
DECLARE SUB lednum (col)

DO
FOR c = 0 TO 96
lednum c
NEXT c
LOOP WHILE INKEY$ = ""

led 0, 0, 0


SUB led (r, g, b)
opt = 0

r2 = 65 - r
g2 = 65 - g
b2 = 65 - b

FOR x = 1 TO 64
IF x MOD r2 = 0 THEN opt = opt + 4
IF x MOD g2 = 0 THEN opt = opt + 2
IF x MOD b2 = 0 THEN opt = opt + 1
OUT &H378, opt
NEXT x
END SUB

SUB lednum (col)
IF col > 0 AND col <= 32 THEN led col, 0, 32 - col
IF col > 32 AND col <= 64 THEN led 63 - col, col - 32, 0
IF col > 64 AND col <= 96 THEN led 0, 96 - col, col - 63
END SUB


The function led takes the Red, Green, and Blue intensities as input and has a (I'm thinking rather inefficient, but haven't messed with it much yet) loop for doing the PWM and sending the output to the first three data lines of the parallel port. The function lednum takes a single color value for input ranging from 1 to 96 (32*3) and converts this number to the RGB value of the color at that point in the visible spectrum (ie: 1 = red, 32 = green, 64 = blue; other number are colors that fall between these). The main module just loops through all of these colors to show a spectrum until the user presses a key on the keyboard.

All-in-all this has been a fun and interesting project - I have learned some about color theory and how to change intensities with digital output. Future plans for this project include possibly using the sound card to convert the input level to a color, reds for loud, purples for soft to make an interesting color display to connect to a stereo, or possibly to use this as a way of expressing real-world data - stock prices, temperature, etc...

1 comment:

Dan W. said...

Follow up - found a slight change in the code that makes the PWM twice as fast and eliminates almost all of the "choppiness" that was visible in it. The new function for the function led (r, g, b) is as follows:

SUB led (r, g, b)
opt = 0

r2 = 65 - r
g2 = 65 - g
b2 = 65 - b

FOR x = 32 TO 64
IF x MOD r2 = 0 THEN opt = opt + 4
IF x MOD g2 = 0 THEN opt = opt + 2
IF x MOD b2 = 0 THEN opt = opt + 1
OUT &H378, opt
NEXT x
END SUB


(code is in italics instead of teletype, as the HTML tag for that is not allowed in comments...)