IRremote for my 8x8x8 led cube on the mega

OK, the only change is the one from timer2 to timer1 for the Megas. That should do the trick as far as I know.

Options:
1)
We did something wrong; no idea what
2a)
Test your sensor on the Uno with boarddefs as it currently is; does it work? This will prove that your sensor is still OK.
2b)
Test your sensor on the Uno with boarddefs modified to use Timer1 instead of Timer2 (line 152/153); does it work? That basically would proof that the approach works.

I think I know what the problem is ... I think the program just loops everytime the patern effect is finished.
What I need is a loop just for the IR.... but how ??

Thats excatly whats happening, I put the irrecv.decode` line somewhere else
and everytime the cube effect changed, the code ran past that line and the result was printed.

But I need the IR to recieve all the time ... not just when the code changes the cube effect. So how do I create a loop for that?

Roon_cube_Mega.ino (25.2 KB)

Try to confirm with some simple Mega code (one of the examples that come with the library) without the cube effects to see if IR works. You should not "think you know what the problem is"; you need to know for sure before you continue.

If you need immediate reaction, get rid of all the delays and replace them by a millis() based approach.

It will be a lot of work as you need to break up all your cube functions in little steps. The simplest one to demonstrate how to get rid of delay_ms is probably effect_rain. It contains a nested for-loop. The inner loop does not pose an issue but the outer loop loop 100 times and hence 100 seconds delay.

This would be a reworked version to demonstrate how you can get rid of delay_ms; code not tested.

/*
  effect 4 rain
  In:
    number of iterations
  Returns:
    true if all iterations completed, else false
*/
bool effect_rain (int iterations)
{
  // count the number of iterations; used to be ii
  static int count;
  // last time that the cube was updated
  static unsigned long lastUpdateTime;

  PORTC = B11001100; // 4

  int i;
  int rnd_x;
  int rnd_y;
  int rnd_num;

  // if number of iterations completed
  if (count >= iterations)
  {
    // done, reset count
    count = 0;

    // and indicate to called that we're finished
    return true;
  }

  if (count == 0)
  {
    lastUpdateTime = currentTime;

    rnd_num = rand() % 4;

    for (i = 0; i < rnd_num; i++)
    {
      rnd_x = rand() % 8;
      rnd_y = rand() % 8;
      setvoxel(rnd_x, rnd_y, 7);
    }
  }

  if (currentTime - lastUpdateTime >= 1000)
  {
    count++;
    lastUpdateTime = currentTime;

    shift(AXIS_Z, -1);
  }

  return false;
}

Other functions are more complicated. For the effect_intro, you will need a state machine to be able to keep track which step you are executing.

In loop(), simply call effect_rain and check for IR

void loop()
{
  if (irrecv.decode(&IRresults))
  {
    Serial.println(IRresults.value, DEC); // Print the Serial 'results.value'
    irrecv.resume();   // Receive the next value
  }
  effect_rain()
}

Now running out of time. See if you can understand state machines.

Thankx man ..... :o

More work for me ......

At least I got it kind of working now with a bit of a delay ..... >:(

But I`ll definitely try what you suggest. Although I looks quite difficult.

Ronald,

Super bedankt nogmaals ........ :slight_smile:

Just a different mind set :wink:

I forgot to mention how to use the return value of the modified effect_rain. You can use this in loop() to determine if you can go to the next effect.

Hi,

I tried replacing the effect_rain code with yours... but no joy :confused:
Trying to compile I got the error;

Arduino: 1.8.5 (Windows 7), Board:"Arduino/Genuino Mega or Mega 2560, ATmega2560 (Mega 2560)"

C:\Users\Roonie\Documents\Arduino\Roon_cube_Mega\Roon_cube_Mega.ino: In function 'bool effect_rain(int)':

Roon_cube_Mega:914: error: 'currentTime' was not declared in this scope

     lastUpdateTime = currentTime;

                      ^

Roon_cube_Mega:926: error: 'currentTime' was not declared in this scope

   if (currentTime - lastUpdateTime >= 1000)

       ^

exit status 1
'currentTime' was not declared in this scope

Dit rapport zou meer informatie bevatten met
"Uitgebreide uitvoer weergeven tijden compilatie"
optie aan in Bestand -> Voorkeuren.

As I dont yet know how the code works I cant say or see whats wrong.
Big learning curve..... :o

Ronald

Roon_cube_Mega.ino (37.4 KB)

Please post your original version of the effect_rain function. I will compare it with what I presented in reply #11.

Okè thankx,

here is the code so far .....

Ronald

Roon_cube_Mega.ino (39.9 KB)

I think you're going about it the wrong way. Start with the simple loop() example that I presented and only the effect rain that I presented; both in reply #11. Does that compile? No, see comment below. Does it show the effect?

OK, for some reason I was a bit sloppy in the code that I presented in reply #11. The variable currentTime fell out and it was never initialised; effect_rain also needed a parameter in loop().

Below the modified version. Please strip everything out of loop() and keep it simple.

unsigned long currentTime;
void loop()
{
  // get the current time
  currentTime = millis();

  if (irrecv.decode(&IRresults))
  {
    Serial.println(IRresults.value, DEC); // Print the Serial 'results.value'
    irrecv.resume();   // Receive the next value
  }
  effect_rain(150)
}

/*
  effect 4 rain
  In:
    number of iterations
  Returns:
    true if all iterations completed, else false
*/
bool effect_rain (int iterations)
{
  // count the number of iterations; used to be ii
  static int count;
  // last time that the cube was updated
  static unsigned long lastUpdateTime;

  PORTC = B11001100; // 4

  int i;
  int rnd_x;
  int rnd_y;
  int rnd_num;

  // if number of iterations completed
  if (count >= iterations)
  {
    // done, reset count
    count = 0;

    // and indicate to called that we're finished
    return true;
  }

  if (count == 0)
  {
    lastUpdateTime = currentTime;

    rnd_num = rand() % 4;

    for (i = 0; i < rnd_num; i++)
    {
      rnd_x = rand() % 8;
      rnd_y = rand() % 8;
      setvoxel(rnd_x, rnd_y, 7);
    }
  }

  if (currentTime - lastUpdateTime >= 1000)
  {
    count++;
    lastUpdateTime = currentTime;

    shift(AXIS_Z, -1);
  }

  return false;
}

Does this work? If it does, do you understand how it works? If not, ask! If it does not work, we need to look into that first.

Once it works, we can add a start and stop of the rain effect using the remote. After that we can look at adding a more complicated effect.

I understand that you're eager to see it all working but "haastige spoed is zelden goed" :slight_smile:

PS
Once you start having numbered variables, you should start using arrays.

Hi,

Removed everything from the loop and only pasted in your code. But it wont compile
error message ;

Arduino: 1.8.5 (Windows 7), Board:"Arduino/Genuino Mega or Mega 2560, ATmega2560 (Mega 2560)"

C:\Users\Roonie\Documents\Arduino\Roon_cube_Mega\Roon_cube_Mega.ino: In function 'bool effect_rain(int)':

Roon_cube_Mega:219: error: 'setvoxel' was not declared in this scope

       setvoxel(rnd_x, rnd_y, 7);

                               ^

Roon_cube_Mega:228: error: 'shift' was not declared in this scope

     shift(AXIS_Z, -1);

                     ^

exit status 1
'setvoxel' was not declared in this scope

Dit rapport zou meer informatie bevatten met
"Uitgebreide uitvoer weergeven tijden compilatie"
optie aan in Bestand -> Voorkeuren.

thankx

Roon_cube_Mega.ino (4.66 KB)

You removed a little bit to much :wink: At least we have something clean to start with 8)

From the code in reply #16

// Shift the entire contents of the cube along an axis
// This is great for effects where you want to draw something
// on one side of the cube and have it flow towards the other
// side. Like rain flowing down the Z axiz.
void shift (char axis, int direction)
{
  int i, x ,y;
  int ii, iii;
  int state;

  for (i = 0; i < 8; i++)
  {
    if (direction == -1)
    {
      ii = i;
    } else
    {
      ii = (7-i);
    } 
  
  
    for (x = 0; x < 8; x++)
    {
      for (y = 0; y < 8; y++)
      {
        if (direction == -1)
        {
          iii = ii+1;
        } else
        {
          iii = ii-1;
        }
        
        if (axis == AXIS_Z)
        {
          state = getvoxel(x,y,iii);
          altervoxel(x,y,ii,state);
        }
        
        if (axis == AXIS_Y)
        {
          state = getvoxel(x,iii,y);
          altervoxel(x,ii,y,state);
        }
        
        if (axis == AXIS_X)
        {
          state = getvoxel(iii,y,x);
          altervoxel(ii,y,x,state);
        }
      }
    }
  }
  
  if (direction == -1)
  {
    i = 7;
  } else
  {
    i = 0;
  } 
  
  for (x = 0; x < 8; x++)
  {
    for (y = 0; y < 8; y++)
    {
      if (axis == AXIS_Z)
        clrvoxel(x,y,i);
        
      if (axis == AXIS_Y)
        clrvoxel(x,i,y);
      
      if (axis == AXIS_X)
        clrvoxel(i,y,x);
    }
  }
}

Oh damn ..... :confused:

Now I see that some void effects need other pieces of code to run ...

But now I put that piece of code back in the loop I get some other errors.

So I copied some more code ... in fact from the part where is says draw functions all the way down.

Because altervoxel , getvoxel and some others also needed some extra code.

And now it does compile but only the top layer of the cube goes on and stays on .... :confused:

I think the code is not looping but why I do not know....

Roon_cube_Mega-test.ino (13.1 KB)

OK, that's a bug (probably) caused by if (count == 0). There is a bit of a chicken and egg problem where count is never updated because lastUpdateTime is always updated.

Looking into it.

I started with the below and tested on an Uno using serial monitor. It uses your original version of effect_rain except it does not call setvoxel and shift but prints to serial monitor; some additional debug was added. It also uses delay instead of delay_ms; reason is that delay_ms did not delay 1 second.
The
* *for (;;);* *
is used to only run once (I could have moved it to setup from that perspective).

void setup()
{
  Serial.begin(57600);
}

void loop()
{
  effect_rain(15);
  for (;;);
}

void effect_rain (int iterations) {

  PORTC = B11001100; // 4

  int i, ii;
  int rnd_x;
  int rnd_y;
  int rnd_num;

  for (ii = 0; ii < iterations; ii++)
  {
    Serial.println();
    Serial.print("currentTime = "); Serial.println(millis());
    Serial.print("iteration =   "); Serial.println(ii);
    rnd_num = rand() % 4;
    Serial.print("rnd_num = "); Serial.println(rnd_num);

    for (i = 0; i < rnd_num; i++)
    {
      rnd_x = rand() % 8;
      rnd_y = rand() % 8;
      Serial.print("rnd_x = "); Serial.println(rnd_x);
      Serial.print("rnd_y = "); Serial.println(rnd_y);
      Serial.println("setvoxel(rnd_x, rnd_y, 7)");
    }

    delay(1000);
    Serial.println("shift(AXIS_Z, -1");
  }
}

The output

currentTime = 0
iteration =   0
rnd_num = 3
rnd_x = 1
rnd_y = 1
setvoxel(rnd_x, rnd_y, 7)
rnd_x = 2
rnd_y = 2
setvoxel(rnd_x, rnd_y, 7)
rnd_x = 0
rnd_y = 0
setvoxel(rnd_x, rnd_y, 7)
shift(AXIS_Z, -1          <<<<<<< little bug in the code here, missing ')'

currentTime = 1021
iteration =   1
rnd_num = 2
rnd_x = 3
rnd_y = 5
setvoxel(rnd_x, rnd_y, 7)
rnd_x = 0
rnd_y = 5
setvoxel(rnd_x, rnd_y, 7)
shift(AXIS_Z, -1

currentTime = 2039
iteration =   2
rnd_num = 0
shift(AXIS_Z, -1

currentTime = 3040
iteration =   3
rnd_num = 2
rnd_x = 3
rnd_y = 7
setvoxel(rnd_x, rnd_y, 7)
rnd_x = 7
rnd_y = 1
setvoxel(rnd_x, rnd_y, 7)
shift(AXIS_Z, -1

currentTime = 4058
iteration =   4
rnd_num = 0
shift(AXIS_Z, -1

currentTime = 5058
iteration =   5
rnd_num = 0
shift(AXIS_Z, -1

currentTime = 6060
iteration =   6
rnd_num = 3
rnd_x = 1
rnd_y = 5
setvoxel(rnd_x, rnd_y, 7)
rnd_x = 5
rnd_y = 0
setvoxel(rnd_x, rnd_y, 7)
rnd_x = 5
rnd_y = 3
setvoxel(rnd_x, rnd_y, 7)
shift(AXIS_Z, -1

currentTime = 7086
iteration =   7
rnd_num = 2
rnd_x = 0
rnd_y = 7
setvoxel(rnd_x, rnd_y, 7)
rnd_x = 1
rnd_y = 2
setvoxel(rnd_x, rnd_y, 7)
shift(AXIS_Z, -1

currentTime = 8102
iteration =   8
rnd_num = 0
shift(AXIS_Z, -1

currentTime = 9104
iteration =   9
rnd_num = 3
rnd_x = 2
rnd_y = 1
setvoxel(rnd_x, rnd_y, 7)
rnd_x = 3
rnd_y = 5
setvoxel(rnd_x, rnd_y, 7)
rnd_x = 3
rnd_y = 5
setvoxel(rnd_x, rnd_y, 7)
shift(AXIS_Z, -1

currentTime = 10130
iteration =   10
rnd_num = 3
rnd_x = 0
rnd_y = 1
setvoxel(rnd_x, rnd_y, 7)
rnd_x = 0
rnd_y = 5
setvoxel(rnd_x, rnd_y, 7)
rnd_x = 1
rnd_y = 4
setvoxel(rnd_x, rnd_y, 7)
shift(AXIS_Z, -1

currentTime = 11156
iteration =   11
rnd_num = 3
rnd_x = 2
rnd_y = 5
setvoxel(rnd_x, rnd_y, 7)
rnd_x = 1
rnd_y = 1
setvoxel(rnd_x, rnd_y, 7)
rnd_x = 4
rnd_y = 0
setvoxel(rnd_x, rnd_y, 7)
shift(AXIS_Z, -1

currentTime = 12182
iteration =   12
rnd_num = 0
shift(AXIS_Z, -1

currentTime = 13184
iteration =   13
rnd_num = 2
rnd_x = 4
rnd_y = 4
setvoxel(rnd_x, rnd_y, 7)
rnd_x = 2
rnd_y = 7
setvoxel(rnd_x, rnd_y, 7)
shift(AXIS_Z, -1

currentTime = 14201
iteration =   14
rnd_num = 2
rnd_x = 2
rnd_y = 5
setvoxel(rnd_x, rnd_y, 7)
rnd_x = 0
rnd_y = 1
setvoxel(rnd_x, rnd_y, 7)
shift(AXIS_Z, -1

When using delay_ms instead of delay, the last iteration started at 922 ms.

currentTime = 922   <<<<<<< about one second
iteration =   14
rnd_num = 2
rnd_x = 2
rnd_y = 5
setvoxel(rnd_x, rnd_y, 7)
rnd_x = 0
rnd_y = 1
setvoxel(rnd_x, rnd_y, 7)
shift(AXIS_Z, -1

Next I fixed my version of effect_rain. To be able to compare, again serial prints were used.

void setup()
{
  Serial.begin(57600);
}

unsigned long currentTime;
void loop()
{
  currentTime = millis();
  if (effect_rain(15) == true)
  {
    for (;;);
  }
}

/*
  effect 4 rain
  In:
    number of iterations
  Returns:
    true if all iterations completed, else false
*/
bool effect_rain (int iterations)
{
  // count the number of iterations; used to be ii
  static int count;
  // last time that the cube was updated
  static unsigned long lastUpdateTime;

  PORTC = B11001100; // 4

  int i;
  int rnd_x;
  int rnd_y;
  // this now needs to be static so it's remembered between successive calls to effect_rain
  static int rnd_num;

  // if number of iterations completed
  if (count >= iterations)
  {
    // done, reset count
    count = 0;

    // and indicate to called that we're finished
    return true;
  }

  // if 'first' call or 1 second lapsed
  if (count == 0 || (currentTime - lastUpdateTime >= 1000))
  {
    Serial.println();
    Serial.print("currentTime = "); Serial.println(currentTime);
    Serial.print("iteration =   "); Serial.println(count);
    rnd_num = rand() % 4;
    Serial.print("rnd_num = "); Serial.println(rnd_num);

    for (i = 0; i < rnd_num; i++)
    {
      rnd_x = rand() % 8;
      rnd_y = rand() % 8;
      Serial.print("rnd_x = "); Serial.println(rnd_x);
      Serial.print("rnd_y = "); Serial.println(rnd_y);
      Serial.println("setvoxel(rnd_x, rnd_y, 7)");
    }
    count++;
    lastUpdateTime = currentTime;

    Serial.println("shift(AXIS_Z, -1)");
  }

  // indicate that effect_rain is still in progress
  return false;
}

And the output

currentTime = 0
iteration =   0
rnd_num = 3
rnd_x = 1
rnd_y = 1
setvoxel(rnd_x, rnd_y, 7)
rnd_x = 2
rnd_y = 2
setvoxel(rnd_x, rnd_y, 7)
rnd_x = 0
rnd_y = 0
setvoxel(rnd_x, rnd_y, 7)
shift(AXIS_Z, -1)

currentTime = 1000
iteration =   1
rnd_num = 2
rnd_x = 3
rnd_y = 5
setvoxel(rnd_x, rnd_y, 7)
rnd_x = 0
rnd_y = 5
setvoxel(rnd_x, rnd_y, 7)
shift(AXIS_Z, -1)

currentTime = 2000
iteration =   2
rnd_num = 0
shift(AXIS_Z, -1)

currentTime = 3000
iteration =   3
rnd_num = 2
rnd_x = 3
rnd_y = 7
setvoxel(rnd_x, rnd_y, 7)
rnd_x = 7
rnd_y = 1
setvoxel(rnd_x, rnd_y, 7)
shift(AXIS_Z, -1)

currentTime = 4000
iteration =   4
rnd_num = 0
shift(AXIS_Z, -1)

currentTime = 5000
iteration =   5
rnd_num = 0
shift(AXIS_Z, -1)

currentTime = 6000
iteration =   6
rnd_num = 3
rnd_x = 1
rnd_y = 5
setvoxel(rnd_x, rnd_y, 7)
rnd_x = 5
rnd_y = 0
setvoxel(rnd_x, rnd_y, 7)
rnd_x = 5
rnd_y = 3
setvoxel(rnd_x, rnd_y, 7)
shift(AXIS_Z, -1)

currentTime = 7000
iteration =   7
rnd_num = 2
rnd_x = 0
rnd_y = 7
setvoxel(rnd_x, rnd_y, 7)
rnd_x = 1
rnd_y = 2
setvoxel(rnd_x, rnd_y, 7)
shift(AXIS_Z, -1)

currentTime = 8000
iteration =   8
rnd_num = 0
shift(AXIS_Z, -1)

currentTime = 9000
iteration =   9
rnd_num = 3
rnd_x = 2
rnd_y = 1
setvoxel(rnd_x, rnd_y, 7)
rnd_x = 3
rnd_y = 5
setvoxel(rnd_x, rnd_y, 7)
rnd_x = 3
rnd_y = 5
setvoxel(rnd_x, rnd_y, 7)
shift(AXIS_Z, -1)

currentTime = 10000
iteration =   10
rnd_num = 3
rnd_x = 0
rnd_y = 1
setvoxel(rnd_x, rnd_y, 7)
rnd_x = 0
rnd_y = 5
setvoxel(rnd_x, rnd_y, 7)
rnd_x = 1
rnd_y = 4
setvoxel(rnd_x, rnd_y, 7)
shift(AXIS_Z, -1)

currentTime = 11000
iteration =   11
rnd_num = 3
rnd_x = 2
rnd_y = 5
setvoxel(rnd_x, rnd_y, 7)
rnd_x = 1
rnd_y = 1
setvoxel(rnd_x, rnd_y, 7)
rnd_x = 4
rnd_y = 0
setvoxel(rnd_x, rnd_y, 7)
shift(AXIS_Z, -1)

currentTime = 12000
iteration =   12
rnd_num = 0
shift(AXIS_Z, -1)

currentTime = 13000
iteration =   13
rnd_num = 2
rnd_x = 4
rnd_y = 4
setvoxel(rnd_x, rnd_y, 7)
rnd_x = 2
rnd_y = 7
setvoxel(rnd_x, rnd_y, 7)
shift(AXIS_Z, -1)

currentTime = 14000
iteration =   14
rnd_num = 2
rnd_x = 2
rnd_y = 5
setvoxel(rnd_x, rnd_y, 7)
rnd_x = 0
rnd_y = 1
setvoxel(rnd_x, rnd_y, 7)
shift(AXIS_Z, -1)

With exception of the currentTime values (and the little bug with ')', my modified effect_rain gives the same output results so I'm comfortable that the next post will work for you.

Note the use of the return value of effect_rain in loop. effect_rain returns true if the number of iterations has been completed, else it returns false. In the example, it's used to only run a full number of iterations once.

effect_rain for your project; it's identical to the above but the serial prints are removed and setvoxel and shift are used.

/*
  effect 4 rain
  In:
    number of iterations
  Returns:
    true if all iterations completed, else false
*/
bool effect_rain (int iterations)
{
  // count the number of iterations; used to be ii
  static int count;
  // last time that the cube was updated
  static unsigned long lastUpdateTime;

  PORTC = B11001100; // 4

  int i;
  int rnd_x;
  int rnd_y;
  // this now needs to be static so it's remembered between successive calls to effect_rain
  static int rnd_num;

  // if number of iterations completed
  if (count >= iterations)
  {
    // done, reset count
    count = 0;

    // and indicate to called that we're finished
    return true;
  }

  // if 'first' call or 1 second lapsed
  if (count == 0 || (currentTime - lastUpdateTime >= 1000))
  {
    rnd_num = rand() % 4;

    for (i = 0; i < rnd_num; i++)
    {
      rnd_x = rand() % 8;
      rnd_y = rand() % 8;
      setvoxel(rnd_x, rnd_y, 7);
    }
    count++;
    lastUpdateTime = currentTime;

    shift(AXIS_Z, -1);
  }

  // indicate that effect_rain is still in progress
  return false;
}

Implement this in the code that you showed in reply #20 and it should work.

Now remember the comment about delay_ms in the previous post. The above code will 'rain' a lot slower; you can adjust the 1000 in the below to e.g. 100 to speed it up.

  // if 'first' call or 1 second lapsed
  if (count == 0 || (currentTime - lastUpdateTime >= 1000))

Wow .. super thankx,

Thats a lot to learn... :o Got the effect to work !! Now I need to understand how it works and how I can get it in the bigsketch ... I tried copy and paste ... but no joy. And I know hastig spoed is zelden goed... but hey, wie niet waagt wie niet wint .....

But Im defenitly going to studie this, cause a lag in my remote isnt what I want.

happy easter

If you don't understand, ask. I will try to explain.

As first step for going further, you can try to stop and start the effect_rain when pressing buttons on the remote. (e.g. 1-> start and 2 -> stop). That should give you an understanding.

You will need to modify all your effects; take one at a time.

I think I mentioned state machine for the more complicated effects. When you get there, shout.

Maybe the Roon effect is a good starting point to explain and show a state machine. A state machine breaks down your code in little steps and each time you call Roon it will go to the next steps (if conditions are satisfied, e.g. a delay has lapsed or a letter is displayed).

Your comments in Roon already give you a guidance (//R, //o, //o and //n); there are a few more. You start with a fill(), next you do letters, next you move stuff and lastly you do a fill again. In between you have all kinds of delays.

fill
R
o
o
n
shift
fill

Now each letter consists of setting some voxels and a delay, setting some other voxels, delay again etc.

Every time you do one or more statements (setvoxel, shift) that is/are followed by a delay_ms, you have two steps. The fills also count as steps. If I counted correctly, you have 57 steps.

// effect 2 text Roon
void Roon() {

  PORTC = B10110110; // 2

1)
  fill(0x00);
  
  //R
2)
  setvoxel(0, 7, 0);
  ...
3)
  delay_ms(5000);
4)
  setvoxel(0, 7, 4);
  ...
5)
  delay_ms(5000);
6)
  setvoxel(0, 7, 3);
  ...
  shift(AXIS_X, 1);
7)
  delay_ms(5000);
8)
  setvoxel(0, 7, 0);
  ...
  shift(AXIS_X, 1);
9)
  delay_ms(5000);
10)
  shift(AXIS_X, 1);
11)
  delay_ms(6000);
  //o
12)
  setvoxel(0, 7, 1);
  ...
  shift(AXIS_X, 1);
13)
  delay_ms(5000);
14)
  setvoxel(0, 7, 0);
  ...
  shift(AXIS_X, 1);
15)
  delay_ms(5000);
16)
  setvoxel(0, 7, 0);
  ...
  shift(AXIS_X, 1);
17)
  delay_ms(5000);
18)
  setvoxel(0, 7, 1);
  ...
  shift(AXIS_X, 1);
19)
  delay_ms(5000);
20)
  shift(AXIS_X, 1);
21)
  delay_ms(6000);
  //o
21)
  setvoxel(0, 7, 1);
  ...
  shift(AXIS_X, 1);
22)
  delay_ms(5000);
23)
  setvoxel(0, 7, 4);
  ...
  shift(AXIS_X, 1);
24)
  delay_ms(5000);
25)
  setvoxel(0, 7, 4);
  ...
  shift(AXIS_X, 1);
26)
  delay_ms(5000);
27)
  setvoxel(0, 7, 1);
  ...
  shift(AXIS_X, 1);
28)
  delay_ms(5000);
29)
  shift(AXIS_X, 1);
30)
  delay_ms(6000);
  //n
31)
  setvoxel(0, 7, 0);
  ...
  shift(AXIS_X, 1);
32)
  delay_ms(5000);
33)
  setvoxel(0, 7, 4);
  shift(AXIS_X, 1);
34)
  delay_ms(5000);
35)
  setvoxel(0, 7, 4);
  shift(AXIS_X, 1);
36)
  delay_ms(5000);
37)
  setvoxel(0, 7, 0);
  ...
  shift(AXIS_X, 1);
38)
  delay_ms(5000);
39)
  shift(AXIS_X, 1);
40)
  delay_ms(6000);
41)
  shift(AXIS_X, 1);
42)
  delay_ms(5000);
43)
  shift(AXIS_X, 1);
44)
  delay_ms(5000);
45)
  shift(AXIS_X, 1);
46)
  delay_ms(5000);
47)
  shift(AXIS_X, 1);
48)
  delay_ms(5000);
49)
  shift(AXIS_X, 1);
50)
  delay_ms(5000);
51)
  shift(AXIS_X, 1);
52)
  delay_ms(5000);
53)
  shift(AXIS_X, 1);
54)
  delay_ms(5000);
55)
  shift(AXIS_X, 1);
56)
  delay_ms(3500);
57)
  fill(0x00);
}

I do not understand why you did not implement steps 39 to 56 in e.g. a for-loop; maybe inexperience.
E.g.

// shift 7 times with a delay of 5000
for(int cnt=0;cnt<7;cnt++)
{
  shift(AXIS_X,1);
  delay_ms(5000);
}
// shift one more with a delay of 3500
shift(AXIS_X,1);
delay_ms(5000);

Anyway, that does not matter too much.

A simple way to implement a state machine is the use of a switch/case construction.

/*
  display Roon
  Returns:
    true if completed, else false
*/
bool effect_Roon()
{
  // remember what we are going to do
  static byte currentState = 1;
  
  switch(currentState)
  {
    case 1:
      fill(0x00);
      // done with this state, next time we call effect_Roon do the next step
      currentState++;
      break;
    case 2:
      setvoxel(0, 7, 0);
      setvoxel(0, 7, 1);
      setvoxel(0, 7, 2);
      setvoxel(0, 7, 3);
      setvoxel(0, 7, 4);
      setvoxel(0, 7, 5);
      setvoxel(0, 7, 6);
      setvoxel(0, 7, 7);
      shift(AXIS_X, 1);
      // done with this state, next time we call effect_Roon do the next step
      currentState++;
      break;
    case 3:
      delay_ms(5000);
      // done with this state, next time we call effect_Roon do the next step
      currentState++;
      break;
    case 4:
      setvoxel(0, 7, 4);
      setvoxel(0, 7, 7);
      shift(AXIS_X, 1);
      currentState++;
      break;
    case 5:
      delay_ms(5000);
      currentState++;
      break;

    ...
    ...
    case 57:
      fill(0x00);
      // done with this state, next time we call effect_Roon do first step
      currentState=0;
      // indicate that the effect is finished
      return true;
  }
  // indicate that effect is in progress
  return true;
}

Note that I have renamed Roon to effect_roon for a more consistent naming with other effects.

Because of all the delay_ms calls, we will end up with the 57 states. We can reduce this by roughly 50% if we dedicate one state to delay. For this, I'm going to reserve a number of numbers (1..10); this allows for a bit of growth if needed; the normal cases will start at 11. To make this work, you need to remember where to go after the delay; you also need to setup a delay duration.

#define ROON_DELAYSTATE 1

/*
  display Roon
  Returns:
    true if completed, else false
*/
bool effect_Roon()
{
  // remember what we are going to do; now start at 11
  static byte currentState = 11;
  // where to go after a delay
  static byte stateAfterDelay = 0;
  // we will also keep a variable for the required delay duration
  static unsigned long delayDuration;
  
  switch(currentState)
  {
    case ROON_DELAYSTATE:
      delay_ms(delayDuration);
      // next time effect_roon is called, execute the indicated step
      currentState = stateAfterDelay;
      break;
    case 11:
      fill(0x00);
      // done with this state, next time we call effect_Roon do the next step
      currentState++;
      break;
    case 12:
      setvoxel(0, 7, 0);
      setvoxel(0, 7, 1);
      setvoxel(0, 7, 2);
      setvoxel(0, 7, 3);
      setvoxel(0, 7, 4);
      setvoxel(0, 7, 5);
      setvoxel(0, 7, 6);
      setvoxel(0, 7, 7);
      shift(AXIS_X, 1);
      // we're going to do a delay after this step; remember which step we want to do after the delay
      stateAfterDelay = currentState + 1;
      // set delay duration to 5000
      delayDuration = 5000;
      // done with this state, next time we call effect_Roon, do a delay
      currentState = ROON_DELAYSTATE;
      break;
    case 13:
      setvoxel(0, 7, 4);
      setvoxel(0, 7, 7);
      shift(AXIS_X, 1);
      // setup the delay step
      stateAfterDelay = currentState + 1;
      delayDuration = 5000;
      currentState = ROON_DELAYSTATE;
      break;
    case 14:
      setvoxel(0, 7, 3);
      setvoxel(0, 7, 4);
      setvoxel(0, 7, 7);
      shift(AXIS_X, 1);
      // setup the delay step
      stateAfterDelay = currentState + 1;
      delayDuration = 5000;
      currentState = ROON_DELAYSTATE;
      break;
    ...
    ...
    case xx:
      fill(0x00);
      // done with this state, next time we call effect_Roon do first step
      currentState=0;
      break;
  }
}

Now, in state 12 (was state 2), we first prepare for the delay. We remember that we need to go to state 13 after the delay, we specify the delay duration and next instead of incrementing the step, we set the step to be the delay step.

In the delay step, we call delay_ms and once that's finished we set the step to the stateAfterDelay variable.

Now basically the only thing left is to implement a non-blocking delay using millis() replacing delay_ms.

/*
  non-blocking delay; call repetitively
  In:
    delay in milliseconds
  Returns:
    true if duration has lapsed, else false
*/
bool delayMS(unsigned long duration)
{
  // remember when the delay was started
  static unsigned long delayStartTime;
  // remember if delay in progress
  static bool inProgress = false;
  
  // if delay is not in progress, 'start' it
  if(inProgress == false)
  {
    inProgress = true;
    delayStartTime = currentTime;
  }
  
  if(currentTime - delayStartTime >= duration)
  {
    inProgress = false;
    // indicate that duration has lapsed
    return true;
  }
  else
  {
    // indicate that delay is not finished yet
    return false;
  }
}

You can use this in the ROON_DELAYSTATE as shown below

    case ROON_DELAYSTATE:
      // if duration lapsed
      if(delayMS(delayDuration) == true)
      {
        // next time effect_roon is called, execute the indicated step
        currentState = stateAfterDelay;
      }
      else
      {
        // if the delay did not lapse yet, we stay in the same state
      }
      break;

I would probably not set effect_roon up this way, but this is easier for you to follow as it better follows your original. Unfortunately a lot of cases inside the switch.

delayMS is tested, the rest as a guide line to get you started.

Yes yes,

I also have changed one of the effects, like you did with the rain effect. It was a lot of
trial and error but it works now, as a stand alone and also in my big sketch`.

Have a look at the sketch mayby there is something that can be beter, it`s probably
not the best or neatest coding but it gets the job done.... 8)

again thx for explaining it al ..... :wink:

Now Ill see if there are others that can also be changed like that, then Ill have a look
at the state machine thing .....

Roon_cube_Mega-worm.ino (13.7 KB)

:slight_smile:

Wel you really explained the state machinegood ..... I also got that one working.
Now I only have two effects left . The effect boxside and jumping box .. :confused:

Havent got a good look at them yet ....... This reprogramming is taking up a long time ... but its worth it.

thankx again