Tiny Color Mixer - a constant-current, 3W RGB LED with low-battery indicator and polymorph diffuser

Picture of Tiny Color Mixer - a constant-current, 3W RGB LED with low-battery indicator and polymorph diffuser

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.

Remove these adsRemove these ads by Signing Up

Step 1: Build & Program It

Picture of Build & Program It
Tiny3W schematic.tiff
Tiny3W board.tiff

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.

simonc811 days ago

Hi, I was wondering, are you because of introducing R2 not changing the voltage drop over R4 from 1.25V to less than 0.01V and thus changing the forward current through R4?

Mark Rehorst9 months ago

Nice project, but I think you could do without the LM317s if your code was aware of the duty cycle and prevented exceeding limits. You could switch 5V directly into the LEDs as long as you keep the average current at or below 350mA- most LEDs can tolerate 5X normal current spikes if they are kept short (in this case, a 20% duty cycle will give average current of 350mA and normal brightness). Your circuit would become a uC and 3 MOSFET switches. Efficiency would be higher because the MOSFETs have near zero on resistance and switch very quickly. No heatsinks would be needed. If you want to get really fancy, you put in a small resistance to monitor LED current and the thing could adjust the duty cycle limits on the fly, so as the battery drains and voltage drops the duty cycle could be increased to maintain constant brightness.

I used a PIC and RFP30N06 to switch 15A current spikes (from a 15V supply) through a 5W LED for a stroboscopic microscope illuminator. By carefully limiting the duty cycle the thing will run for hours on end only getting warm to the touch.

markmoran (author)  Mark Rehorst9 months ago

Thanks, Mark. That sounds really intriguing, but I'm not sure I understand how to do it. If I follow correctly, you're saying that besides using the duty-cycle to control the brightness (and thus shade) of each LED, I can also set the overall PWM rate to be fast enough that each LED never sees more than 350 milliamps at a time anyway, or at least not enough so that it burns out? So I could get rid of the LM317s and the resistors and just use the 2N7000 to turn them on and off directly? Would I need a power MOSFET since the 2N7000 is only "rated" for 300ma, or would the same principle also protect the 2N7000?

I've read elsewhere you can drive a regular LED without a resister using a similar technique, although I don't know how fast the LED has to be turned on and off in order to make sure that it only is exposed to a given current. I assume there's a straight forward way to figure this out? (Sorry if there's an obvious answer, my only electronics knowledge is from reading hobby books over the past couple years.)

Thanks for the tip and would love to hear more.

If you're going to pulse an LED with current higher than the nominal rating, there are three limits to be concerned with. First, absolute maximum current should generally be limited to 3-5X the nominal current. This prevents destruction of the LED die by electromigration and burning the bond wires like fuses. Second, the maximum on-time of a high current pulse should be limited to prevent excessive heating of the LED die. I'm not sure what a maximum safe value is- keep the on-time short (maybe a few tens of ms max depending on the current) and you're probably OK. Third, duty cycle should be limited to keep maximum average current at or below the nominal rated current.

Duty cycle can be used to control brightness. If you're using 2X nominal current pulses and you only turn on the LED for 50% of the time, it will look like normal brightness provided you are flashing it fast enough so that the flashing is imperceptible. For example, on 1 ms then off 1 ms then on 1ms, etc. gives 50% duty cycle, and 100% brightness if you are using 2X nominal current because the average current IS the nominal current. It will flash 500 times per second which is imperceptible as flashing unless you're lighting up spinning objects. If you want to dim the LED, just increase the off-time. 1 ms on and 3ms off looks dimmer than 1 ms on and 1 ms off. A uC can easily control the timing of the pulses down to usec level so it is pretty easy to control brightness and therefore color of a 3 color LED..

Practically speaking, let's say you use a 12V battery for power. and you're driving a LED that drops 3.6V at the rated current of 350 mA. You want to ensure that the current through the LED can never exceed 4X 350mA= 1500mA. The LED will drop a little more voltage at the higher current (current is roughly an exponential function of voltage in an LED), assume 3.9V. 12V-3.9V = 8.1V 8.1V/1.5A = 5.4 Ohms. If you put a 5.4 Ohm resistor in series with the LED you can be sure the current won't exceed 1.5A. Now if you switch the LED on and off with a MOSFET switch you'll be switching 1.5A pulses through the LED. If you drive the LED with 25% duty cycle it will have an average current of 350 mA. The resistor will heat up, so you lose some efficiency by protecting the LED this way.

I don't know if you could get away with using the small MOSFET. I suggest you give it a try. The RFP30N06 cost $1 each at sparkfun.
darkarts9 months ago

pretty cool, can this project work with normal rgb led ? will be huge difference in circuit and code ? sorry for the noob questions , just faded and blinked the led and want to get the next level :D ,thx for sharing this

markmoran (author)  darkarts9 months ago
Thanks, darkarts. Yes, the build is much simpler with a normal RGB LED, and the code is exactly the same. A regular RGB LED needs just 20 milliamps per color, so you can drive it just as you would fade three regular LEDs. You don't need the LM317s to create a constant high-current and you don't need the 2N7000 transistors to turn the LM317s on and off. So the three pins that I have hooked up to the gate of the each 2N7000 would instead just hook directly to the red, green, or blue pin of your RGB LED.

The fourth pin of your RGB LED would be connected either to ground or your positive voltage, depending on whether it is a common-cathode or common-anode RGB LED. It doesn't really matter since you can drive either one with this circuit, the only difference is whether turning the knob left makes that color brighter or dimmer.

Between the AVR pins and the LED pins you need a resistor.  My circuit has 1K ohm resistors on PB0, PB1, and PB2, but you'd want much smaller, say 100 ohms each. Assuming your microcontroller is running at 5v, that would allow 30 milliamps to go in the red channel and about 20 milliamps to go into the blue and green, which would work fine. If you want them all to be at 20 ma, you could use 100 ohm resistors for blue and green and 150 ohms for the red.

i think i got it, what about injecting the code into the avr ? sorry as i told iam very beginner, i really appreciate your help

markmoran (author)  darkarts9 months ago

Here's the schematic from Dhananjay Gadre's TinyAVR book which uses a regular RGB LED. I tried to attach to my last reply, but the server wasn't allowing any file uploads temporarily. This schematic assumes a common-anode LED, but as I said, if you have a common-cathode one, the just assume the connection on the top of the LED in the upper-right that says VCC says GND instead.

As for programming the AVR, that's a bit longer of an answer. This instructable is partly about how to do high-voltage programming for this particular situation of wanting to disable to reset pin on an 8-pin AVR. But it's much easier to just use a bigger AVR and doesn't really cost any more if you're just making a few of something. If you're just starting out, I strongly suggest building and programming a bunch of circuits with an Arduino. That's how I learned a few years ago and it's a really fun and easy way to get introduced to a whole bunch of connects and fun projects, like driving motors and relays, etc. It also doesn't require any special equipment to program.

Once you're ready to get a little more under the hood and figure out how stuff is actually working, then I suggest programming AVR chips with an In-Circuit Serial Programmer (ICSP/ISP). The TinyAVR book I mention above assumes you are programming AVR chips directly and has some of this info. But even better is Elliott Williams' terrific new book, Make: AVR Programming, which goes step by step from the beginnings to some pretty advanced projects.


I've never heard of polymorph before, but it looks really fun to work with!

I found it on Sparkfun's website and thought it looked interesting. I then didn't do anything with it for two years and finally got around to trying it a few weeks ago. It's actually useful and does seem fun to be able to cheaply make your own hard plastic. I've read you can color it by adding food coloring or another dye. I haven't tried sugru yet but I imagine it has its own pros and cons. I think the final product is softer and more like rubber with sugru, rather than hard, stiff plastic with polymorph.

Also, sugru is completely opaque!

Verticees9 months ago

Looks fun!