LED Driver Code
This is the draft code I am using to drive the RGB LED string I am eventually going to build into a lighting fixature, that will give me soothing red lights in the evening and then wake me up with brighting red and orange lights, fading into blue.
/////////////////////// INCLUDES /////////////////////////////////// #include <IRremote.h> // set up irReciever const int irReceiverPin = 3; IRrecv irrecv(irReceiverPin); decode_results results; /////////////////////// VARIABLES /////////////////////////////////// // LED pins int rLED = 9; int gLED = 10; int bLED = 6; // Current LED color (0... 255 brightness) int rC = 0; int gC = 0; int bC = 0; // last remote code (needs to be an unsigned long unsigned long remoteCode = 0; ///////////////// TEMPERATURE and BRIGHTNESS OF COLOR // Color Temperature, In Kelvin // unsigned long needed for very cold, very blue light temperatures, // e.g. above 32,700 kelvin (we can do that even if those colors are mostly theortical!) unsigned long temp = 3000; // Brightness int bright = 100; //////////////// TIMERS FOR THE LOOP // Time of Last Loop unsigned long prevMS = 0; // Time of Last Button Press unsigned long buttonMS = 0; ////////////// SPECIAL MODES (e.g. time delay dimming for sleep or rise) // special mode version int specialMode = 0; // time elapsed in special mode unsigned long specialModeMS = 0; // time elapsed in special mode LOOP unsigned long specialModeMSLoop = 0; // what task number are we on in specialMode int specialModeTK = 1; /////////////////////// FUNCTIONS /////////////////////////////////// // Kelvin to RGB Code is roughly based on this javascript that I re-wrote in C# // http://www.tannerhelland.com/4435/convert-temperature-rgb-algorithm-code/ // unsigned long needed for very cold, very blue light temperatures, // e.g. above 32,700 kelvin (we can do that even if those colors are mostly theortical!) void kRGB (unsigned long kelvin, int *r, int *g, int *b) { Serial.println(kelvin); int t = kelvin / 100; if(t <= 66 ){ *r = 255; *g = t; *g = 99.4708025861 * log(*g) - 161.1195681661; if( t <= 19){ *b = 0; } else { *b = t-10; *b = 138.5177312231 * log(*b) - 305.0447927307; } } else if (t < 320) { *r = t - 60; *r = 329.698727446 * pow(*r, -0.1332047592); *g = t - 60; *g = 288.1221695283 * pow(*g, -0.0755148492 ); *b = 255; } else { // this is mostly made up, just testing // as original code doesn't look at imaginary colors // beyond about 32,000 kelvin // this will create negative numbers at times // but setColor will just zero out the channels *b = 255; *r = t - 255; *g = t - 255; } } // Dim Each Channel Equally void dimColor(float percent, int *r, int *g, int *b) { if (percent > 100) percent = 100; float p = (percent/100); float rD = *r; float gD = *g; float bD = *b; *r = round(rD * p); *g = round(gD * p); *b = round(bD * p); } // Simple Function to Set Colors void setColor(int r, int g, int b) { // occassionally we will get fed // values outside of the 0-255 acceptable // range so we fix here if (r < 0) r = 0; if (g < 0) g = 0; if (b < 0) b = 0; if (r > 255) r = 255; if (g > 255) g = 255; if (b > 255) b = 255; analogWrite(rLED, r); analogWrite(gLED, g); analogWrite(bLED, b); // set the internal color channels rC = r; bC = g; gC = b; // debugging output Serial.print("r="); Serial.print(r); Serial.print(", g="); Serial.print(g); Serial.print(", b="); Serial.print(b); Serial.print("\n"); } // set color by temperature void setColorByTemp(unsigned long tempColor) { temp = tempColor; // set the internal temp color kRGB(temp, &rC, &gC, &bC); dimColor(bright, &rC, &gC, &bC); setColor(rC, gC, bC); } // set brightness void setColorByBrightness(int brightness) { bright = brightness; // set the internal brightness kRGB(temp, &rC, &gC, &bC); dimColor(bright, &rC, &gC, &bC); setColor(rC, gC, bC); } // Setup Function void setup() { // for debugging Serial.begin(9600); // load IR pin irrecv.enableIRIn(); // load pin pinMode(rLED, OUTPUT); pinMode(gLED, OUTPUT); pinMode(bLED, OUTPUT); // start LEDs kRGB(temp, &rC, &gC, &bC); dimColor(bright, &rC, &gC, &bC); setColor(rC, gC, bC); } // Loop cycles through the colors void loop() { // check to see if any mode requests have come in if (irrecv.decode(&results)) { Serial.println(results.value); irrecv.resume(); // Receive the next value // this is to prevent button bounce // from somebody holding the button too long if (millis() - buttonMS >= 400) { remoteCode = results.value; buttonMS = millis(); } } // every half a second see if user // has requested any changes if (millis() - prevMS >= 500) { // if any remote codes are hit, interrupt any special modes // reset to default modes before taking next option if (remoteCode && specialMode) { specialMode = 0; specialModeMS = 0; specialModeTK = 1; temp = 3000; bright = 100; kRGB(temp, &rC, &gC, &bC); dimColor(bright, &rC, &gC, &bC); setColor(rC, gC, bC); } // turn light string on or off if (remoteCode == 4105841032) { if (!rC && !bC && !gC) { kRGB(temp, &rC, &gC, &bC); dimColor(bright, &rC, &gC, &bC); setColor(rC, gC, bC); Serial.print("on button activated"); } else { setColor(0,0,0); Serial.print("off button activated"); } } // lower or raise the brightness if (remoteCode == 2209452902 ) { if (bright > 10) { bright -= 10; } setColorByBrightness(bright); Serial.print("dim button activated"); } if (remoteCode == 1752382022) { if (bright < 90) { bright += 10; } setColorByBrightness(bright); Serial.print("bright button activated"); } // warm or chill the color temperature // above 3500 kelvin we make bigger steps if (remoteCode == 1595074756) { if (temp < 3500) { temp += 200; } else { temp += 700; } setColorByTemp(temp); Serial.print("cool button activated"); } if (remoteCode == 412973352) { if (temp > 3500) { temp -= 700; } else if (temp > 100) { temp -= 200; } setColorByTemp(temp); Serial.print("warm button activated"); } // color temperature pre-sets if (remoteCode == 3778927144) { setColorByTemp(500); Serial.print("one button activated"); } if (remoteCode == 2908251746) { setColorByTemp(1000); Serial.print("two button activated"); } if (remoteCode == 657459652) { setColorByTemp(1500); Serial.print("three button activated"); } if (remoteCode == 4120482440) { setColorByTemp(2000); Serial.print("four button activated"); } if (remoteCode == 1931099650) { setColorByTemp(2500); Serial.print("five button activated"); } if (remoteCode == 742730860) { setColorByTemp(3000); Serial.print("six button activated"); } if (remoteCode == 1167253836) { setColorByTemp(3500); Serial.print("seven button activated"); } if (remoteCode == 1747313982) { setColorByTemp(6000); Serial.print("eight button activated"); } if (remoteCode == 2340753640) { setColorByTemp(10000); Serial.print("nine button activated"); } if (remoteCode == 3119867746) { bright = 100; temp = 5000; // rough ball park setColor(255,255,255); Serial.print("zero button activated"); } ////////// special modes //////////// if (remoteCode == 1976685926) { // special mode 1 - Sunset specialMode = 1; specialModeMS = millis();; specialModeTK = 1; // start as 50% dim, warm yellow light setColorByTemp(1200); setColorByBrightness(50); Serial.print("back button activated"); } if (remoteCode == 3980777284) { // special mode 2 - Sunrise specialMode = 2; specialModeMS = millis(); specialModeMSLoop = millis(); specialModeTK = 1; setColorByTemp(500); setColorByBrightness(5); Serial.print("forward button activated"); } if (remoteCode == 1784778242) { // special mode 3 - Sunset then eight hours later, sunrise specialMode = 3; specialModeMS = millis();; specialModeTK = 1; // start as 50% dim, warm yellow light for the sunset mode setColorByTemp(1200); setColorByBrightness(50); Serial.print("play button activated"); } if (remoteCode == 1784778242) { // special mode 3 - Sunset then seven hours later, sunrise specialMode = 4; specialModeMS = millis(); specialModeTK = 1; // start as 50% dim, warm yellow light for the sunset mode setColorByTemp(1200); setColorByBrightness(50); Serial.print("stop button activated"); } // reset remote code to zero to avoid repeating // the action and rest the loop timer to zero remoteCode = 0; prevMS = millis(); } /////////// this section is for special timer modes //////////////////////// if (specialMode == 1 || (specialMode == 3 && millis() - specialModeMS < 10L * 60 * 1000) || (specialMode == 4 && millis() - specialModeMS < 10L * 60 * 1000) ) { // Task 1 for Special Mode 1 // Task 1 for Special Mode 3, 4 (first ten minutes) // // Special Mode 1 - Sunset Mode // Special Mode 2 - Sunset Mode; See Below for Sunrise // // oranges and reds, lights fade out to black in 5 minutes // 50 cycles * 10 seconds = 5 minutes // initial color set above in "play button activated section" if (millis() - specialModeMSLoop > 10L * 1000) { if (bright > 0) { // fifty cycles // reduce color temperature by 10 degrees kelvin // from 1000k to 500k to make a nice warm temperature temp -= 10; setColorByTemp(temp); // reduce from 50 brightness to 0 brightness // then shut off the unit bright -= 1; setColorByBrightness(bright); } else { // we are done. turn off special mode, reset colors specialMode = 0; setColor(0,0,0); temp = 3000; bright = 100; specialModeTK++; // task 1 is done } specialModeMSLoop = millis(); // reset LOOP timer } } if (specialMode == 2 || (specialMode == 3 && millis() - specialModeMS > 8L * 60 * 60 * 100) || (specialMode == 4 && millis() - specialModeMS > 7L * 60 * 60 * 100)) { // Task 1 for Special Mode 2 // Task 2 for Special Mode 3 (eight hours later) // Task 2 for Special Mode 4 (seven hours later) // // Special Mode 2 - Sunrise Mode // Special Mode 3 and Special Mode 4, Task 2 - Sunrise in the Morning Mode // // 500 kelvin light driven at 5%, incremented 100 kelvin for 95 times // to bring us up to 9,500 kelvin at 100% brightness // // Once we reach 9,500 kelvin, we pull up the blue channel (bC) at a rate of // 10/256th or 4% each ten seconds until we reach 255 (full brightness). // // Then to reach full brightness, which is less blue and more light // we pull up the red (rC) and green chanels at a rate of // 10/256th or 4% each ten seconds until we reach 255 (full brightness all channels). // // 95 cycles * 6 seconds = 570 seconds or 9 1/2 minutes to // full brightness // initial color set above in "play button activated section" if (millis() - specialModeMS > 6L * 1000) { if (bright < 100) { // fifty cycles // reduce color temperature by 100 degrees kelvin // from 500 K to 10,0000 to a nice daylight temperature temp += 100; setColorByTemp(temp); // reduce from 50 brightness to 0 brightness // then shut off the unit bright++; setColorByBrightness(bright); } else if (bright > 100 && rC != 255 && bC != 255 & gC != 255){ // if the blue channel isn't at 255 increment it by 4% or 10/256th if (bC < 255) { bC+= 10; // if we overrun, that's fine, we check and fix that in setColorw() } else { // do the same equally with red and green channelsl rC+=10; gC+=10; } setColor(rC,gC,bC); } else { // we are done. turn off special mode, reset colors specialMode = 0; setColor(255,255,255); // end at maximum brightness temp = 3000; bright = 100; specialModeTK++; // task 2 is done } specialModeMS = millis(); } } }