Delay without blocking - Please help

Hi
I'm almost embarrased to present this post. I am developing an Arduino-ESP-01 TCPClient Server solution using coding that does not involve the delay() function. But I cannot get my head around using a non-blocking delay that I want to use to increment a counter variable every 5 seconds. I have reduced the project coding to the extract below which shows that the statCounter variable retains the value 1 and is not incremented. The Serial Monitor does correctly update this value at 5sec intervals. I'm sure there is a trivial error, but I just cant get my head around a solution after 2 hours and n cups of coffee!! It is based on the 'Blink without delay' tutorial.
many thanks in anticipation of your help.

const long interval = 5000;
unsigned long previousMillis = 0;
int statCounter;  //counter variable

void setup() {

Serial.begin(9600);
statCounter = 0;

}

void loop() {
         unsigned long currentMillis = millis();
               
       if (currentMillis - previousMillis >= interval)
       {        
        previousMillis = currentMillis;      
        statCounter=statCounter+1; //increment counter
        Serial.println(statCounter);
        
          if(statCounter=10){
                  statCounter=0;  //reset counter
        }    
       }
       
}// end loop


[\code]
// if(statCounter=10)
 if(statCounter==10)

Try this:

const long interval = 5000;

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

void loop() {
   static long currentMillis;
   static byte statCounter = 0;
   if (millis() - currentMillis >= interval)
   {
      if (statCounter> 10)
      {
         statCounter = 0;
      }
      statCounter++;
      Serial.println(statCounter);

      currentMillis = millis():
   }

}// end loop
[\code]

Hi both
Many thanks for your help - much appreciated. As I suspected a relatively minor change! Both solutions worked for me. I think I will now have a whiskey rather than the copius amounts of coffee. Pity you were not local - we could share a Scotch!
Thanks again.

I love that you celebrate victory with scotch!
Single malt or blended?

I might be off topic but... SCOTCH!

Now you have a simple loop(), but if it was more time consuming you could end up having your time slip a few tenths of a second for every iteration. It adds up to quite some time after a while.
To prevent this to happen you can change

previousMillis = currentMillis;

To
previousMillis = previousMillis+interval; 

Thanks for that additional tip which I have have now incorporated into the ESP8266-Arduino Sketch. Re earlier 'off topic' comment: Single Malt ... and it's all gone now sorry! (can't reveal the brand!).
Thanks again for your very helpful replies.
Mike

You should use unsigned longs for the timing variables to avoid problems with millis() rollover.

Thanks for your commentUKHeliBob - will incorporate suggestion.

Mike_Cymru:
we could share a Scotch!

.... but you're a Taff

The demo Several Things at a Time illustrates the use of millis() to manage timing. It may help with understanding the technique.

...R

I don't know if it matches your needs, but have you thought about setting up a timer that calls an interrupt every 5 seconds? You can increment your counter (or set a flag, etc..) inside the function that is called by the interrupt.

MattFL:
have you thought about setting up a timer that calls an interrupt every 5 seconds?

I could understand the use of a Timer for something that must happen every 5 millisecs - but I can’t see an need for it if the interval is 5 seconds. Indeed, it may not even be necessary for an interval as long as 5 millisecs.

…R

Not that it would be "necessary", but it would remove all that timing code from your loop() and might make the code easier to read and maintain, and possibly easier to implement power saving features (sleep) without missing your time events.

MattFL:
Not that it would be "necessary", but it would remove all that timing code from your loop() and might make the code easier to read and maintain, and possibly easier to implement power saving features (sleep) without missing your time events.

The Timers (except Timer2 in Asynchronous mode) only work in IDLE, which means millis() will stay running. And using Timer2 in Asynchronous mode to use Power Save sleep mode is definitely one of the more advanced techniques.

I'm just learning this stuff so you likely know more than me; but the watchdog timer will run in SLEEP_MODE_PWR_DOWN, and will call an interrupt when it expires. You can increment the count in the interrupt routine. If you want the chip to keep sleeping after it increments the counter then just have your sleep routine put it right back to sleep if there are no other jobs pending. I'm assuming the watchdog timer will still cause an interrupt even when the chip isn't sleeping?

My timer function is part of my Arduino - ESP (peripheral) code used in conjunction with a conditional statement which checks the number of failed Tx requests from an ESP8266 TCP Client. Timing accuracy in this regard is not critcal therefore. If within a given interval no Client requests are received, functions are called which hard reset the ESP-01 and re-initialize the TCP Server's WiFi layer functionality. Thanks to your comments now making good progress on this project.

I like the idea of exploring an interrupt driven approach but haven't coded the use of interrupts except using m/code on microchip microcontrollers many years ago not C++! Can you point me to examples or tutorials please. I am implementing an operational status register for the Server and setting Flags using this technique could prove beneficial here.

This is a good place to start:

https://www.arduino.cc/en/Reference/attachInterrupt

After the interrupt is processed,your main code will resume where it left off when the interrupt occurred. There are quite a few examples and write-ups for using the watchdog timer to trigger an interrupt, google "arduino watchdog timer interrupt" and you'll get a list of nice write ups.

Many thanks for the reference. Will pursue.
Mike

The only issue to watch out for is that the WDT uses its own RC oscillator (128 kHz frequency) that has pretty terrible tolerance. It’s fine if you just want to time events for yourself, but if you want to use it to coordinate actions between two independent controllers I know from first-hand experience that it isn’t that good.