Controlling an RGB LED is a simple and common microcontroller project, often the next project done after blinking and fading an LED.
To make this more interesting, I built it using an ATtiny13, one of the smallest and simplest AVRs, which required "high-voltage programming." I also used a 3W LED because I wanted to learn how to make a constant-current driver. Then I added a low-battery indicator, since that seemed like a useful skill for other projects, and mounted the PCB onto acrylic. (I'd never worked with acrylic and heard it was difficult to drill and cut, but had no issues with either.) Finally, I made a diffuser out of polymorph - I had tried polymorph a few weeks earlier to make the cover for my electronic candle, and I wanted more practice shaping it.
This was made from parts I had lying around. To buy all the components would be about $25, with most of that for the $15 high-power LED. Because this build was to practice with various electronics concepts, I'll use each step to discuss what I learned, hoping that information might be useful for one of your projects.
Step 1: Build & Program It
With the exception of the power regulation, this is essentially the same circuit repeated three times, one for red, green, and blue. Three of the ATtiny's pins - PB0, PB1, PB2 - are configured as outputs and are used to rapidly turn on and off a transistor using PWM, which in turn turns on and off the red, green, or blue LED attached to it. (An RGB LED is really just three LEDs mounted in a single package.) The other three pins on the ATtiny13 - PB3, PB4, and PB5 - are configured as inputs and run through the chip's analog-to-digital converter. Each pin is attached to a 10K potentiometer which acts as a voltage divider, providing from 0 to 5 volts depending on whether the knob is turned all the way left or right. The microcontroller converts this voltage to a value from 0-255, which it then uses to determine what percentage of the time the corresponding output pin is on, thus turning the blue knob's position into the blue LED's brightness, etc.
My Eagle schematic and board layout are attached, as well as the print-out of the board's traces which I used to etch the PCB. There are a few jumper wires on top of the board since I've yet to try double-sided etching. The three long wires from the POTs to the ATtiny are also shown on top of the board, although to make it look nicer, I put them on the back of the board using insulated wire.
The RGB LED comes mounted to a heatsink star, but Sparkfun's documentation says that if all three LEDs are fully on, then additional heat sinking is needed. Figuring I'd certainly want to turn all three knobs up and see how bright of a white light this can produce, I decided to attach the LED's star to a larger 1" aluminum square (1/8" thick). The LED isn't really attached as much as held in place by the six power wires, although I did place thermal compound between the two plates, which also keeps it in place.
The LM317's get pretty hot as well -- they are each dissipating around 2-watts -- so I screwed TO-220 heatsinks with thermal grease onto each of those as well.
The C source code is attached. Since the ATtiny13 only has two hardware PWM pins, the PWM here is done "manually." That is, every time the timer counter register overflows, the interrupt routine checks to see whether it's time to turn off the red, blue, or green LED. The chip is running at its default speed of 9.6MHz, which means the overflow interrupt triggers at 37.5KHz (9.6MHz/256), which means the PWM speed is only 146Hz (37500/256). There are ways to update this much faster, but I didn't see any reason to since 146Hz is still well above people's flicker fusion threshold.