How to have a second loop in the sketch

Hi all,

Just wondering if the above is possible please?

For example I have some things that I want a 2 minute delay on (sending some data to the web), but adding these into the void loop(void) { } piece of code means that the delay I've put is also delaying the output of the data to the serial/console by 2 minutes.

Is it possible to have two loops so I can have one on a 2 minute delay and one on a 10 second delay?

I'm not sure if I'm just missing something obvious, but I can't see what makes the void loop(void) { } actually loop, so not sure how to re-create another one (or if it is even possible)

Thanks :slight_smile:

How to several things at once.

You can't have two loop functions, but you can use one loop function to do as many things at once as you want so long as you don't block with the delay function. See the link above for how to do that.

There can be only one function called loop, but it can do many things (it's called repeatedly from an invisible "main").

Have a look at blink without delay.

You were asking where loop was called. In the cores library is the main.cpp file which is where your program will get its "main()" function from. The main function looks like this. This is where loop() gets called from...

int main(void)
{
	init();

	initVariant();

#if defined(USBCON)
	USBDevice.attach();
#endif
	
	setup();
    
	for (;;) {
		loop();
		if (serialEventRun) serialEventRun();
	}
        
	return 0;
}

Yes, “blink without delay” style coding allows you to do that.

void loop() is called out to run repeatedly by the unseen
main() program.

#include <Arduino.h>

int main(void)
{
	init();

#if defined(USBCON)
	USBDevice.attach();
#endif
	
	setup();
    
	for (;;) {
		loop();
		if (serialEventRun) serialEventRun();
	}
        
	return 0;
}

azibux1:
Is it possible to have two loops so I can have one on a 2 minute delay and one on a 10 second delay?

You cannot have such thing as a "delay()" which means "blocking every program execution for x ms" in a "cooperative multitasking" program.

Of course it could be done, that a program has different 'tasks' to be done in different time slices.

First: Use the IPO programming model, seperating your program into logical blocks for

  • Input
  • Processing
  • Output

Then define a processing function that remembers when each task has been processed and process it when its the right time to do so:

long nowMillis;

void input()
{
  nowMillis=millis();
}


boolean proc1done, proc2done;

void processing()
{
  static unsigned long lastProc1;
  static unsigned long lastProc2;
  
  // handle 1st processing
  if (nowMillis-lastProc1>10000) // each 10 seconds
  {
    lastProc1=nowMillis;
    proc1done=true;
    // do what must be done
  }
  else proc1done=false;

  // handle 2nd processing
  if (nowMillis-lastProc2>60000) // each 60 seconds
  {
    lastProc2=nowMillis;
    proc2done=true;
    // do what must be done
  }
  else proc2done=false;
}

void output()
{
  if (proc1done) Serial.println("Just finished task ONE");
  if (proc2done) Serial.println("Just finished task TWO");
}

void setup()
{
  Serial.begin(9600); // Initialize Serial for debugging messages
  Serial.println();
  Serial.println("Good night and good luck!");
  Serial.println();
}

void loop()
{
  input();
  processing();
  output();
}
if (nowMillis-lastProc2 >= 60000) // each 60 seconds

Not a big deal at these sort of timescales, but it's a good habit to get into.

Thank you all, the blink without delay seems to be the style of code I want, and the easiest way of implementing what I need

I see millis() will reset when it gets to its max value, and I'm guessing that will happen before the max value of an unsigned long will be reached? So what happens then as that will 'break' the code surely since subtracting previousMillis from currentMillis will put you into a negative number and that task will not run again surely then?

Thanks again :slight_smile:

azibux1:
Thank you all, the blink without delay seems to be the style of code I want, and the easiest way of implementing what I need

I see millis() will reset when it gets to its max value, and I'm guessing that will happen before the max value of an unsigned long will be reached? So what happens then as that will 'break' the code surely since subtracting previousMillis from currentMillis will put you into a negative number and that task will not run again surely then?

Thanks again :slight_smile:

millis() returns an unsigned long. The subtraction is safe, you never have to worry about an unsigned variable having a negative value. That's the point of it being unsigned. Work through it with a few different numbers and you should be able to convince yourself that it is safe from any rollover.

Remember, that with an unsigned long, 1 - 2 == 4,294,967,295.

Remember, that with an unsigned long, 1 - 2 == 4,294,967,295

Altho you should never run into that situation.
The subtraction should always be (later time) - (earlier time).
Thus if you had a stored time that was prior to rollover, and the current time is after the rollover, than elapsed time ends up being the time from (prior to rollover to 0) + (0 to current time)

Ex 0x00000010 - 0xFFFFFFF0 = FFFFFFFF 00000020, and since only 32 bits are used for unsigned long, the result is 0x00000020
This is equivalent to decimal 16 after 0 - decimal 16 before 0; 16+16 = 32, or 0x20

I think you can demonstrate a case where the math falls apart, but you need to have a situation where the time between the two is longer than 32 bits total, like
0xF0000001 - 0xEFFFFFFF = 2
(more than 1/2 way to next rollover - more than 1/2 way prior to earlier rollover)
so the result is a 64 bit number that rolls over.
So keep your durations between samples smaller.

Thanks for both explanations, completely forgot/overlooked the fact that it was using an unsigned value so it has no negative

Thanks all :slight_smile:

Implemented and working, thanks all :smiley:

You can think of several sequential loops like this:

void loop() {
   sub_loop1();
   sub_loop2();
   sub_loopx();
}

void sub_loop1() { 
   // etc etc etc
}

void sub_loop2() { 
   // etc etc etc
}

void sub_loopx() { 
   // etc etc etc
}

Again, like others have said, if you use delay on one of the "sub_loop" functions, the other ones will be delayed as well, pretty much like a chain reaction.

1 Like

And... this is why I keep encouraging people to use unsigned long for those variables. I keep seeing people posting code using merely a long. Although the math still works out in this special case, it can make it rather confusing if you try to do anything else with those numbers.

millis() and micros() returned unsigned long. All time related variables should be unsigned long for the math to work correctly all the time.

Agreed.

Delta_G:
Remember, that with an unsigned long, 1 - 2 == 4,294,967,295.

CrossRoads:
Altho you should never run into that situation.
The subtraction should always be (later time) - (earlier time).

Exactly the case above. The earlier time was 2, the later time was 1. It was 4,294,967,295ms after the earlier time of 2 and (shortly) after a rollover.