Skip to content

Instantly share code, notes, and snippets.

@jimsynz
Created January 5, 2011 20:59
Show Gist options
  • Select an option

  • Save jimsynz/766994 to your computer and use it in GitHub Desktop.

Select an option

Save jimsynz/766994 to your computer and use it in GitHub Desktop.
Arduino sketch to cycle an RGB LED through the colour spectrum.
const int redPin = 11;
const int greenPin = 10;
const int bluePin = 9;
void setup() {
// Start off with the LED off.
setColourRgb(0,0,0);
}
void loop() {
unsigned int rgbColour[3];
// Start off with red.
rgbColour[0] = 255;
rgbColour[1] = 0;
rgbColour[2] = 0;
// Choose the colours to increment and decrement.
for (int decColour = 0; decColour < 3; decColour += 1) {
int incColour = decColour == 2 ? 0 : decColour + 1;
// cross-fade the two colours.
for(int i = 0; i < 255; i += 1) {
rgbColour[decColour] -= 1;
rgbColour[incColour] += 1;
setColourRgb(rgbColour[0], rgbColour[1], rgbColour[2]);
delay(5);
}
}
}
void setColourRgb(unsigned int red, unsigned int green, unsigned int blue) {
analogWrite(redPin, red);
analogWrite(greenPin, green);
analogWrite(bluePin, blue);
}
@peterrus

Copy link
Copy Markdown

Wouldn't it be better to use PWM here? Leds have a nonlinear voltage response

@Hurragorilla

Copy link
Copy Markdown

Well written jamesotron, thanks.

Peterrus: analogWrite() is PWM.

@razic

razic commented Sep 12, 2013

Copy link
Copy Markdown

Perfect. Just what I was looking for!

@stonez56

stonez56 commented Jan 7, 2014

Copy link
Copy Markdown

Very well written codes! Thank you so much!!

@vasileio

vasileio commented Apr 3, 2015

Copy link
Copy Markdown

Neat code! Thank you!

@whalemare

Copy link
Copy Markdown

Yeah, thanks!)

@VolandiYisser

Copy link
Copy Markdown

Hello Arduino World,
I'm trying to work out how this sketch works. I understand it up to the line 20.
int incColour = decColour == 2 ? 0 : decColour + 1;
I think it starts by declaring an integer called incColour and sets it equal to the other int decClour but then I get lost with the two = signs and then the quesion mark. Is there a long way to write this line that will be easier to understand?
Regards,
Volandi

@pizen

pizen commented Oct 25, 2015

Copy link
Copy Markdown

Volandi,

? is a ternary operator. Line 20 is the same logic as:

int incColour;
if (decColour == 2) {
    incColour = 0;
} else {
    incColour = decColour +1;
}

@spreadred

Copy link
Copy Markdown

Thanks!

@doublejosh

Copy link
Copy Markdown

You can skip a block of code by assigning values when you initialize the array...

unsigned int rgbColor[3] = {255, 0, 0};

Also, thanks for this example.

@ManciuStefan

Copy link
Copy Markdown

You can also write that line as:
incColour = (decColour + 1) % 2

@Cellane

Cellane commented Oct 10, 2016

Copy link
Copy Markdown

@ManciuStefan Not really, that line only ever gives you 0 or 1 as an output. The original line with ternary operator gives you either 0, 1, or 2.

@nizamky

nizamky commented Oct 11, 2016

Copy link
Copy Markdown

i need to control rgb light via blutooth from mobile?. any advice?

@hideyhole1

Copy link
Copy Markdown

@jamesotron Your schetche works but, you need to explain stuff and add comments. Explain what this means(on line 20):

int incColour = decColour == 2 ? 0 : decColour + 1;

@XombyCraft

Copy link
Copy Markdown

This works great for common cathode LEDS.
If you're using common Anode LEDS, change line 27 to:
setColourRgb(255-rgbColour[0], 255-rgbColour[1], 255-rgbColour[2]); //quick and ugly invert

@inxomnyaa

Copy link
Copy Markdown

Interesting code, but for me only blue changes

@jdimpson

jdimpson commented Jan 9, 2018

Copy link
Copy Markdown

I just noticed a minor bug. A stickler (such as myself) may wish to call setColourRgb(rgbColour[0],rgbColour[1],rgbColour[2]); delay(5); immediately after rgbColour gets initialized to {255,0,0}, before hitting the for loops. Otherwise the LED doesn't ever hit a pure red output.

Alternatively, you could initialize rgbColour to {256,-1,-1}, but then you'd need to change the declaration of rgbColour to signed and make similar change to the arguments to setRgbColour() function. I'm pretty sure making it signed won't hurt anything; at worst analogRead() will complain about implicit casting. If that bothers you (and it should) you can safely cast it to unsigned in setRgbColour()

I noticed that the red output seemed underpowered a few months ago, but assumed I used too large a value of resistor on the red pin. That may still be true, but this fix should help a bit.

I love this gist, by the way. I've come back to it several times since I first saw it a couple years ago. Thank you, @jamesotron !

@michalmonday

michalmonday commented Feb 8, 2018

Copy link
Copy Markdown

Simultaneous increasing and decreasing of 2 colours leads to the situation where the colors "meet" at midpoint between 0 and 255 so the RGB status is like 127,128,0 which gives a darker shade. If you take a look at "color picker" in google, set the color to be the brightest and play with the slider you'll notice that it always changes 1 of the RGB variables at a time leading it to reach 6 main states that gradually switch between themselves, these states are:

  1. 255, 0, 0
  2. 255, 255, 0
  3. 0, 255, 0
  4. 0, 255, 255
  5. 0, 0, 255
  6. 255, 0, 255
  7. 255, 0, 0 (whole cycle ends, it's the same as 1st step)

Your implementation is providing the following states:

  1. 255, 0, 0
  2. 127, 128, 0
  3. 0, 255, 0
  4. 0, 128, 127
  5. 0, 0, 255
  6. 127, 0, 128
  7. 255, 0, 0

Here's a python implementation which shows how to loop through RGB without getting the darker shade:
https://github.com/michalmonday/RGB_rainbowLoop/blob/master/RGB_rainbowLoop.py

I guess it would be better without the section list but it does the thing... On the other side it allows for other operations being executed without the need to complete the whole cycle from red to blue, also it would be easy to implement custom sequences of colours with it.

@susumakeit

Copy link
Copy Markdown

very nice to use make the prototype. and I can save time by using this function.
I will make a led lamp using contained register led(NeoPixel)that operate by data but
previous products are consist of normal type led to controlled ON or OFF voltage

@mahenzon

mahenzon commented May 24, 2018

Copy link
Copy Markdown

I've implemented a non-blocking version of it using @michalmonday's algorithm for Arduino:
https://gist.github.com/mahenzon/6eb44d102d207bc94b9f9bd1c7e87c42

@rvt

rvt commented Aug 28, 2018

Copy link
Copy Markdown

You can also use the HSB model for your colors (if your mc is fast enough) then cycling through all colors will start to feel very natural. C++ for this can be found here https://github.com/rvt/Arilux_AL-LC0X

@etaironivo

etaironivo commented Jun 29, 2020

Copy link
Copy Markdown

i have this, and i want to implement this into my code using one of the 'case' statements i have. now, i have no clue what i'm doing so help would be appreciated. i want to add it into the lowest one (play/pause key)


=]ppm #include <IRremote.h>

// Define sensor pin
const int RECV_PIN = 4;

// Define LED pin constants
const int redPin = 3;
const int greenPin = 5;
const int bluePin = 6;

// Define integer to remember toggle state
int togglestate = 0;

// Define IR Receiver and Results Objects
IRrecv irrecv(RECV_PIN);
decode_results results;

void setup(){
// Enable the IR Receiver
irrecv.enableIRIn();
// Set LED pins as Outputs
pinMode(redPin, OUTPUT);
pinMode(greenPin, OUTPUT);
pinMode(bluePin, OUTPUT);
}

void loop(){
if (irrecv.decode(&results)){

    switch(results.value){
      case 0xFF30CF: //1 key
    // Toggle LED On or Off
    if(togglestate==0){
    digitalWrite(redPin, HIGH);
    togglestate=1;
    }
    else {
    digitalWrite(redPin, LOW);
    togglestate=0;
    }
    break;

    case 0xFF10EF: //4 key
    // Toggle LED On or Off
    if(togglestate==0){
    digitalWrite(bluePin, HIGH);
    togglestate=1;
    }
    else {
    digitalWrite(bluePin, LOW);
    togglestate=0;
    }
    break;

    case 0xFF18E7: //2 key
    // Toggle LED On or Off
    if(togglestate==0){
    digitalWrite(greenPin, HIGH);
    togglestate=1;
    }
    else {
    digitalWrite(greenPin, LOW);
    togglestate=0;
    }
    break;

    case 0xFFC23D: //play-pause key
    if togglestate==0){
    
    }
    
}
irrecv.resume(); 

}

}

@dreamer1048576

Copy link
Copy Markdown

@jdimpson

Otherwise the LED doesn't ever hit a pure red output.

??? WHY ???

 for (int decColour = 0; decColour < 3; decColour += 1) {
 // When `decColour ==2`
   int incColour = decColour == 2 ? 0 : decColour + 1;
   //  `incColour = 0` at this moment 

After finish the i loop ,
rgbColour[0]=255; and rgbColour[1]=rgbColour[2]=0; ... back to pure red again...
right ?

@dreamer1048576

Copy link
Copy Markdown

Another kinds of colour cycle
it might ignore darker shade problem

but it's total different spectrum with original

void loop() {
  unsigned int rgbColour[3];

  // Start off with red.
  rgbColour[0] = 255;
  rgbColour[1] = 255;    //// Different place !
  rgbColour[2] = 0;  

  // Choose the colours to increment and decrement.
  for (int decColour = 0; decColour < 3; decColour += 1) {
    int incColour = (0==decColour ) ? 2 : decColour - 1;    //// Different place !

    // cross-fade the two colours.
    for(int i = 0; i < 255; i += 1) {
      rgbColour[decColour] -= 1;
      rgbColour[incColour] += 1;
      
      setColourRgb(rgbColour[0], rgbColour[1], rgbColour[2]);
      delay(5);
    }
  }
}

@dreamer1048576

Copy link
Copy Markdown

for states :
255, 0, 0
255, 255, 0
0, 255, 0
0, 255, 255
0, 0, 255
255, 0, 255
255, 0, 0

void loop() {
  unsigned int rgbColour[3];

  // Start off with red.
  rgbColour[0] = 255;
  rgbColour[1] = 0; 
  rgbColour[2] = 0;  
  int decColour =0;
  int incColour =1;

void loop() {
			if (255<=rgbColour[incColour]) {
				if (0>=rgbColour[decColour]) {
					decColour++;	decColour %= 3;
					incColour++;	incColour %= 3;
				} else 	// if (0==rgbColour[decColour]) {
					rgbColour[decColour] -= 15;  // --
			} else	// if (255==rgbColour[incColour]) {
				rgbColour[incColour] += 15;  // ++
      
        setColourRgb(rgbColour[0], rgbColour[1], rgbColour[2]);
        delay(5);
    }
}

@tigrouind

tigrouind commented Apr 7, 2025

Copy link
Copy Markdown

Here is some code that address the issue pointed by @michalmonday (eg: colors such as (255, 255, 0), (255, 0, 255), (0, 255, 255) never reached). Additionally, it's a non-blocking version. Unlike original code, it does not keep 100% brightness anymore (eg: at some point 2 leds are fully on, sometimes only one...).

const int redPin = 11;
const int greenPin = 10;
const int bluePin = 9;
unsigned char rgbColor[3] = { 255, 0, 0 }; //start with red
int state = 0;

unsigned char colors[6]= { 1, 0, 2, 1, 0, 2 }; //green, red, blue
unsigned char directions[6]= { 1, -1, 1, -1, 1, -1 }; //up, down

void setup() {
	// Start off with the LED off.
	setColourRgb(0,0,0);
}

void loop() {
	int color = colors[state];
	rgbColor[color] += directions[state];
	if (rgbColor[color] == 0 || rgbColor[color] == 255) {
		state = (state + 1) % 6; //next state
	}
	
	setColourRgb(rgbColor[0], rgbColor[1], rgbColor[2]);
	delay(3);
}

void setColourRgb(unsigned char red, unsigned char green, unsigned char blue) {
	analogWrite(redPin, red);
	analogWrite(greenPin, green);
	analogWrite(bluePin, blue);
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment