So you're a Noob? Post your questions here until you graduate! Don't be shy.

User avatar
By btidey
#81099 This is the type of structure I commonly use.
Code: Select all#define STATE_0 0
#define STATE_1 1
#define STATE_2 2

int state = STATE_0;
int counter;

void stateMachine() {
   switch(state) {
      case STATE_0 :
         //check whether a state transition should be made
         if(counter > 20) {
            //set state to transition to
            state = STATE_1;
            //do actions on changing state
            Serial.println("Switching to state 1");
            counter = 0;
         }
         break;
      case STATE_1 :
         if(counter > 30) {
            state = STATE_2;
            Serial.println("Switching to state 2");
            counter = 0;
         }
         break;
      case STATE_2 :
         if(counter > 40) {
            state = STATE_0;
            Serial.println("Switching to state 0");
            counter = 0;
         }
         break;
   }
}

setup {
   Serial.begin(115200);
}

loop {
   stateMachine();
   // do other stuff
   counter++;
   delay(100);
}


Note that several different state machines can be called from the main loop to manage different activities. The counter in the example is just a trivial method to show transitions. Normally one might be testing for other conditions. State transitions can also be triggered by other activities. E.g. a button press or a web server call may change state and trigger a sequence of activities through further state transitions.
User avatar
By RichardS
#81102 You can also use yield(); exactly the same as delay(0);

In theory it delays zero milliseconds, as opposed to the user who said use delay(1) which will delay a fill millisecond...

Its just not as obvious to use delay(0) as it seems wrong.

RichardS
User avatar
By eben80
#86279 Hi everyone,
I'm having an issue with this too and yield or delay does not seem to help as it still bootloops.

Loop code:
Code: Select allvoid loop()
{
  count = (count + 1) % 10; // keep count between 0 to 9

  my_tube1.crossfade_init(count, 15, 127, 0);
  my_tube2.crossfade_init(10-count, 15, 127, 0);
  // my_tube3.crossfade_init(count, 15, 127, 0);
  // my_tube4.crossfade_init(10-count, 15, 127, 0);

  /*
      again, crossfade_run() is non-blocking, that means
    you can run other tasks in the loop.
      just make sure to call it at least every 33ms
    and check its return value to see if it's finished.
  */
  while(1)
  {
    yield();
    unsigned char result1 = my_tube1.crossfade_run();
    unsigned char result2 = my_tube2.crossfade_run();
    // unsigned char result3 = my_tube2.crossfade_run();
    // unsigned char result4 = my_tube2.crossfade_run();
    // exit when both animations are finished
    if(result1 == EXIXE_ANIMATION_FINISHED && result2 == EXIXE_ANIMATION_FINISHED)
      break;
  }

  my_tube1.set_led(127, 40, 0); // orange;
  my_tube2.set_led(127, 0, 127); // purple;
  my_tube3.set_led(127, 40, 0); // orange;
  my_tube4.set_led(127, 0, 127); // purple;
 
  delay(500);
}


Offending exixe library code https://github.com/dekuNukem/exixe:
Code: Select allunsigned char exixe::crossfade_run()
{
  unsigned long current_frame = (millis() / EXIXE_ANIMATION_FRAME_DURATION_MS) - animation_start_frame;
 Serial.println(current_frame);
  if(current_frame > animation_duration)
  {
    animation_src_digit = animation_dest_digit;
    return EXIXE_ANIMATION_FINISHED;
  }

  memset(spi_buf, 0, EXIXE_SPI_BUF_SIZE);
  memset(spi_buf, 0x80, EXIXE_SPI_BUF_SIZE - 5);
  spi_buf[0] = animation_overdrive ? EXIXE_SPI_HEADER_OD : EXIXE_SPI_HEADER;
 
  unsigned char temp = cap_float(animation_step * (float)current_frame);
  spi_buf[animation_src_digit] = 0x80 | (animation_brightness - temp);
  spi_buf[animation_dest_digit] = 0x80 | temp;
  spi_write();

  return EXIXE_ANIMATION_IN_PROGRESS;
}