RGB leds are fun and because they can be used in many projects I have decided to make a library to easily crossfade the colors of one or multiple RGB leds.
To see this library used in a real project, check out this video Digital Clock With RGB Night Lamp & Spherical Shelf.
Crossfading an RGB led in the RGB colorspace
With 8 bits we have 256 values from 0 to 255 that represents the duty cycle - how long a led will be on then off in a period. For example setting the RED led to 255 and GREEN and BLUE to 0 will result in RED color. Or RED 255, GREEN 0 and BLUE 255 will show a purple color. All leds on (255 value) will result in a white lite. So this is how a certain color can be produced but how to cycle through all the possible combinations?
First the red color is set at 255 and green and blue to 0. Then the red will
be decremented and the green will be incremented. When the red will be 0 and
green 255 we change the fading up and fading down colors.
Now the green color is at 255 and red got to 0. In step 2 the green is decremented and the blue color is incremented until the green reaches 0 and blue 255.
Now the green color is at 0 and blue at 255 so we decrement blue and increment red and after that we start at step 1. In total we have 768 of color combinations (3 * 256).
The following is the full code. For generating the PWM on the RGB pins you can use one of my two libraries for generating PWM:
- Software PWM: https://www.programming-electronics-diy.xyz/2021/02/multi-channel-software-pwm-library-for.html
- Binary Code Modulation (BCM): https://www.programming-electronics-diy.xyz/2021/01/binary-code-modulation-bcm-aka-bit.html
BCM has the advantage of taking very low processing power compared to soft PWM
and it's only drawback is that it has a short blink at the cross-over between
127 and 128 values.
Cross-fading the RGB led without the library
#include <avr/io.h> #include "softwarePWM.h" #define RGB_MAX_COLOR_VALUE 255 enum RGB{ RED, GREEN, BLUE, NUM_COLORS }; int main(void){ // RGB related int16_t RGB_values[] = {255, 0, 0}; // Red, Green, Blue (must be int16_t or int) uint8_t RGB_fading_up_color = GREEN; uint8_t RGB_fading_down_color = RED; const uint8_t RGB_fade_step = 1; softwarePWM_init(); while(1){ softwarePWM_Set(0, RGB_values[RED]);
softwarePWM_Set(1, RGB_values[GREEN]);
softwarePWM_Set(2, RGB_values[BLUE]); RGB_values[RGB_fading_up_color] += RGB_fade_step; RGB_values[RGB_fading_down_color] -= RGB_fade_step; // Reached top of fading up color, change to the next one if(RGB_values[RGB_fading_up_color] > RGB_MAX_COLOR_VALUE){ RGB_values[RGB_fading_up_color] = RGB_MAX_COLOR_VALUE; RGB_fading_up_color++; if(RGB_fading_up_color > BLUE) RGB_fading_up_color = RED; } // Reached bottom of fading down color, change to the next one if(RGB_values[RGB_fading_down_color] < 0){ RGB_values[RGB_fading_down_color] = 0; RGB_fading_down_color++; if(RGB_fading_down_color > BLUE) RGB_fading_down_color = RED; } _delay_ms(10); } return 0; }
RGB fader library - crossfading in RGB colorspace
Instead of having all that code in the main loop let's use a library instead. First include it:
include "rgbFader.h"
By default the code is for a common cathode RGB led and if you are using a common anode one you have to change this define to TRUE:
#define IS_COMMON_ANODE FALSE
Then create an object for every RGB led. In this example we have 2 RGB leds
that requires a total of 6 pins. "RGBFader" is the name of the "class" and
"rgb_led1" can be any name.
RGBFader rgb_led1; RGBFader rgb_led2;
Next initialize each object:
rgbFader_init(&rgb_led1, 1); rgbFader_init(&rgb_led2, 5);
First parameter is the address of the object hence the & symbol and the second is the fade step. With a fade step of 5 we have less colors and the cross-fading will be faster.
The above code must not be in the loop only the following code must be in the
main loop:
softwarePWM_Set(0, rgb_led1.RGB_values[RGB_RED_IDX]); softwarePWM_Set(1, rgb_led1.RGB_values[RGB_GREEN_IDX]); softwarePWM_Set(2, rgb_led1.RGB_values[RGB_BLUE_IDX]); softwarePWM_Set(3, rgb_led2.RGB_values[RGB_RED_IDX]); softwarePWM_Set(4, rgb_led2.RGB_values[RGB_GREEN_IDX]); softwarePWM_Set(5, rgb_led2.RGB_values[RGB_BLUE_IDX]); /*softwarePWM_Set(0, softwarePWM_LineartoLog(rgb_led1.RGB_values[RGB_RED_IDX])); softwarePWM_Set(1, softwarePWM_LineartoLog(rgb_led1.RGB_values[RGB_GREEN_IDX])); softwarePWM_Set(2, softwarePWM_LineartoLog(rgb_led1.RGB_values[RGB_BLUE_IDX]));*/ rgbFader(&rgb_led1); rgbFader(&rgb_led2); _delay_ms(10);
RGB_values[] holds the values for each color for each object and is a member of RGBFader structure. rgbFader() function is the main function that holds the code for crossfading the RGB colors and updates the RGB_values[] array with the new values for each object (led). Like with the init function it takes the address of the led object.
The delay can be changed depending on how fast you want to change the colors and can even be set by a flag in a timer interrupt instead.
The commented code is an alternative to the above code and is using a logarithmic brightness. Try both methods and see which ones do you like. In my opinion the logarithmic brightness produces better colors. Try increasing the minimum RGB color when using the logarithmic function
self->RGB_min_color_value = 0;
But what if you want to set a specific color?
rgbFader_setColor(RGBFader *self, uint8_t color_index)First parameter is the address of the led object and the second one is the index of the color inside the color array. The array can be accessed by index or by the name of a defined color. In this way the color can be changed using a button and incrementing an index.
rgbFader array with predefined RGB colors |
#define USE_COLORS_ARRAY TRUE
This define must be true for the color array to be included.
Cycling through all the predefined colors
// Cycle through colors for(uint8_t i = 0; i < RGBFader_NrOfColors; i++){ rgbFader_setColor(&rgb_led1, i); softwarePWM_Set(0, softwarePWM_LineartoLog(rgb_led1.RGB_values[RGB_RED_IDX])); softwarePWM_Set(1, softwarePWM_LineartoLog(rgb_led1.RGB_values[RGB_GREEN_IDX])); softwarePWM_Set(2, softwarePWM_LineartoLog(rgb_led1.RGB_values[RGB_BLUE_IDX])); _delay_ms(2000); }
Crossfading an RGB led in HSL color space
With the help of the HSL to RGB library provided at this link https://www.programming-electronics-diy.xyz/2021/02/colorspace-conversion-between-rgb-and.html cycling the RGB colors is much easier and also the saturation and brightness can be changed with just one function.
#include <avr/io.h>
#include <util/delay.h>
#include "softwarePWM.h" #include "RGBvsHSL.h" int main(void){ uint8_t saturation = 0; uint8_t lightness = 0; uint8_t rgb[3] = {0}; softwarePWM_init(); while(1){ for(uint16_t i = 0; i < 361; i++){ HSLtoRGB(i, saturation, lightness, rgb); // 0, 1 and 2 are channel numbers where led pins are located softwarePWM_Set(0, rgb[0]); softwarePWM_Set(1, rgb[1]); softwarePWM_Set(2, rgb[2]); // How fast to change the colors _delay_ms(40); } } return 0; }
Download
v1.0
No comments:
Post a Comment