How to call multiple delayed functions using a single millis()

I am working in a project where I need to call more than 1 functions actually 4 functions using a single millis()

Here is the code below.

unsigned long then = 0;

void loop(){

unsigned long now = millis();

if(now-then >=0){

Serial.println("Function 1 called");

}else if(now-then>=2000){

Serial.println("Function 2 called");

}else if(now-then>=4000){

Serial.println("Function 3 called");

}else if(now-then>=6000){

Serial.println("Function 4 called");

Serial.println("The end");

then = now;
}
}

All the functions above gets run successfully but not in a proper sequence.

The running sequence of the functions seem to be very improper and random.

The 'function 1' gets executed in a proper sequence and timing but rest of the others are making a messy output.

How can I fix it please?

Thanks.

• How do you want the functions to be called in order? Like "1,2,3,4 ... 1,2,3,4" or like "1...1,2...1,2,3...1,2,3,4...1...1,2..."? May 2 '21 at 11:01
• Like '1234' order May 2 '21 at 11:03
• why with else? why only one then?
– Juraj
May 2 '21 at 13:54

The current structure with multiple if statements and on timestamp variable does only work, if you also check for millis()-then being smaller than the next interval. Otherwise the first if statement will always be executed.

I think it gets easier, when you use only one if statement, but put the intervals in an array. In that if statement you can either use a switch statement to execute the code for the corresponding interval, or use a function pointer. Somewhat like this (untested):

unsigned long then = 0;
unsigned long intervals = {0, 2000, 4000, 6000};
int current_interval_index = 0;

...

void loop(){
unsigned long now = millis();
if(now-then >= intervals[current_interval_index]){
switch(current_interval_index){
case 0:
Serial.println("Function 1");
break;
case 1:
Serial.println("Function 2");
break;
case 2:
Serial.println("Function 3");
break;
case 3:
Serial.println("Function 4");
break;
}
then = now;
current_interval_index = (current_interval_index + 1) % 4; // increment index and wrap it back to zero, if it goes to 4
}
}

That way you can easily extent for more functions and the intervals are conveniently managed in an array. Note, that the intervals add up here. So function 4 executes after 2s+3s+6s = 11s.

• Nah, my bad, missed the scope of the index update. May 4 '21 at 3:33

your else in that set of if's is causing only a single if to be possible to be true at any one time, and once the now-then line up, only the first one in the line-up will ever execute. remove the else from your if block. treat each if as its own thing. i.e.

if(now-then >=0) { /* do thing 1*/ }
if(now-then >=1000) { /* do thing 2*/ }
if(now-then >=2000) { /* do thing 3*/ }
if(now-then >=3000) { /* do thing 4*/ }

that way, even if the conditions line up, all the blocks will be checked, and all the if's that resolve true, will execute.

• your code will result in sequence 1, 1, 2, 1, 2, 3, 1, 2, 3, 4 May 2 '21 at 17:01
• You need a stamp for every thing x because you'll have to reset each of them to the current millis when the thing gets executed. May 2 '21 at 17:25