Fading by HEX, not PWM ...

I’m using a bunch of WS2801s to control RGB LEDs. The code provided takes an RGB value and sticks it in an array before pushing it all down the wire to the various ICs and LED in the chain.

So, assume a strip of 3 IC/LEDs, the array starts off

#define STRIP_LENGTH 3;
long strip_colors[STRIP_LENGTH]

From there, I take HEX values for r, g, and b and construct the color before putting it in the array:

r = 0xFF;
g = 0x33;
b = 0x99;
// construct full color value
long color = r;
color <<= 8;
color |= g;
color <<= 8;
color |= b;
// push color into array
strip_colors[x] = color;

(where ‘x’ is the LED I want that color)
Lather, rinse, repeat for the remaining LEDs.

After that, everything gets pushed to the string. Now comes my question: how can I fade what’s in the array back to 0x0 (or technically 0x000000, or 0)?

At the point where I need to shut off the string, I can simply stick 0x0 into all the array slots and push the values out. Done, string is off. However, I’m wondering if there’s a way to fade down to 0x0 based on what’s in the array, without knowing the individual values for r, g, and b. Or do I have to calculate what those individual values are before I can do anything?

Any other time I need to fade and I already know what the individual values are, I simply subtract 0x29 (or whatever number) from them till they drop below 0x0 (at which time I force them to 0x0). But since the values in the array are now together, I’m at a loss as to what I can do …

I realize the stuff in the array can be interpreted as either a hex value or a large int … do I translate what i want subtracted into a large int as well and do it that way? Seems too easy … and more often than not, I’m wrong.

After that, everything gets pushed to the string

Once more, in English please.

You have an array of long values. What is done with this array?

At the point where I need to shut off the string, I can simply stick 0x0 into all the array slots and push the values out. Done, string is off.

Oh, I get it. The string is a string of LEDs. One does not push data to a string those. Data is passed to a function that outputs it to a shift register that actually toggles the LEDs via PWM.

However, I'm wondering if there's a way to fade down to 0x0 based on what's in the array, without knowing the individual values for r, g, and b. Or do I have to calculate what those individual values are before I can do anything?

Yes, you have to know the current value, and compute intermediate values to get to where you want to go.

If you want to fade from the highest value in the color triplet to 0, in equal steps for all colors, the intermediate values will be one thing.

If you want to step each color down one step at a time, some colors will become 0 sooner that others.

If you want to fade out one color at a time, the intermediate values will be a 3rd set of color numbers.

But since the values in the array are now together, I'm at a loss as to what I can do ...

I don't see why. You shifted the values into the long. You can shift them back out to r, g, and b bytes.

You could use a union to union a long and a 4 byte array, where three of the bytes represent the r, g, and b values, and the 4th byte is always 0. Not shifting at all, then.

Just create an instance of the union, set the long, and read the bytes.

Oy, yes, you just made me realize something ... I can't simply subtract a fixed value from each as that will cause some of them to reach 0 before the others, as you pointed out. So I need to do some more calculations and lower everything in percentages so they all go down and reach 0 roughly) at the same time.

Hmmm, more food for the brain ... Ok, first I need to learn shifting out, then figuring out what to do from there. Thanks for the pointers.

Ok, that was easier than I thought ... shifting the values out that is. Just had to remember that it's in reverse order ... r, g, b in and b, g, r out. So that's sorted. Now to figure out a formula to drop them all down to 0. This'll be fun.

how about just dividing them by 2 until you reach 0?

r=r>1;
g=g>1;
b=b>1;

then put color back together:
long color = r;
color <<= 8;
color |= g;
color <<= 8;
color |= b;

CrossRoads: how about just dividing them by 2 until you reach 0?

r=r>1;

I think you mean:

r = r >> 1;

or:

r >>= 1;

Yeah, one >, two >>'s, whatever it takes!

You'll never reach zero though ... just saying. But I can reach a certain threshold where it's as good as zero ... The thing is, I want to do this in a specific amount of steps. If I have a delay of 40ms between each step, I'd want this done in ten steps (400ms), so from whatever max value down to next to zero in ten steps. Division or percentage won't always get there in time. I think I need a better solution there. Still pondering what to do that's relatively easy, or maybe simple is a better word.

"You'll never reach zero though "

Why not? Any one's will shift off to the right after enough shifts (long is 32 bits?) and the bits don't fill in from the MSB side with more 1's.

shift 4 bits at a time r=r>>4; after 8 shifts, r should = 0.

R = FF FF FF FF R = R>>4; now R = 0F FF FF FF R = R>>4 now R = 00 FF FF FF etc. six more shifts and R = 0

KirAsh4: You'll never reach zero though ...

Why?

Ok, I forgot you had 3 variable being put together. Same concept applies tho. Shift each byte r, g, b, 8 times, all will end up at 0.

KirAsh4: Oy, yes, you just made me realize something ... I can't simply subtract a fixed value from each as that will cause some of them to reach 0 before the others, as you pointed out.

The shifting would do it, as that is dividing each one by 2 each time, so the ratio would stay the same. And since you must get to zero in 8 steps, you can just do those divisions fairly slowly.

[quote author=Nick Gammon link=topic=77125.msg582648#msg582648 date=1319864785]

KirAsh4: You'll never reach zero though ...

Why? [/quote]Because my brain isn't thinking shifting ... my brain is thinking simply dividing a number by 2 ... you won't reach zero. 2/2 = 1 1/2 = 0.5 0.5/2 = 0.25 etc., etc.

I have to get out of one method of calculating something, into this method of shifting things.

So that’s why the hare never overtakes the turtle? Because each time the hare halves the distance between it and the turtle, the turtle moves forwards a bit, and thus the hare never catches up?

The fact is that you are dealing with integers. They don’t store any value between 0 and 1.

Eggzactly! And that’s the part I keep forgetting, to make the distinction between INTs and FLOATs …

Just for testing purposes, I wrote this tidbit:

// Test sequence
  randomColor(COLOR, r, g, b, 0);  // this gives me individual r, g, and b, as well as all three shifted into a variable 'colora'
  while (!colora) randomColor(COLOR, r, g, b, 0);  // as long as the resulting colora is 0x0, get a new one
  // shift r, g, and b together into one - the result should be the same exact thing as what's in 'colora'
  long color = r;
  color <<= 8;
  color |= g;
  color <<= 8;
  color |= b;
  strip_colors_a[0] = color; // shove the color into the array
  r=0xFF, g=0xFF, b=0xFF;
  long oColor = strip_colors_a[0]; // fetch what's in the array
  // break it up
  b &= oColor;
  oColor >>= 8;
  g &= oColor;
  oColor >>= 8;
  r = oColor;
  for (int x = 0; x < 10; x++) {
    Serial.print("r: ");
    Serial.print(r);
    Serial.print(", g: ");
    Serial.print(g);
    Serial.print(", b: ");
    Serial.println(b);
    r = r >> 1;
    g = g >> 1;
    b = b >> 1;
  }

Now, with my limited coding practice, this actually works. From within the ten steps, I can see the values getting halfed each time, down to 0. In fact, if I start with 0xFF as a color value (or 255), it reaches zero on the 8th iteration, so I could change it to 8 steps instead of 10 since the max value won’t ever be any larger than 0xFF.

Question now is, am I actually doing the right thing here? Mistakes? Better coding practice? Optimizations?

Your 'tidbit doesn't even compile. what are you trying to do?

Don't do this, whilst it compiles and works it is not good practice:

  r=0xFF, g=0xFF, b=0xFF;

Instead use:

  r=0xFF; g=0xFF; b=0xFF;

Instead of:

    r = r >> 1;
    g = g >> 1;
    b = b >> 1;

You could do:

    r >>= 1;
    g >>= 1;
    b >>= 1;

There is that little less chance you will accidentally do, for example:

    g = r >> 1;

[quote author=Nick Gammon link=topic=77125.msg583257#msg583257 date=1319925244]
Instead use:

  r=0xFF; g=0xFF; b=0xFF;

[/quote]I wondered about that. It’s remnants of a sample code I picked up … I think it was from the h2rgb() routine I got. Figured it works, but you’re right, if it isn’t standard, it shouldn’t be used. It’s not like it’s adding/taking away from the final code size anyway.

Thanks!

Looks good to me. No rocket science here.