Separate Looping code?

Hey guys

I have tried to get two separate functions to execute independently at the same time and cant seem to get anything other than a cascaded result no matter what I try…

EG: this basic example I would like the light to toggle on/off every second whilst separately executing the “up-time” publish function.

At the moment, the led flashes on, then off, then up-time is published, then wait for up-time delay to complete before the led flash again.

Should I be using a “nested loop”? I have tried but unable to get anything happening!

Any assistance appreciated!!

Cheers

unsigned long lastTime = 0UL;
char publishString[40];
int led = D7;

void setup() {
    pinMode(led, OUTPUT);


}

void loop() {

  digitalWrite(led, HIGH);
  delay(1000);
  digitalWrite(led, LOW);
  delay(1000);

    
    
    unsigned long now = millis();
    //Every 15 seconds publish uptime
    if (now-lastTime>15000UL) {
        lastTime = now;
        // now is in milliseconds
        unsigned nowSec = now/1000UL;
        unsigned sec = nowSec%60;
        unsigned min = (nowSec%3600)/60;
        unsigned hours = (nowSec%86400)/3600;
        sprintf(publishString,"%u:%u:%u",hours,min,sec);
        Spark.publish("Uptime",publishString);
    }
  delay(10000);

}

Delays will… Wait for it… Delay. Who would’ve guessed?
A delay will halt the microcontroller, having it do absolutely nothing until the day is over. Rather than doing your timing like that, try implementing ‘soft-delays’, like you have for the publish functionality by using the millis timer.
Or use software timers to set a flag which you check for in the loop, or…

Not sure if this is what you mean?

If not can please demonstrate how to run two looping functions without effecting each other by providing an example??

unsigned long lastTime = 0UL;
unsigned long lastTime2 = 0UL;
char publishString[40];
int led = D7;

void setup() {
    pinMode(led, OUTPUT);
}

void loop() {
    unsigned long now = millis();
    //Every 15 seconds publish uptime
    if (now-lastTime>15000UL) {
        lastTime = now;
        // now is in milliseconds
        unsigned nowSec = now/1000UL;
        unsigned sec = nowSec%60;
        unsigned min = (nowSec%3600)/60;
        unsigned hours = (nowSec%86400)/3600;
        sprintf(publishString,"%u:%u:%u",hours,min,sec);
        Spark.publish("Uptime",publishString);
    }
  delay(100);
      unsigned long now2 = millis();
          //Every 2 seconds Flash Light Sequence
      if (now2-lastTime2>2000UL) {
         digitalWrite(led, HIGH);
          delay(1000);
         digitalWrite(led, LOW);
         delay(1000);
      }

}

Sort of, but you’d need to update lastTime2 inside of the respective conditional block.
And remove all delay()s and rather toggle the LED like this

  if(now - lastTime2 > 1000)
  {
    lastTime2 = now;
    digitalWrite(led, !digitalRead(led));
  }
3 Likes

Thanks @ScruffR for taking the time to help with this and providing example.
Using your example I was able to come up with the following which I will share for future reference with fellow Particle / C# enthusiasts having same query!
Many thanks :smile:

  void loop()
{
     unsigned long LoopTimeAcc01 = millis();
     unsigned long LoopTimeAcc02 = millis();
    
// First looping routine:
     if (LoopTimeAcc01 - LoopTimer01 > 3000)
     {
         LoopTimer01 = LoopTimeAcc01;
         	digitalWrite(Led01_EN, !digitalRead(Led01_EN));
     }
    
// Second looping routine:
    if (LoopTimeAcc02 - LoopTimer02 > 500)
     {
         LoopTimer02 = LoopTimeAcc02;
         	digitalWrite(Led02_EN, !digitalRead(Led02_EN));
     }
}
1 Like

Just another note;
Since LoopTimeAcc01 & LoopTimeAcc02 are always only holding the “same” value, you can drop one :wink:

1 Like

@Moors7 Thank you for your suggestions, although I didn’t seem to understand the soft-delays at the time.

Interested in an example on your software timers reference - would you kindly explain using my example please?

That’s the place to look at when it comes to Software Timers :wink:
https://docs.particle.io/reference/firmware/photon/#software-timers

2 Likes

Cheers @ScruffR

Also, what’s your take on the following:

I would have thought…
after 3 seconds, turn on Led01_EN
after 1 additional second, turn off Led01_EN

(essentially acting like a delay to hold the LED on for one second, without halting the controller?) whilst still allowing the second loop routine to run, undisturbed?

\void loop() 
{
     unsigned long LoopTimeAcc = millis();

    
// First looping routine:
     if (LoopTimeAcc - LoopTimer01 > 3000)
     {
         LoopTimer01 = LoopTimeAcc;
         	digitalWrite(Led01_EN, HIGH);
     }
     if (LoopTimeAcc - LoopTimer03 > 4000)
     {
         LoopTimer03 = LoopTimeAcc;
         	digitalWrite(Led01_EN, LOW);
     }
    
// Second looping routine:
    if (LoopTimeAcc - LoopTimer02 > 500)
     {
         LoopTimer02 = LoopTimeAcc;
         	digitalWrite(Led02_EN, !digitalRead(Led02_EN));
     }
}

With your code there you have three independent/async “loops”, but you want the first two to act in sync with each other, make them share one “timer”.

OK, ive had a go but not working still :confused:

Trying to turn ON LED1 after three seconds, then after a further 10 seconds (using the timer) turn OFF LED1. Repeat.

All without effecting the second looping routine.

    void Timer1DN() 
{
digitalWrite(Led01_EN, LOW);
}

Timer Timer1(10000, Timer1DN); 
//

void setup() 
{
    // Set mode of pins
	pinMode(Led01_EN, OUTPUT);
	pinMode(Led02_EN, OUTPUT);
    // Initial state
	digitalWrite(Led01_EN, LOW);
	digitalWrite(Led02_EN, LOW);
}

void loop() 
{
     unsigned long LoopTimeAcc = millis();

    
// First looping routine:
     if (LoopTimeAcc - LoopTimer01 > 3000)
     {
         LoopTimer01 = LoopTimeAcc;
         digitalWrite(Led01_EN, HIGH);
         Timer1.start();
     }
     
// Second looping routine:
    if (LoopTimeAcc - LoopTimer02 > 500)
     {
         LoopTimer02 = LoopTimeAcc;
         	digitalWrite(Led02_EN, !digitalRead(Led02_EN));
     }
}

I’d rather stick with the conventional aproach first - once you got the hang of that, you can move on to software timers as they are slightly more involved when it comes to what goes and what not inside a timer callback.

With conventional, there are several options, but one would look like this

void loop() 
{
  unsigned long LoopTimeAcc = millis();

  // treat the less frequent action first, since it might impact the more frequent one
  if (LoopTimeAcc - LoopTimer03 > 4000)  // use the same timer variable for both linked actions
  {
    LoopTimer01 = LoopTimeAcc;  // only after the full task is completed, reset the timer
    digitalWrite(Led01_EN, LOW);
  }

  if (LoopTimeAcc - LoopTimer03 > 3000 && digitalRead(LED01_EN) == LOW)
  { // only do it when the time's up AND the LED isn't already on
    // don't reset the timer, to have it carry on through to the second part of the action
    digitalWrite(Led01_EN, HIGH);
  }

  // Second looping routine:
  if (LoopTimeAcc - LoopTimer02 > 500)
  {
    LoopTimer02 = LoopTimeAcc;
    digitalWrite(Led02_EN, !digitalRead(Led02_EN));
  }
}

This is not the most elegant way of doing it, but should be very easy to understand.

2 Likes

Makes sense and easy to follow, thanks for that @ScruffR

Timers would probably be much less “backyard” and more appropriate; was my attempt above close to the mark?

For software timers for your 3+1 blink I’d go with one that fires every second and increment a counter a switch the light on when the counter is 3 (and off when it’s four just for clarity).

like this

void secCallback()
{
  static int cnt = 0; 

  cnt++;
  if(cnt == 3)
  {
    digitalWrite(Led01_EN, HIGH);
  }
  else if (cnt == 4)
  {
    digitalWrite(Led01_EN, LOW);
    cnt = 0;
  }
}

Timer everySec(1000, secCallback);
void setup()
{
  pinMode(Led01_EN, OUTPUT);
  everySec.start();
}

void loop() { }

For the 500ms counter just do the same, or you could incorporate that in the same timer, half its periode to 500ms and double the check values to 6 (on) and 8 (off).

BTW, the above is not backyard but has its use for tasks that can’t go into timer callbacks for various reasons.
Although in my own code I’d write it a lot more streamlined :wink:

2 Likes

Brilliant - thanks so much @ScruffR

To clarify, backyard being the difference between by noob / leaning and perception as to what’s most appropriate and that of the professional coders like you guys.
On that note, this post alone has taught me so much. Your examples using my examples mean I can take the code “to the bench” and play / learn and grow my understanding, under the terms in the way that I learn best.

Grateful there are valued people such as yourself committed to helping others get through.
Cheers

2 Likes

Hi ScruffR

Could you provide an example of your abouve comment of how one would go about coding the same Timer using half the value.
Example:
Timer mstTimer(1000, secCallback);
mstTimer(500, halfSecCallback);

Thank you.

take a look at changePeriod()

1 Like

The original intent of my code above is to choose the common factor for the desired periods (e.g. 500ms) in the constructor and increment a counter in the timer to distinguish the respective multiples of that common periode.

That makes sense, I wasn’t looking at it from that angle. Thank you.