Using the Intervaltimer in a class (access issues)

Status
Not open for further replies.

PickyBiker

Well-known member
The following sketch was set up to demonstrate the problem I have trying to use the IntervalTimer in my class. The member function the IntervalTimer points to, (Blink), is declared static. Once that is done, any attempt to address the class global value (val) from that member function generates the error, "invalid use of member 'Test::val' in static member function".

Of course if I don't declare the member function (Blink) static, I get the error, "invalid use of non-static member function".

If I don't access val, the code works fine.

How can I set this up to use the IntervalTimer in a class that won't prevent me from accessing class global values?


Code:
class Test
{
  public:
    IntervalTimer Timer;
    int val;

    Test()
    {
      pinMode(LED_BUILTIN, OUTPUT);
      Timer.begin(Blink, 100000);
    }

    void On()
    {
      digitalWrite(LED_BUILTIN, LOW);
    }

    void Off()
    {
      digitalWrite(LED_BUILTIN, HIGH);
    }

    void SetBlinkSpeed(long desired_speed)
    {
      Timer.update(desired_speed);
    }

    static void Blink()
    {
      val = 20;
      digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));
    }

};

Test LED1;


void setup()
{
  LED1.SetBlinkSpeed(25000);
}

void loop()
{
  delay(2000);
  LED1.SetBlinkSpeed(500000);
  delay(2000);
  LED1.SetBlinkSpeed(50000);
}
 
You can not access non static member variables from a static member function. This is quite obvious because a static member function like your Blink() "belongs" to the class not to a specific object. Now, Blink() can't know from which object it should read your 'val' variable. You can of course make "val" static as well, then your code would compile. On the other hand, this means that you can only have one object of class Test since all objects would share the same static variables.
=> if this is what you intended, make "val" static and you are done. (However, in this case, using namespaces instead of static classes would make more sense).

In case you want to create more than one object there are a few strategies to do so. In embedded programming the usual way is to pass a pointer to the actual object into the static function. This pointer can then be used to access the non static members. Something like this:
Code:
static void Blink(Test* obj)
{
    obj->val = 20;    
    digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));
}

Unfortuately the Intervaltimer does not handle passing variables to callbacks. However, it is not very difficult to extend it accordingly. You might want to have a look at my TeensyHelpers repository. It contains IntervalTimerEx which
adds this functionality to the IntervalTimer https://github.com/luni64/TeensyHelpers#intervaltimerex. You can choose between the approach shown above or using std::function callbacks (more convenient but needs more resources). There are worked out examples in the readme which show how to embed an IntervalTimerEx into a user class with both methods.

Hope that helps
 
Status
Not open for further replies.
Back
Top