Software apps and online services
The goal of this project was to familiarize myself with RGB LEDs and the use of pulse width modulation (PWM) to control the overall brightness of an LED as well as its color composition.
If you're unfamiliar with PWM or duty cycles, I suggest you take a look at my write-up about them to get a deeper understanding of how things will be working in this project. PWM is used to simulate analog signals in order to allow LEDs to output a variable brightness.
I started off by trying to dim a single LED before delving into more complicated things. In order to accomplish this, I built an LED circuit as seen in the schematic below.
I controlled the brightness of the LED by modifying the duty cycle of the PWM pin. After setting up the code to supply an output signal to pin 3, I used the function analogWrite() to set the duty cycle. The function accepts integers from 0 to 255, which correspond to duty cycles of 0-100%. To test that everything works, I tried a 100% duty cycle, and saw that the LED was glowing quite brightly. Reducing the duty cycle to 50% (127) saw a noticeable reduction in brightness. You can see this code in the attachments below.
I still had a button wired up from my project on debouncing buttons and switches, so I decided to include it in this design as well. I set up the code to have the Arduino gradually reduce the brightness with every click until the LED was off, and then to start over. This code is in the attachments.
By setting WaveForms Live to trigger on the falling edge of the button signal, I was able to capture the PWM duty cycles change.
You'll notice in the screenshots below that the change in duty cycle isn't instantaneous. Instead, there is a stabilization period during which the duty cycle is somewhere between the previous and new values. This doesn't matter with LED brightness, but other PWM applications may see unwanted behavior due to this effect.
RGB LEDs are actually 3 LEDs built into a single compact package. They closely resemble regular LEDs, except they have 4 legs instead of 2. The long leg is the common anode or common cathode, depending on which type you have, and the other three are connected to each color the LED can output: red, green, and blue. Typically the short leg that is separated from the others is red, the middle is green, and the outside is blue. Refer to the image below.
To configure the circuit for controlling the LED color, I needed to have individual PWM pins attached to each of the colors. By varying the relative brightness of each of the three component colors with PWM, the LED can create a wide range of colors, spanning the visible spectrum. As with the red LED earlier, Arduino pin 3 is attached to the base of the transistor. However, this time it is functioning only as an on/off signal. The PWM signals, and thus the brightness of each LED, will be controlled by the three pins connected to the color legs of the LED. See the schematic below.
Note: since my RGB LED is a common anode, its response to the PWM signals is inverse - a 100% duty cycle would cause the LED to be constantly off, and a 0% duty cycle would cause it to be constantly on. If the LED is a common cathode, it would function like a regular LED, with a 100% duty cycle causing it to be on.
Running all three colors at full brightness (0% duty cycles) made the LED painfully bright, but it did demonstrate that it can create white light. I wanted to make the LED display any color I wanted, but at a consistent, viewable brightness. To make the brightness consistent regardless of the color being generated, I needed to have the same total amount of power supplied to the three colors in the LED even as the as the color ratios changed.
I found that the best way for me to think about power was in terms of a value out of 255. Then, I need to pick a sum of duty cycles, shared by the three colors. For example, if I made the sum of the duty cycles 100 (out of 255), and wanted a white light, I would set each color to 33. This would be the same brightness as if I set the red to 100 and the other two to 0, or made yellow with 50 red, 50 green, and 0 blue.
Ultimately I found that a total out of 30 made for the best viewing brightness.
To test my understanding of the color control, I had the code cycle through the 6 base colors of the rainbow, based off the RGB values listed in the Simple English Wikipedia article about rainbows. Here are each of the colors, normalized to a duty cycle sum of 30.
At this point I realized red was over-represented in most of the colors. In the pictures above, you may have noticed the yellow had a red tint to it, even though red and green are supposed to be equally represented in that color. I set the Arduino to output a yellow color, and, according to print statements in the code, both pins were receiving the same PWM duty cycle command. I decided to check the signals with the OpenScope to see what was really going on.
Looking at the signals with an oscilloscope revealed that the duty cycles were indeed equal, but the voltage drop across the LEDs was not the same. This prompted me to look up a datasheet for an RGB LED, where it became apparent that my problem was stemming from the fact that my green and blue LEDs were not receiving the same amount of current as the red. Since green and blue LEDs have a larger voltage drop than red, they require a smaller resistance to have the same current flowing through them. With 150Ω resistors on all three, I had about half the current flowing through blue and green as red.
After putting in correct resistances (approximately 55Ω for each green and blue, 110Ω for red), I took pictures of the rainbow colors again. As you can tell, the colors are more balanced, namely the orange and yellow don't have a red tint.
Finally, I wanted to be able to make the LED output any color, based on a mixture of the red, green, and blue components. I set up three potentiometers to function as knobs, putting them into voltage dividers with 10kΩ resistors. Using the analog input pins to measure the voltages in the dividers, the Arduino calculates the ratio of the three colors and sets the PWM duty cycles based on the brightness discussed above. This allowed me to twist the knobs and get the ratio of the three knobs expressed as the color that ratio generates.
Below are WaveForms Live screenshots of the red and green PWM signals as I change the ratio from 1:0 (red) to 1:1 (yellow) to 0:1 (green). As you can see, the sum of the two pulse widths remains the same as the ratios change. By using cursors it can be ascertained that the pulse width sum is 240µs. The top line is the red signal and the bottom line the green signal.
The schematic below shows how to wire up the potentiometers, and code to control this circuit is included in the attachments section. The code for the rainbow and color selection modes is all in one file. To choose between these two modes, just change which function is commented out.