Best method for managing multiple tasks?

Rezo

Well-known member
I have a fairly complex application that requires some reoccuring fucntion calls on a timed manner; GUI library, CAN bus transmits, SD writes, MTP loop etc
I am using some delays without delays to manage this in the main loop as follow:
Code:
if (millis() > loopTimeNow1 + loopDelay1) {
      loopTimeNow1 = millis();
      lv_timer_handler(); 
      mtpLoop();
  }

  if ((millis() > loopTimeNow2 + loopDelay2) && canEnabled && canEnabledButton) {
    loopTimeNow2 = millis();
    if((millis() > canLoopTime + (loopDelay2 + (loopDelay2/2))) && !readyToTransmit){
      readyToTransmit = true;
      canTimeouts++;
    }
    canTransmit();
  }

  if ((millis() > loopTimeNow3 + loopDelay3) && readyToUpdate) {  
    loopTimeNow3 = millis();
    updateGaugeScreen();
    if(dataLogEnabled && dataLogHeaderReady){
      logDataLine();
    }
  }

  if(millis() > loopTimeNow4 + loopDelay4){
    loopTimeNow4 = millis();
    if(!dataLogEnabled){
      isSdInserted = SD.mediaPresent();
    }
    if(autoBrightness){
      getClusterBrightness();
    }
  }

Each one of these loops runs in different intervals:
1. 5sm
2. 25-30 ms
3. 25ms
4. 1s

Is there a better way of managing multiple tasks in parallel?
Perhaps replace some of these loop delays (such as CAN transmits or SD writes which are enabled/disabled by the users) with IntervalTimers and starting/stopping them where relevant?

Just looking for some insights as there more the app develops the more app contextual functions calls will be needed in timed intervals.
 
One possible approach: just have one loopTimeNow variable that times the shortest interval (5ms) & count multiples of that (5x for 25ms, 200x for 1 sec) for the longer intervals. I have used this approach in conjunction with a timer interrupt, but you should be able to do the same thing in the loop() function. Here's some conceptual code (NOTE: typed off-the-cuff, so not specifically tested) . . .

Code:
#define LOOP_DELAY 500     // 5 ms interval

#define LOOP_COUNT_1 1     // once every 5 ms
#define LOOP_COUNT_2 5     // once every 25 ms
#define LOOP_COUNT_3 200   // once every 1 second

unsigned long loopTimeNow = millis();

uint8_t loop_counter_1 = 0;
uint8_t loop_counter_2 = 0;
uint8_t loop_counter_3 = 0;

loop() {
   if (millis() > loopTimeNow + LOOP_DELAY) {
      loopTimeNow = millis();

      if (++loop_counter_1 >= LOOP_COUNT_1) {
         loop_counter_1 = 0;

         do_loop_1();
      }

      if (++loop_counter_2 >= LOOP_COUNT_2) {
         loop_counter_2 = 0;

         do_loop_2();
      }

      if (++loop_counter_3 >= LOOP_COUNT_3) {
         loop_counter_3 = 0;

         do_loop_3();
      }
   }
}

Mark J Culross
KD5RXT
 
Thanks all for the input!

The device is only powered up for a couple hours at a time, so won't hit the millis() max limit.
But I think I will move over to using elapsed mills as it's just slightly easier to manage and a bit less code
 
Back
Top