Running multiple timers

Hello,

I'm attempting to write a timer function for my class. The basic function is to wait n seconds, then execute some arbitrary code entered by the user. An example below:

int state = OFF;
int stateTwo = OFF;
void wait_test() { state = (state == OFF) ? ON : OFF; board.writeLED(0, state); }
void wait_test_2() { stateTwo = (stateTwo == OFF) ? ON : OFF; board.writeLED(1, stateTwo); }

NeuroBoard board;

void loop() {
    board.wait(1000, wait_test);
}

Every second the function is called which turns on/off the first led on the board. However, if I add this to the next line in the loop:

    board.wait(2000, wait_test_2);

It doesn't work, and only the first led is turned on/off.

For the wait function, I use an instance variable to hold the milliseconds, then calculate the difference in the function. I've seen other questions with inquiries about multiple timers, but I haven't found any that relate to class functions. Below is my function:

bool NeuroBoard::wait(const int& milliseconds, void callback()) {

    // TODO: Wait n milliseconds, then invoke callback.

    if (millis() - this->previousMilliseconds >= milliseconds) {
        this->previousMillisecondsCallback = millis();
        callback();
        return true;
    }
    return false;;

}

Where "this->previousMilliseconds" is an unsigned long, declared in the header file.

How can I edit this function so multiple calls to the wait functions results in multiple timers? Thank you.

Surely if you need to use two "timers" then you need separate "timer" objects so that the values associated with them are encapsulated in each instance

Obviously, you have a bug in your code. You only provided half, or less, of your code. So don't be surprised if you only get half of an answer to your question....

Regards,
Ray L.

Multiple timers? I got multiple timers! You want a class that's ready to go? Or are you having fun rolling your own?

-jim lee

@UKHeliBob

Yes, I tried going that approach. However, I don't know how many times the user will use our wait function, so I don't know how many timer objects to create to handle each delay.

@RayLivingston

I've only displayed the bare minimum because anything else from the header/source file is just extra noise that's not related to the question.

@jimLee

I would like to roll by myself and see if I could do it, but if you'd like to share what you've used in the past to help me that would be greatly appreciated!

linnydude3347:
@UKHeliBob

Yes, I tried going that approach. However, I don't know how many times the user will use our wait function, so I don't know how many timer objects to create to handle each delay.

You don't need to create a timer object every time you need to run the timer. Typically, each timer object would be created and exist for the lifetime of the program. It would have some kind of "start" method, and would be automatically or explicitly be reset by a reset method after registering the expiry of an interval.

If you don't know where the problem lies in the section you posted, how can you be so sure it's there, and not somewhere else?

Here's my take on multiple timer objects that can "wait n seconds, then execute some arbitrary code".

#include "timeObj.h"
#include "idlers.h"

// ************************************************************** 
// delayTrigger is your base class. Inherit this to make your
// actual triggered classes.
// **************************************************************


class delayTrigger : public timeObj,
                     public idler {

   public:
               delayTrigger(float delayTime);
   virtual     ~delayTrigger(void);
   
   virtual     void  doAction(void);   // Derived classes inherit this and fill it out.
   
   // Probably ignore these.. (under hood kind of stuff)
   virtual     void  start(void);
   virtual     void  stepTime(void);
   virtual     void  idle(void);

               bool  mTriggered;
};


delayTrigger::delayTrigger(float delayTime)
   : timeObj(delayTime),
   idler() { mTriggered = false; }

 
delayTrigger::~delayTrigger(void) {  }  


// This one is filled out by the inherited class.  
void  delayTrigger::doAction(void) { }


// These next few are just for tying all the bits together.
// We need to add the hookup() call and to clear the triggered flag.
void delayTrigger::start(void) {
 
   hookup();
   mTriggered = false;
   timeObj::start();
}


// Also need to clear the triggered flag here as well.
void delayTrigger::stepTime(void) {

   mTriggered = false;
   timeObj::stepTime();
}


// This thing runs behind in the background. Think of this
// as your own private slice of loop().
void  delayTrigger::idle(void) {
   
   if (!mTriggered && ding()) {
      mTriggered = true;
      doAction();
   }
}



// ************************************************************** 
// A couple exampples of delay trigger classes.
// **************************************************************

class liteOn : public delayTrigger {

   public:
               liteOn(float delayMs);
   virtual     ~liteOn(void);
              
   virtual     void doAction(void);
};


liteOn::liteOn(float delayMs)
   : delayTrigger(delayMs) {  }


liteOn::~liteOn(void) {  }

   
void liteOn::doAction(void) { digitalWrite(13, HIGH); }
   

// ************ 

class liteOff : public delayTrigger {

   public:
               liteOff(float delayMs);
   virtual     ~liteOff(void);
     
   virtual     void doAction(void);
};


liteOff::liteOff(float delayMs)
   : delayTrigger(delayMs) {  }


liteOff::~liteOff(void) {  }


void liteOff::doAction(void) { digitalWrite(13, LOW); }
   


// ************************************************************** 
// And we let the run..
// **************************************************************


liteOn   MrOn(1000);
liteOff  MrOff(2000);


void setup() {
   
   pinMode(13, OUTPUT); // Make LED pin output.
   MrOn.start();        // Start the call to turn on the LED
   MrOff.start();       // Start the call to turn off the LED
}

void loop() {
   idle();                 //Let the idlers have their time in the sun.
}

You will need this library : LC_baseTools

Each different function call would need to be "wrapped"in its own class. But, you can make as many of the same function at different times as you'd like.

IE for a double blinbk..

liteOn MrOn1(1000);
liteOff MrOff1(2000);
liteOn MrOn2(4000);
liteOff MrOff2(4500);

Then your setup() could have..

void setup() {
   
   pinMode(13, OUTPUT); // Make LED pin output.
   MrOn1.start();        // Start the call to turn on the LED
   MrOff1.start();       // Start the call to turn off the LED
   MrOn2.start();        // Start the call to turn on the LED
   MrOff2.start();       // Start the call to turn off the LED
}

Hope this helps..

-jim lee