Everybody needs a little color in their life! This color changer mixes light from high-power LEDs to create more than 16 million colors. A smooth auto-fader cycles the colors, or you can hook it up to a USB port and control it from your computer.
A great toy for architectural lighting, parties, and holidays. Since the circuit will run from 12 volts, it can even be installed in a car.
Learn how to build your own, after the fold.
All the files for this project are included in a .zip archive, you can download it here
This color changer borrows a well-known color model
used in TVs and LCD panels. These displays blend red, green, and blue light
to create a vast number of colors. Look closely at your monitor -- this image of the DIY Life site is made of tiny red, green, and blue dots. We'll mimic this technique by mixing light from red, green, and blue LEDs.
The easiest way to dim LEDs is to blink them and vary the ratio of on and off time. If the LED blinks fast enough, we perceive it as a solid light of lower intensity. This method of dimming is known as pulse-width modulation
(PWM). The figure below shows a single period in a pulse-width modulation cycle. At the start of the period, the signal is high (the LED is on) for the time defined as the duty cycle
. When the duty cycle is finished, the signal goes low (the LED is off) for the remainder of the period. Adjusting the duty cycle varies the brightness of the LED. By extending this to red, green, and blue channels, we can mix a nearly infinite number of colors.
We'll need some red, green, and blue LEDs to use with the fader. A possible way to group a bunch of LEDs is a small, round light board. This board is based on a design by Big Clive
, but I've fattened the traces and changed the routing to make the board a easier to etch and solder. See Big Clive
for his version. My design is part of the si-light project
I chose the Microchip PIC 18F2550 as the microcontroller for this project (IC1). It has a full-speed USB connection and a free firmware framework for a generic serial port to USB emulator. It's got a ton of program space for fancy, stand-alone fading programs. As far as support gear goes, we need a 0.1uF capacitor between the power and ground pins (C6), and a resistor and diode are needed for the ICSP programming header (R7,D1). The on-chip USB peripheral requires an additional two 0.1uF capacitors (C7,8) and a 20 MHz crystal (Q1)-- don't forget two 27pF caps for the crystal (C1,2). Crystals vary, but 27pF capacitors usually work.
The device should continue to run a nice color fading program when the USB isn't connected. This type of USB device is 'self powered' -- it has an external power source and runs independently of the USB connection. This setup requires one microcontroller pin to monitor the power line of the USB cable. When a cable is attached, the PIC senses a voltage and opens the USB connection. The USB power line is connected to the PIC through two small resistors (R8,9), in order to cut down on noise and protect the chip. I used 100K ohm and 10K ohm resistors, but any close values should work fine.
The PIC has two hardware PWMs that could be used to fade LEDs, but we need a total of three channels -- one each for red, green, and blue. We could use a hardware device, but with so much power in the PIC we can do it in software without the added expense.
A microcontroller pin is unable to power more than a few LEDs directly. Instead, the PIC will switch the LEDs with a transistor or MOSFET
(Q2,3,4). This diagram shows a simple LED circuit, and switching circuits that use a FET and transistor.
I used an IRLZ44 MOSFET, but there are many options. You should choose a FET that switches completely at 5 volts or less. The data sheet usually has a graph of operation over a range of switching voltages (Vgs). A FET with a minimum gate voltage of 12 volts will never turn on when switched by the PIC running at 5 volts.
You can also use a transistor to switch the LEDs.A transistor requires an extra current-limiting resistor (R4 in the figure above), whereas a FET doesn't. FETs are preferable, but we'll put a spot for resistors on the circuit board, just in case (R3,4,5). Those of us with FETs will jumper over those dirty resistor holes. Transistor people, use a 1K resistor here.
The PIC has a serial port (USART) that requires no additional hardware. This is exposed on the pins so that the device can also take serial commands from a PC or another microcontroller.
Three small LEDs show power, USB, and serial status. Note that the LEDs are the small 3mm variety, not the more common 5mm variety. The circuit runs at 5 volts, so a 330 ohm resistor will suffice for the LEDs (R1,2,6).
This circuit requires two power supplies, one for the microcontroller and one for the LEDs. The microcontroller runs at 5 volts, which is provided by a common 7805 regulator (IC2). The 7805 needs a 0.1uF decoupling capacitor between each power pin and ground (C9,10). Make sure that the capacitors on the supply side of the 7805 (C9) are rated for double your intended supply voltage -- I used an 18 volt wall wart and capacitors rated for 50 volts. The TO220-size part (IC2) is usually good for 1-1.5 amps. This is overkill! Only a few hundred milliamps are used, but smaller regulators don't leave any room for expansion and get uncomfortably hot when the supply voltage is high.
The example light board uses two strings of two green and blue LEDs, and one string of four red LEDs. The red string requires 10 volts, and the green and blue strings need 6.6 volts. A 12-volt supply is perfect for this circuit, with a 220 ohm resistor on the red string and a 270 ohm resistor on the green and blue strings. The 12-volt supply is provided by a 7812 (IC3).Many voltages will work, just calculate
the correct LED resistor. Make sure that the 0.1uF decoupling caps (C3,4) and supply filter capacitor (C5) are rated at least double your intended operating voltage.
Download a full-sized image of the schematic.
The circuit and PCB are made using Cadsoft's Eagle Layout Editor. A freeware version of Eagle is available for download
. This is my first project for DIY Life, so I decided to do an all through-hole design. Most unused pins are routed to headers for maximum expansion possibilities.
There are two jumper wires on the board. The jumper from the LED voltage supply regulator to the connector wouldn't route well on single-sided board. This will be an ugly jumper if you make a single-sided board, like I did. Another jumper connects the USB power line to a PIC pin.
There are additional vias on the ground plane near the MOSFETS. If you plan to connect a bunch of LEDs, solder some wires here to reinforce the ground plane. These vias could also connect to a thick ground plane on the top layer of a two-sided board. If you connect a LOT of LEDs, move the FETs to a separate board and add heat sinks.
- C1,2 - 27pf
- C3,4,6,7,8,9,10 - 0.1uf/50V
- C5,11 - 22uF/50V
- D1 - 1N4148
- IC1 - PIC18F2550 28DIP + 28 pin DIP socket
- IC2 - 7805TTO220H
- IC3 - 7812TTO220H
- SERIAL - strip of 4 pin header
- ICSP. PORTA - strip of 5 pin header
- LED1,2,3 -LED 3MM
- Q1 - 20MhzcrystalHC49U-V
- Q2,3,4 - IRLZ44 MOSFETTO220BV
- R1,2,6 - 330R (330 ohms)0.25 watt
- R3,4,5 - 1K (1000 ohms) 0.25 watt
- R7 - 10K (10,000 ohms) 0.25 watt
- R9 - 100K (100,000 ohms) 0.25 watt
- USB- Female, B style USB Connector, PCB mount
- X1,3,4- screw clamp (2 sockets per block)
The firmware is compiled in Microchip's MPLAB with the PIC C18 compiler. MPLAB is free, you can grab it here
. Evaluation and free student editions of the C18 compiler are available for download here
. A compiled .hex file, ready to program to a PIC, is included in the project archive. If you want to compile the project yourself, see the instructions at the end of this article.
Software Pulse-Width Modulator
The software-based pulse-width modulator creates a dimming effect by blinking LEDs very quickly. The PWM has a period (total time) and a duty cycle (the 'on' time). Each period of the pulse-width modulator is broken up into 255 time segments of equal length. These 'slices' are tracked with a one-byte counter, which conveniently counts to 255 and resets to 0. At the beginning of slice 0, all LEDs are on. At the beginning of each time slice, we check the desired light intensity settings against the counter value. If the counter is equal to the intensity level, then the LED is turned off. For example, if we want 50% blue (126 parts of 255) and the counter hits 126, the blue LED is switched off. This comprises the duty cycle. The actual switching is done on a buffer in memory, and then placed on all output pins at once. This ensures that channels set to 0 are always off, and that all switching happens simultaneously.
Why all this 255 stuff? A byte in a microcontroller is capable of storing a number from 0-255 (256 levels). We track the time slices with a byte and store the desired intensity levels for each channel (RGB) in a byte. Thus each color channel has 255 possible intensity levels.This is a well-established color storage method known as 24-bit color
. You might recognize this if you've worked with web page colors or a photo-editing program
. 255 brightness levels per color yields 16.7 million color combinations! We could expand everything to be 10, 12, or even 16 bits, giving about 65 thousand intensity levels per channel. This is silly, though, because 16.7 million colors are far more than the human eye can perceive
. Using a 24-bit color representation also maintains compatibility with common color picker color codes used by computers.
The PWM code is time-sensitive. If a cycle is missed, the color-mixing effect will be ruined. We can achieve this exact scheduling with a hardware timer and alarm. The timer is set at the beginning of each time slice. When the alarm sounds, the PIC immediately stops whatever it's doing and processes the PWM code. On a computer or microcontroller this alarm is called an interrupt
Although the software-based PWM has priority, it can interrupt time-sensitive USB activities. It's important that the code for processing the interrupt is as short as possible, and the time between interrupts be as long as possible, in order to prevent flaky USB connections. The microcontroller is running at 12 million instructions per second, on a 48 Mhz clock, so we have a lot of processing power to work with. I could have done some calculations to find a good setting for the timer, but I just adjusted it until it looked right.
The PWM code is fairly easy to use and is well-documented in the source (see user.c). The desired brightness setting is put into the SoftPWM.R/G/B variables. The soft PWM is double-buffered -- this means that the new values are not directly used. Instead, we set an update flag (SoftPWM.UPDATE) and then the new values are copied into the working variables on the next interrupt. Double-buffering prevents erratic behavior (such as irregular flashing) if an interrupt occurs while the auto-fader is in the middle of changing colors.
The auto-fader program runs when there is no USB connection. It cycles between a pallet of colors stored in an array. This simple fader has lots of room for improvement. You can add pallets or change the pallet. It was ported from BASIC source code used in the si-light project
When a USB connection is enumerated, the auto-fader stops and the device waits for commands from the PC. The protocol for setting the color is quite simple: values for red, green, and blue channels are sent, separated by a space, and followed by a full newline
(CR+LF, 0x0D 0x0A).
Set all colors to 100%
Set all colors to 0%
Set to a color (e.g., purple)
We're sending ASCII values to the virtual serial port, not a true byte value. Rather than sending the value "255", we send the ASCII sequence "0x32,0x35,0x35". This means we can input values using a terminal program, but each sequence needs to be converted to an actual byte-based decimal value on the PIC. Refer to the source code to see exactly how this is done. When a full command sequence is successfully received, ASCII 0 (0x30) is sent on a new line.
All low-level USB operations are handled by the Microchip Full Speed USB Firmware, which makes USB development much easier. See the USB specification and Microchips framework documentation
[pdf] for further info.
Microchip offers both a Human Interface Device
(HID) firmware and a communications device class
(virtual serial port, or CDC) firmware. Both are generic protocols, already supported by many operating systems (including MS Windows). The HID driver is used in devices like keyboards, mice, and joysticks, where data primarily flows from device to computer. We want to send data from the computer to the device, so the CDC driver is a better choice. A CDC device appears as an additional serial port
on your computer. Any program that works with a serial port can send color data to the device. The software will never know that it's talking through USB instead of an old serial cable.
Programming the PIC
See how I program the PIC, and build your own programmer, in my PIC programming tutorial
The PIC is a through-hole (DIP) chip, so it's possible to program it in a socketed programmer
. All of the pins needed to program the PIC are brought to a header, so in-circuit programming and debugging
(ICSP) is also possible. To learn more about programming a PIC, read some of the PIC programming tutorials linked at the end of this project.
Connecting to a PC
Warning -- you are about to connect something you cooked up in your shed to a delicate PC with lots of data... are you sure you want to do this? Use a junk computer or a USB hub with galvanic isolation
Windows Connection Procedure
Testing the USB connection
- Connect the color changer to a power supply before connecting it to a PC. The circuit is not designed to draw power from the USB port.
- The auto-fader will start when the device powers up.
- Plug in the USB cable.
- Windows will prompt you for a driver file. You don't really need a driver, just a file that associates the device with a driver that's already part of Windows. Microchip provides this as part of the USB framework; it's in the project archive or you can download it here. Navigate to the location of mchpcdc.inf and choose it as the driver, click OK.
- Windows will recognize the device and add it as a serial port to your computer.
- To see the device's assigned port, go to the windows control panel, click the system icon, choose the hardware tab, click device manager. Expand the "port" listing and verify that you have a new COM port. Note the COM port number, because you will use it in the terminal test.
Using a simple terminal program to send a few settings to the device is an easy way to test the USB connection. Windows Hyperterminal will work in a pinch. The project archive contains a saved Hyperterminal session so you don't have to do all the steps below-- just double-click to load Hyperterminal with the correct settings. You still need to go to File->Properties and change the "Connect to" port to the proper setting for your computer.
- Open Windows Hyperterminal, usually found in the "Communications" folder (part of the default Windows install).
- Create a new connection-- Hyperterminal may prompt you for a new name.
- After naming the connection you will be prompted for connection details. Change the "Connect Using" drop-down to the new COM port that was added when you connected the device. Click OK.
- Next, enter the port settings. You can choose any speed, and the USB driver will sort everything out in the background. Change "Flow Control" to none. Click OK.
- Next, configure the correct newline characters. Go to Files->Properties. Click the "Settings" tab. Click "ASCII setup". Tick the top two boxes: "Send line ends with line feeds" enables a proper newline, and "Echo typed characters locally" lets you see what you're typing as you type it. Click OK and then click OK again.
Now, send some light intensity commands to the device. Enter intensity levels for red, green, and blue as ASCII characters and finish by pressing Enter. To set all the LEDs to full, type:
and press Enter. All outputs should go to 100% and the device will respond with '0' on a new line.
Next, turn all the lights off. Type:
and press Enter. All outputs should go to 0 volts. The device will again respond with '0' on a new line.
Finally, disconnect the USB cable. The auto-fader program will resume.
So you want to fidget with the code? Here's the deal--
The Microchip USB driver comes as an install package. Its not easy to transfer an existing project to your computer and get it working correctly. This is the absolute best method I've found to get the source up and running. Its seems involved, but it actually takes less than 60 seconds.
Software you'll need
MPLAB (I used 8.01) (installed).
PIC C18 Compiler (I used 3.15) (installed).
Microchip USB source code install package (this project based on version 1.2).
The replacement files included in the project archive. These are already in the proper directories so they can be copied over the Microchip USB source.
Install the framework
- Install the Microchip USB source code (version 1.2).
- Open the replacement file archive and extract the directories over the Microchip USB source code. The directory structure is contained in the archive so that all the files go to the proper place. If Windows prompts, choose 'yes' to overwrite the existing files. If you'd like to copy the files by hand, these are the files that you need to replace:
Update the project settings
- Linker files for the 18f2550, use the 'I' version when using a debugging tool like the ICD2.
- Modifications: Set custom USB sense PIN, LED PINS.
- Modifications: Disabled USB power mode, enabled self power mode.
- Modifications: Disable sleep mode on USB disconnect.
- Modifications: Software PWM, color auto-fader,USB interface.
Taking it further...
- Open the MPLAB Workspace file installed with the USB source code (MCHPFSUSB.mcw).
- Find the Project window in MPLAB -- it should say MCHPFSUSB.mcw at the top and contain a list of files. Remove the unnecessary file 'temperature.c' from the source files list, it will cause a compile error.
- Now scroll down past header files to the linker script folder. Remove the linker script for the 18F4550 (right click, remove). Replace it with the 18F2550 version included in the replacement files (right click, add).
- Now update the device used in the project. From the MPLAB top menu select Configure->Select device. In the device menu choose the 18F2550. Click OK and you're done.
This design leaves plenty of room for new functionality to be added through firmware upgrades, or by adding new hardware to the various headers. A fader program with multiple color pallets and buttons for speed/pallet selection is an obvious upgrade. The serial port is exposed, but unimplemented -- with this port the board can communicate with another microcontroller or a PC serial port. Analog-to-digital converters on the upper pins of PORTA are exposed on a header -- these can measure the output of a preamplified microphone for beat detection based color mixing.
Have fun mixing colors, and stay safe
New to electronics? Here are some introductory tutorials to help you get started.
Eagle CAD tutorials
Draw Circuits with Eagle
Turn your Eagle Schematic into a PCB
Eagle Design Rules
Create a Custom Parts Library
Make circuit boards
How to Solder
Sparkfun Soldering Basics
Microchip's PIC microcontroller
PIC In-Circuit Serial Programming
The original JDM2 Programmer
Business Card PIC Programmer
Multi-Socket PIC Programmer
USB PIC Programmer