5 second change from one color value to another

So the idea here is for an RGB led to randomly get the values for each built in color: random for red, random for blue, random for green, for the analog PWM. So far no problem. Then when a button is pushed, I want the system to get new RGB values, and over the course of 5 seconds fade from the current values to the new values. I got this by getting the max value (which was higher, current or new values), subtracting the other from that, and then dividing 5000 from that value. i.e., current Red is 120, new value is 42. 120-42 = 78. 5000(ms) / 78 = 64.1. Since they are all ints, it will be 64.
So now this way every 64ms, the current value will change by 1 until it gets to the new value.
And that's just for reds. Blues and Greens will also be going through this with their own random values. The point though is for them to all change smoothly from current to new in ~5000ms at the same time.
And that's where I fall apart. I assume that I should create a function to start counting the millis, starting at 0 and ending at 5000. Every milli that passes it does a check to see if it lands on the interval value (64 in this case), and I assume every multiple thereafter until it finishes at 5000 (or just up to it, as 64 will never reach 5000 exactly). On the interval it adds or subtracts 1 from the current value to the new value and analogWrite(workingLed, currentValue);
Maybe I'm just burned and can't think of it, maybe I'll get it tomorrow, but right now I can't even think of how to start this function.

On another note, what would be a good Intermediate book for Arduino programming, or even a slightly more advanced Beginners book? All I have is this small Getting Started w/ Sketches book, and I'm looking to progress. Alas my local B&N doesn't have much.

A better approach would be to do your math and determine that you need to update every 64 milliseconds, so count up to that, and, when it expires, increment (or decrement) you values and repeat.

// do math to determine calcInterval
// and rinc, binc, ginc (could be + or -)
if ( millis() - lastTime >= calcInterval ) {
  lastTime = millis();
red += rinc;
blue += binc;
green += ginc;
// set your RGB values - analogWrite() I am guessing
}

Yes, that would indeed work. You could do this (but there are other ways as well) with a timer interrupt that fires every millisecond. But if you just call a function from your main loop that checks the value of millis() it will likely work just fine too.

I'm not sure where you got stuck, because the description you gave that I quoted above looks very sensible and feasible. Perhaps the problem is that you need to split this into two functions:
1: One function to set the stage; it calculates the interval for each color and if it should increment or decrement, and sets a flag (typically a boolean variable) that signals the 2nd function that it should run. You call this one only at the start of a fade routine.
2: One function that periodically (every millisecond, of every x milliseconds) check if the interval for any of the colors has elapsed and that increments/decrements the color value.

Not necessarily; perhaps I'm misreading your post, but the thing is that his routine isn't bound to a single interval. He wants to fade from any random color to another random color within a fixed timeframe (5 seconds), and he has chosen to do this by incrementing/decrementing by 1 each color. The consequence is that the interval at which the inc/dec happens varies with the from: and to: color.

True. You would have do the interval math and counting for each of the colors or better, use an array


byte oldColor[3];
byte newColor[3];
byte currentColor[3];
byte increment[3];

const unsigned long timeInterval = 5000;
unsigned long lastTime[3], interval[3];

void setup() {
  ...
}

void loop() {
  ...
  if ( <<some contition is met>> ) {
    // calc new color and start transition
    for(int i=0; i<3; ++i) newColor[i] = random(256);
    calcInterval();
  }
  updateLEDs(); // always update
}


void calcInterval() {
  // calculate how to get from oldColor to newColor
  for (int i = 0; i < 3; ++i) {
    interval[i] = (oldColor[i] - newColor[i]) / timeInterval;
    lastTime[i] = millis();
    currentColor[i] = oldColor[i];
    if ( newColor[i] >= oldColor[i] ) increment[i] = 1; // going up
    else increment[i] = -1; // going down
  }
}

void updateLEDs() {
  // if it is time, update currentColor and stop if we reach newColor
  for(int i=0; i < 3; ++i ) {
    if ( millis() - lastTime[i] >= interval[i] && currentColor[i] != newColor[i])
    lastTime[i] = millis();
    currentColor[i] += increment[i];
  }
}
1 Like
unsigned long elapsedTime = millis() - StartTime;

if (elapsedTime <= 5000)
{
  currentColor = (oldColor * (5000-elapsedTime) +
    newColor * elapsedTime) / 5000;
  }
else
  {
    oldColor = newColor;
    newColor = pickRandomColor;
    StartTime = millis();
  }
}
2 Likes

Elegantly solved.