TimerOne attachInterrupt with non-static function member

lpaolini

Member
I would need to setup a timer in a class constructor with a non-static class member, using the TimerOne library.
How can I do that, given the attachInterrupt function is expecting a free function as an argument?

Thanks.

Code:
Foo::Foo() {
    Timer1.initialize(1000);
    Timer1.attachInterrupt(update);
    Timer1.start();
}

void Foo::update() {
    // do something
}

error: invalid use of non-static member function 'void Foo::bar()'

Thanks,
Luca
 
Assuming you only want one instance of foo in your code then the method I've used for this in the past is:

Code:
// in header
class foo { 
private:
static foo* m_instance;
void update();
inline static void update_static() {m_instance->update();};

}

// in cpp
foo::m_instance = NULL;

foo::foo() {
    m_instance = this;
    Timer1.initialize(1000);
    Timer1.attachInterrupt(update_static);
    Timer1.start();
}


This works best if you make the class a singleton, that then makes it impossible to have two instances of foo. The changes for this are:
Code:
// in header
class foo { 
  public:
    inline static foo* Instance() { if (!m_instance) m_instance = new foo(); return m_instance;};

  private:
    foo(); // yes the constructor is private.
    static foo* m_instance;
    void update();
    inline static void update_static() {m_instance->update();};
    timer Timer1;
};

// in cpp
foo::m_instance = NULL;
foo::foo() {
    Timer1.initialize(1000);
    Timer1.attachInterrupt(update_static);
    Timer1.start();
}

// to access it from other code
foo::Instance()->somePublicFooFunction();

This is a little weird at first but it does work well. foo::instance() acts like a global pointer to the class instance but with the added security that it is always valid and you can never have more than one.


If you need multiple instances of the class, each calling their own version of your update function then it gets more fun.
 
While AndyA's solution certainly works, you might also be interested in IntervalTimerEx which can be embedded in classes out of the box https://github.com/luni64/TeensyHelpers#intervaltimerex. Just copy the two files from here https://github.com/luni64/TeensyHelpers/tree/master/src/IntervalTimerEx to your source folder to use it. This solution also works for more than one instance.

Here a working example:

Code:
#include "Arduino.h"
#include "IntervalTimerEx.h"

class foo
{
 public:
    void begin(){
        timer.begin([this] { this->update(); }, 100'000);
    }

 private:
    void update(){
        Serial.printf("Called at %d\n", millis());
    }

    IntervalTimerEx timer;
};

foo f1;

void setup(){
    f1.begin();
}

void loop(){
}


which prints:

Code:
Called at 500
Called at 600
Called at 700
Called at 800
Called at 900
Called at 1000
Called at 1100
Called at 1200
Called at 1300
Called at 1400
Called at 1500
Called at 1600
Called at 1700
Called at 1800
Called at 1900
Called at 2000
Called at 2100
Called at 2200
 
Last edited:
@luni
Do you know other similar libraries with microsecond resolution which can be embedded in classes out of the box and are compatible with standard Arduinos?

Thanks.
 
Just for the fun of it I did a quick TimerOneEx which should compile for all boards supported by TimerOne (just copy this file into your sketch folder: https://github.com/luni64/TeensyHelpers/blob/master/src/TimerOneEx/TimerOneEx.h)
TimerOneEx subclasses TimerOne, i.e., all functionality of TimerOne is still available, it just adds an alternative atttachInterrupt function which allows to attach an arbitrary member function. It is not as flexible as the IntervalTimerEx but it should do the job.

Code:
#include "TimerOne.h"
#include "TimerOneEx.h"

class foo
{
 public:
    void begin(uint32_t period)
    {
        timer.setPeriod(period);
        timer.attachInterrupt(&foo::update, this);
        timer.start();
    }

 protected:
    void update()
    {
        Serial.println( millis());
    }

    TimerOneEx<foo> timer;
};

foo f1;

void setup()
{
    f1.begin(10000);
}

void loop()
{
}

You can also attach free functions or member functions from other classes:

Code:
#include "TimerOne.h"
#include "TimerOneEx.h"

class bar
{
 public:
    void update()
    {
        Serial.println( millis());
    }
};

bar b1;
TimerOneEx<bar> timer;

void setup()
{
    timer.attachInterrupt(&bar::update, &b1);
    timer.setPeriod(50000);
}

void loop()
{
}
 
Back
Top