This is a simple library used to easily cross-fade one or multiple RGB leds in RGB space or from one color to another. There is also a function that sets a led to a specific color.
To see this library used in a real project, check out this video Digital Clock With RGB Night Lamp & Spherical Shelf.
Contents
- Crossfading an RGB led in the RGB colorspace
- Cross-fading the RGB led without the library
- Data Structures
- API
- Code example
- Crossfading an RGB led in HSL color space
- Links
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 light. 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).
Controlling the intensity of a led is done using PWM. For generating the PWM you can use one of these two libraries:
- 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.
Cross-fading the RGB led without the library
In this example, I have used the BCM library to control the LEDs connected to Port C on pins 1 (red), 2 (green), and 3 (blue). Pins are defined in the bcm.h header file. Optionally, the library includes functions to map linear values to logarithmic values so brightness changes appear more natural to the human eye (pass rgb_log to BCM_encode instead when using this mode).
#include <stdbool.h> #include <util/delay.h> #include "bcm.h" // Define F_CPU in project settings to be globally accessible and easier to maintain. // See: https://www.programming-electronics-diy.xyz/2024/01/defining-fcpu-in-microchip-studio.html #ifndef F_CPU #warning "F_CPU not defined. Define it in project properties." #elif F_CPU != 16000000 // Replace with your actual frequency #warning "Wrong F_CPU frequency!" #endif enum RGB { RED, GREEN, BLUE, NUM_COLORS }; int main(void) { // Start RED at max (255) so fade_down works cleanly bcm_duty_t rgb[NUM_COLORS] = {255, 0, 0}; bcm_duty_t rgb_log[NUM_COLORS] = {0}; uint8_t fade_up = GREEN; uint8_t fade_down = RED; BCM_init(); while (1) { if (BCM_CYCLE_END) { BCM_CYCLE_END = false; // Optional: Map values to logarithmic scale for human eye perception // rgb_log[RED] = BCM_linearToLog(rgb[RED]); // rgb_log[GREEN] = BCM_linearToLog(rgb[GREEN]); // rgb_log[BLUE] = BCM_linearToLog(rgb[BLUE]); // Send values to BCM encoder (use 'rgb_log' if enabling log scale above) BCM_encode(rgb, 'C'); // Adjust color values rgb[fade_up]++; rgb[fade_down]--; // Reached top of fading up color, hand off channels to the next color if (rgb[fade_up] == 255) { fade_down = fade_up; fade_up++; if (fade_up > BLUE) { fade_up = RED; } } _delay_ms(30); } } return 0; }
Data Structures
rgbFader_t
A control structure that maintains the state of a single RGB LED instance. It holds internal variables including the current active-high color channels, target values for fading transitions, directional fade indexes, boundary limits, and the configured hardware LED configuration type (Common Anode vs. Common Cathode).
API
Initialization
void rgbFader_init(rgbFader_t *self, rgb_led_type_t led_type)
Initializes the rgbFader_t instance with default parameters (starting at full Red) and sets the LED hardware type.
self:
Pointer to the rgbFader_t structure.
led_type:
Hardware type, either RGB_COMMON_CATHODE or RGB_COMMON_ANODE.
RGB fader
void rgbFader(rgbFader_t *self)
Advances continuous primary color wheel cycling by incrementing the current fade_up channel and decrementing the fade_down channel by 1 step, automatically shifting channel roles once peak intensity is reached.
self:
Pointer to the rgbFader_t structure.
Output retrieval
void rgbFader_getValues(rgbFader_t *self, uint8_t *out_rgb)
Copies the internal RGB values into a destination array, automatically applying active-low bit inversion if configured for RGB_COMMON_ANODE.
out_rgb:
Pointer to a 3-byte array (uint8_t[3]) to hold the converted Red, Green, and Blue output values ready to be passed to PWM or BCM modules.
Set color
void rgbFader_setHexColor(rgbFader_t *self, uint32_t hex_color)
Sets the active RGB values immediately using a 24-bit hex color code (e.g., COLOR_SALMON or 0xFF5733). Some defined colors can be found in the header file.
hex_color:
24-bit color value formatted as 0xRRGGBB.
Fade to specific color
Set color
void rgbFader_setTargetHex(rgbFader_t *self, uint32_t hex_color)
Sets the target destination color for a smooth transition without changing the current color instantly.
hex_color:
Target 24-bit color value formatted as 0xRRGGBB.
Fade to target color
bool rgbFader_toTargetHex(rgbFader_t *self)
Steps the current RGB color values one unit closer to the set target values on each call.
self:
Pointer to the rgbFader_t structure.
Code example
#include <stdio.h> #include <stdlib.h> #include <util/delay.h> #include "rgbFader.h" #include "bcm.h" int main(void) { rgbFader_t rgb_led1; // Initialize LED with hardware type configuration rgbFader_init(&rgb_led1, RGB_COMMON_CATHODE); // If using rgbFader_toTargetHex() below, set target color before the loop: // rgbFader_setTargetHex(&rgb_led1, COLOR_BLUE); BCM_init(); while (1) { if (BCM_CYCLE_END) { BCM_CYCLE_END = false; // Extract values (automatically inverted if configured for Common Anode) uint8_t output_rgb[3]; rgbFader_getValues(&rgb_led1, output_rgb); // Send formatted values to driver BCM_encode(output_rgb, 'C'); // Continuous color wheel fade: rgbFader(&rgb_led1); // OR Fade to specific target color (comment out rgbFader() if using this): // rgbFader_toTargetHex(&rgb_led1); // Effect speed control _delay_ms(30); } } return 0; }
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 <stdio.h> #include <stdlib.h> #include <util/delay.h> #include "bcm.h" #include "RGBvsHSL.h" int main(void) { // 100% Saturation, 50% Lightness gives vibrant, pure colors uint8_t saturation = 100; uint8_t lightness = 50; uint16_t hue = 0; uint8_t rgb[3] = {0}; BCM_init(); while (1) { if (BCM_CYCLE_END) { BCM_CYCLE_END = false; // Calculate current RGB for active hue step HSLtoRGB(hue, saturation, lightness, rgb); // Send formatted values to driver BCM_encode(rgb, 'C'); // Increment Hue angle (0° to 360°) hue++; if (hue > 360) { hue = 0; } // Effect speed control _delay_ms(40); } } return 0; }
Links
| v2.0 | |
| rgbFader.h | |
| rgbFader.c | |
| v1.0 | |
| rgbFader.h | |
| Changelog | |
| v2.0 |
09-08-2026: - Multiple improvements. |




No comments:
Post a Comment