Loop different parts of code in different periods

Hi,

If one wants to loop one function for example once every 100 ms (I use delay atm) and another part for example every 3 seconds, what is the simplest/smartest/best way to do that?

Best regards
Staffan

See Using millis() for timing. A beginners guide, Several things at the same time and look at the BlinkWithoutDelay example in the IDE.

To not use delay() and change both loops to a state machine. :slight_smile:

One messy option if the 3 second task isn't blocking you can do that every 30 loops of the 100ms task.

Here's a basic framework you can try. I generally use a 1mS interrupt for timing stuff like this but millis() works fine too. Make sure whatever these tasks you're doing are not coded with huge delay() crap in them:

unsigned long
    currTime;
unsigned long
    T100Time,
    T3000Time;

#define T100    100     //100mS
#define T3000   3000    //3000mS == 3s

void setup() 
{
  // put your setup code here, to run once:
  //...
  currTime = millis();
  T100Time = currTime;
  T3000Time = currTime;
  
}

void loop() 
{
    CheckThingsToDo();
    //do other loop stuff
    //....
}

void CheckThingsToDo()
{
    currTime = millis();

    //time to run 100mS task?
    if( currTime - T100Time >= T100 )
    {
        Do100mSThing();
        T100Time = currTime;
          
    }//if

    if( currTime - T3000Time >= T3000 )
    {
        Do3000mSThing();
        T3000Time = currTime;
          
    }//if
        
}//CheckThingsToDo

void Do100mSThing()
{
    //do stuff you need done every 100mS
}//Do100mSThing

void Do3000mSThing()
{
    //do stuff you need done every 3000mS
}//Do3000mSThing

Two tips,

-Don't use stuff like 'T100Time' as variable names. Give it usefull names for the task it's doing or just make an array.

  • scrap macro's, use const variables.

My version:

const unsigned long LoopIntervals[] = {100, 3000}; //in ms
const byte NrLoops = sizeof(LoopIntervals)/sizeof(LoopIntervals[0]);
unsigned long previousLoopTimes[NrLoops];

void setup()
{
  
}

void loop()
{
  checkThingsToDo();
  //do other loop stuff
  //....
}

void checkThingsToDo()
{
  const unsigned long CurrTime = millis();

  //time to run 100mS task?
  if( CurrTime - previousLoopTimes[0] >= LoopIntervals[0] )
  {
    previousLoopTimes[0] = CurrTime;
    doThingA();
  }//if

  if( CurrTime - previousLoopTimes[1] >= LoopIntervals[1] )
  {
    previousLoopTimes[1] = CurrTime;
    doThingB();
  }//if
       
}//CheckThingsToDo

void doThingA()
{
  //do stuff you need done every 100mS
}//doThingA

void doThingB()
{
  //do stuff you need done every 3000mS
}//doThingB
const unsigned long CurrTime = millis();

const?

Blackfin:

const unsigned long CurrTime = millis();

const?

15-all

Yeah, const :slight_smile: Do you ever want to change it in it's lifespan?

To each his own style I guess. In sum, yours seems like something of an unnecessary complication obfuscation of a pretty simple concept.

But I'm not a programmer by trade so I'll defer to you on coding style. ¯_(ツ)_/¯

Why does making something const complicated? ???

Not style so much as a best practice. Defining variables that you know will not (should not) change during their lifetime -- along with aggressively limiting their scope as much as possible -- allows the compiler to find more of your errors.

THe complication I was referring to was this:

const unsigned long LoopIntervals[] = {100, 3000}; //in ms
const byte NrLoops = sizeof(LoopIntervals)/sizeof(LoopIntervals[0]);
unsigned long previousLoopTimes[NrLoops];

vs

unsigned long
    currTime;
unsigned long
    T100Time,
    T3000Time;

#define T100    100     //100mS
#define T3000   3000    //3000mS == 3s

The outcome is exactly the same but yours is more difficult for a non-programmer to read.

The use of "const" is just weird to me; no, I don't want it to change in its lifetime but in my code it wouldn't anyway.

As I said: To each his own.

Blackfin:
The use of "const" is just weird to me; no, I don't want it to change in its lifetime but in my code it wouldn't anyway.

Well, you wouldn't change it intentionally, anyway. That's the point. But, if you never make mistakes when creating and entering code, I guess it doesn't matter.

gfvalvo:
if you never make mistakes when creating and entering code, I guess it doesn't matter.

As they say, if de-bugging is the act of taking errors out of code, programming must be the act of putting the errors in.

Blackfin:
The outcome is exactly the same but yours is more difficult for a non-programmer to read.

Compiled (at least at functional level), yes. In code, no! My version is

  1. scalable (at least a good start)
  2. not using macro’s (for which C++ almost always had a better/safer alternative)
  3. not using variable names defining the value. The power of a value is you can change it in one place. But it just makes confusing code if you would change T100 to be 2500, doesn’t it?

Okay, the way of writing can be styled a bit nicer:

//one of the times a macro has no good C++ alternative:
#define numberof(x) (sizeof(x)/sizeof(x[0]))

//interval between calls in 
const unsigned long LoopIntervals[] = {
  100, 
  3000
};
const byte NrLoops = numberof(LoopIntervals);
unsigned long previousLoopMilliss[NrLoops];

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

void loop(){
  checkLoops();
}

void checkLoops(){
  const unsigned long currMillis = millis();
  
  for(byte i = 0; i < NrLoops; i++){
    if(currMillis - previousLoopMilliss[i] >= LoopIntervals[i]){
      previousLoopMilliss[i] += LoopIntervals[i];

      switch(i){
        case 0: doA();
                break;
        case 1: doB();
                break;
      }
    }
  }
}

void doA(){
  Serial.print("Hello A!");
}

void doB(){
  Serial.print("Hello B!");
}

Of scalable fully from the top:

//one of the times a macro has no good C++ alternative:
#define numberof(x) (sizeof(x)/sizeof(x[0]))

struct loop_t{
  const unsigned long LoopInterval;
  void (*const LoopFunction)();
};

const loop_t Loops[] = {  {100, &doA},
                          {3000, &doB}};
const byte NrLoops = numberof(Loops);
unsigned long previousLoopMilliss[NrLoops];

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

void loop(){
  checkLoops();
}

void checkLoops(){
  const unsigned long currMillis = millis();
  
  for(byte i = 0; i < NrLoops; i++){
    if(currMillis - previousLoopMilliss[i] >= Loops[i].LoopInterval){
      previousLoopMilliss[i] += Loops[i].LoopInterval;

      Loops[i].LoopFunction();
    }
  }
}



void doA(){
  Serial.print("Hello A!");
}

void doB(){
  Serial.print("Hello B!");
}

Just add members to Loops (pointing to excising functions of course! and you’re good to go!