nested delay

Hi
I am building a neopixel animated clock which requires several “for” loops incorporating delays. I need these to be non blocking. Here is a cut down example of what I am trying. It keeps crashing and rebooting.

int i;
void setup() { 
  Serial.begin(115200);   
}
void loop() {
 static unsigned long last = millis();
  if (millis() - last > 5000) {
  last = millis();
i=0;
Serial.println("new loop-----------------");
testLoop();
} 

}
void testLoop(){
do {     
   static unsigned long lastL = millis();
  if (millis() - lastL > 500) {
  lastL = millis();
       Serial.print("loop number : ");Serial.println(i);
       //do stuff
       i++;     
     }
  
  } while (i<7);
}

Your posted program runs OK for me

As to your question, you need to restructure your program, perhaps to use a state machine to execute only required code for the current state each time through loop().

For instance, if you had a state named TEST_LOOP then the code block for that state would test whether it is time to print the loop number, increment the counter and save the time ready for the next check. There would be no blocking do/while and you would use loop() to do the looping

thanks for the response.
It’s strange that the code runs OK for you. On my Wemos is consistently crashes and reboots at 5 counts.
If I reduce the testLoop interval it will run.
Anyway I will investigate “state machine” and see if I can work it out.

I’m not sure if it has side effects or not, but this is a really weird place to put this declaration:

  do {
    static unsigned long lastL = millis();

Have a look at this

enum states
{
  WAITING_TO_COUNT,
  COUNTING
};

states currentState = WAITING_TO_COUNT;
unsigned long currentTime;
unsigned long startTime;
unsigned long waitPeriod = 5000;
unsigned long countPeriod = 500;
byte counter = 0;

void setup()
{
  Serial.begin(115200);
  while (!Serial);
  startTime = millis();
}

void loop()
{
  currentTime = millis();
  switch (currentState)
  {
    case WAITING_TO_COUNT:
      if (currentTime - startTime >= waitPeriod)  //change state if wait period is over
      {
        currentState = COUNTING;
        counter = 0;
        startTime = currentTime;
        Serial.println("new loop");
      }
      break;
    case COUNTING:
      if (currentTime - startTime >= countPeriod) //time for new counter value ?
      {
        counter++;
        if (counter > 6)  //all done counting.  Change state
        {
          currentState = WAITING_TO_COUNT;
          startTime = currentTime;
        }
        else  //otherwise print the current value
        {
          Serial.print("loop number : ");
          Serial.println(counter);
          startTime = currentTime;
        }
      }
      break;
  }
  //any other non blocking code can go in loop()
}

Fantastic. Thank you so much. I’ve never used states before but can see the obvious logic to it all and will use it in future.
And yes it works!

yes it works!

Whoop, whoop !

State machines are not the answer to every problem but they are certainly useful.
A few things to note about my example :

The meaningful names given to the states
The use of an enum to define the states means that we do not have to know their values, merely their name
The use of switch/case instead of if/else which to my mind is easier to read and understand
The way that the entry values for the target state are set up before changing state, for example, startTime
That none of the code in any state blocks the free running of loop(), rather it exploits it
Note that you could have 2 (or more) state machines in loop() if required

You may be interested in Several Things in Succession