Hi all,
I´d like to have a possibility, to fade smoothly from one thing I see on a RGB strip right now to something else I want to see in future by calculating and showing some frames in between.
The basic idea is, to check for any color for any pixel, if the targetvalue is bigger or smaller than the current one. And then calculate the single steps - in case of a bigger targetvalue for example:
red=red+((new_red-old_red)/steps_i_want)*current_step
That seems logic to me...?!
I wrote the code, tested it and, well, it "kind of" does what i expect. For some frames its visible, that it comes from the random pattern (old_frame) closer to the defined one (new_frame) - but much faster, than I expected. And after 3 or 4 interations it turns into colorful chaos.
What did I do wrong? Are the bytes/integers the wrong datatypes? How could I solve it with the limited memory the Uno has? Or am I just a moran and the formula/concept itself is the problem?
Any hints are appreciated.
Thanks, Helmuth and sorry for my bad english.
Here is my comlete code:
#include <FastSPI_LED.h>
//that is the length of your strip
#define NUM_LEDS 20
//change the order of your rgb here
struct CRGB { unsigned char r; unsigned char g; unsigned char b; };
struct CRGB *leds;
//to save, what you see right now (current frame)
byte old_frame[NUM_LEDS][3];
//to store, what you want to see in future (next frame)
byte new_frame[NUM_LEDS][3];
//some tools first:
//set color of a single LED, don´t show
void set_color_led(int adex, int cred, int cgrn, int cblu) {
leds[adex].r = cred;
leds[adex].g = cgrn;
leds[adex].b = cblu;
}
//save what you see right now to old_frame for playing with it later
void copy_led_array_to_old_frame(){
for(int i = 0; i < NUM_LEDS; i++ ) {
old_frame[i][0] = leds[i].r;
old_frame[i][1] = leds[i].g;
old_frame[i][2] = leds[i].b;
}
}
//show something unique
void create_random_pixels(){ //show something unique
for(int i = 0 ; i < NUM_LEDS; i++ ) {
set_color_led(i, random(255), random(255), random(255));
}
FastSPI_LED.show();
}
//fill new_frame with some linear color fade
void fill_new_frame_with_content(){ //some linear fade
for(int i = 0 ; i < NUM_LEDS; i++ ) {
new_frame[i][0] = i*(255/NUM_LEDS);
new_frame[i][1] = 255-(i*(255/NUM_LEDS));
new_frame[i][2] = 0;
}
}
//make the content of new_frame visible
void show_new_frame(){
for(int i = 0 ; i < NUM_LEDS; i++ ) {
leds[i].r = new_frame[i][0];
leds[i].g = new_frame[i][1];
leds[i].b = new_frame[i][2];
}
FastSPI_LED.show();
}
//just to compare: show the frame you started with again
void show_old_frame(){
for(int i = 0 ; i < NUM_LEDS; i++ ) {
leds[i].r = old_frame[i][0];
leds[i].g = old_frame[i][1];
leds[i].b = old_frame[i][2];
}
FastSPI_LED.show();
}
//fade to new content over a numer of steps with wait_ms delay between the steps
void fade_from_old_to_new_frame(int steps, int wait_ms){
for(int a=0; a < steps; a++){ // over the steps
for(int b=0; b < NUM_LEDS; b++){ // over the whole lenght
//modify red
if (old_frame[b][0] < new_frame[b][0])
{leds[b].r=leds[b].r+(new_frame[b][0]-old_frame[b][0])*a/steps;}
if (old_frame[b][0] > new_frame[b][0])
{leds[b].r=leds[b].r-(old_frame[b][0]-new_frame[b][0])*a/steps;}
//modify green
if (old_frame[b][1] < new_frame[b][1])
{leds[b].g=leds[b].g+(new_frame[b][1]-old_frame[b][1])*a/steps;}
if (old_frame[b][1] > new_frame[b][1])
{leds[b].g=leds[b].g-(old_frame[b][1]-new_frame[b][1])*a/steps;}
//and blue
if (old_frame[b][2] < new_frame[b][2])
{leds[b].b=leds[b].b+(new_frame[b][2]-old_frame[b][2])*a/steps;}
if (old_frame[b][2] > new_frame[b][2])
{leds[b].b=leds[b].b-(old_frame[b][2]-new_frame[b][2])*a/steps;}
}
FastSPI_LED.show();
delay(wait_ms);
}
}
void setup(){
FastSPI_LED.setLeds(NUM_LEDS);
//select your chipset according to your strip type here - have a look at FastSPI documentation
//i´m using a LPD1101 right know who behaves like a LPD6803
FastSPI_LED.setChipset(CFastSPI_LED::SPI_LPD6803);
FastSPI_LED.init();
FastSPI_LED.start();
leds = (struct CRGB*)FastSPI_LED.getRGBData();
}
void loop() {
/* just for testing
create_random_pixels();
copy_led_array_to_old_frame();
delay(1000);
fill_new_frame_with_content();
show_new_frame();
delay(1000);
show_old_frame();
delay(1000);
show_new_frame();
delay(1000);
ok, that seems to work so far*/
create_random_pixels();
copy_led_array_to_old_frame();
fill_new_frame_with_content();
fade_from_old_to_new_frame(10,500); //10 steps with 500 ms delay in between
delay(1000);
}
Ok, I used the wrong stuff to calculate with, now it works fine:
#include <FastSPI_LED.h>
//that is the length of your strip
#define NUM_LEDS 20
//change the order of your rgb here
struct CRGB { unsigned char r; unsigned char g; unsigned char b; };
struct CRGB *leds;
//to save, what you see right now (current frame)
byte old_frame[NUM_LEDS][3];
//to store, what you want to see in future (next frame)
byte new_frame[NUM_LEDS][3];
//some tools first:
//set color of a single LED, don´t show
void set_color_led(int adex, int cred, int cgrn, int cblu) {
leds[adex].r = cred;
leds[adex].g = cgrn;
leds[adex].b = cblu;
}
//save what you see right now to old_frame for playing with it later
void copy_led_array_to_old_frame(){
for(int i = 0; i < NUM_LEDS; i++ ) {
old_frame[i][0] = leds[i].r;
old_frame[i][1] = leds[i].g;
old_frame[i][2] = leds[i].b;
}
}
//show something unique
void create_random_pixels(){ //show something unique
for(int i = 0 ; i < NUM_LEDS; i++ ) {
set_color_led(i, random(255), random(255), random(255));
}
FastSPI_LED.show();
}
//fill new_frame with some linear color fade
void fill_new_frame_with_content(){ //some linear fade
for(int i = 0 ; i < NUM_LEDS; i++ ) {
new_frame[i][0] = i*(255/NUM_LEDS);
new_frame[i][1] = 255-(i*(255/NUM_LEDS));
new_frame[i][2] = 0;
}
}
//make the content of new_frame visible
void show_new_frame(){
for(int i = 0 ; i < NUM_LEDS; i++ ) {
leds[i].r = new_frame[i][0];
leds[i].g = new_frame[i][1];
leds[i].b = new_frame[i][2];
}
FastSPI_LED.show();
}
//just to compare: show the frame you started with again
void show_old_frame(){
for(int i = 0 ; i < NUM_LEDS; i++ ) {
leds[i].r = old_frame[i][0];
leds[i].g = old_frame[i][1];
leds[i].b = old_frame[i][2];
}
FastSPI_LED.show();
}
//fade to new content over a numer of steps with wait_ms delay between the steps
void fade_from_old_to_new_frame(int steps, int wait_ms){
for(int a=0; a < steps; a++){ // over the steps
for(int b=0; b < NUM_LEDS; b++){ // over the whole lenght
//modify red
if (old_frame[b][0] < new_frame[b][0])
{leds[b].r=old_frame[b][0]+(new_frame[b][0]-old_frame[b][0])*a/steps;}
if (old_frame[b][0] > new_frame[b][0])
{leds[b].r=old_frame[b][0]-(old_frame[b][0]-new_frame[b][0])*a/steps;}
//modify green
if (old_frame[b][1] < new_frame[b][1])
{leds[b].g=old_frame[b][1]+(new_frame[b][1]-old_frame[b][1])*a/steps;}
if (old_frame[b][1] > new_frame[b][1])
{leds[b].g=old_frame[b][1]-(old_frame[b][1]-new_frame[b][1])*a/steps;}
//and blue
if (old_frame[b][2] < new_frame[b][2])
{leds[b].b=old_frame[b][2]+(new_frame[b][2]-old_frame[b][2])*a/steps;}
if (old_frame[b][2] > new_frame[b][2])
{leds[b].b=old_frame[b][2]-(old_frame[b][2]-new_frame[b][2])*a/steps;}
}
FastSPI_LED.show();
delay(wait_ms);
}
}
void setup(){
FastSPI_LED.setLeds(NUM_LEDS);
//select your chipset according to your strip type here - have a look at FastSPI documentation
//i´m using a LPD1101 right know who behaves like a LPD6803
FastSPI_LED.setChipset(CFastSPI_LED::SPI_LPD6803);
FastSPI_LED.init();
FastSPI_LED.start();
leds = (struct CRGB*)FastSPI_LED.getRGBData();
}
void loop() {
/* just for testing
create_random_pixels();
copy_led_array_to_old_frame();
delay(1000);
fill_new_frame_with_content();
show_new_frame();
delay(1000);
show_old_frame();
delay(1000);
show_new_frame();
delay(1000);
ok, that seems to work so far*/
create_random_pixels();
copy_led_array_to_old_frame();
fill_new_frame_with_content();
fade_from_old_to_new_frame(50,100); //10 steps with 500 ms delay in between
delay(1000);
}
: