Go Down

Topic: attachInterrupt within Classes (Read 2386 times) previous topic - next topic

tomhow

My C++ is ok, but I don't do it for a living. To analogise, I can change a wheel and bleed the brakes, but don't ask me to change the entire engine.

Anyhow,rather simplistically , I want to have a motor class. In the motor class is a function that is called by interrupt.  If I don't use classes, the code is simple and compiles. If I try and use a class, when I try and setup the interrupt, I get lots of messages about )() not matching void (*)() which is a bit beyond what I can cope with.

Very simple example that will compile....

Code: [Select]

void setup()
{

  /* add setup code here */
      attachInterrupt(0,doEncoder,CHANGE);

}

void loop()
{

  /* add main program code here */

}


void doEncoder() {}


Another very simple example which does NOT compile.....error is
EncoderExample.pde : In function 'void setup()'
EncoderExample.pde : )()' does not match 'void (*)()'

Code: [Select]

class Motor {
public:
      void doEncoder();

};

void Motor::doEncoder() {}


Motor motor;

void setup()
{

  attachInterrupt(0, motor.doEncoder , CHANGE);

}

void loop()
{

  /* add main program code here */

}


Of course what I want to do is more like this, but i get the same error
EncoderExample.pde : Motor(int)'
EncoderExample.pde : )()' does not match 'void (*)()'

Code: [Select]

class Motor {
public:
      Motor(int pin);
private:
      int EncoderPin;
      void doEncoder();

};

Motor::Motor(int pin) {
      EncoderPin = pin;
      attachInterrupt(EncoderPin, doEncoder , CHANGE);
}
void Motor::doEncoder() {}


Motor *motor;

void setup()
{
      motor = new Motor(0);
 

}

void loop()
{

  /* add main program code here */

}



Furthermore, this does compile, but i do not understand why

Code: [Select]

class Motor {
public:
      Motor(int pin);
private:
      int EncoderPin;
      static void doEncoder() {}

};

Motor::Motor(int pin) {
      EncoderPin = pin;
      attachInterrupt(EncoderPin, doEncoder , CHANGE);
}



Motor *motor;

void setup()
{
      motor = new Motor(0);
 

}

void loop()
{

  /* add main program code here */

}

robtillaart


The point is that the compiler need to resolve some addresses compile-time which cannot be resolved at link time.

Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

tgm1175

#2
Apr 18, 2012, 10:04 pm Last Edit: Apr 18, 2012, 10:06 pm by tgm1175 Reason: 1
When using classes in C++, the compiler does not duplicate member functions for each instance of the class.  Instead, there is a hidden parameter for every function which points to the class as away to access the instance variables.

So for your example, when you're calling

Code: [Select]
motor.doEncoder();

This is actually being re-written as

Code: [Select]
Motor::doEncoder(motor);

The compiler is protecting you from yourself when you try and create a reference to the non-static member function. What you'll need to do is write a separate subroutine to wrap the function call.

Such as:

Code: [Select]

void setup()
{
attachInterrupt(0, interrupt_handler_0, CHANGE);
}

void function interrupt_handler_0()
{
 motor.doEncoder();
}


EDIT: The other problem you're having is that you scoped doEncoder() as private.  Private Scope means that only the class itself can call the function.  You'll want to declare the doEncoder function as public to be able to call it from the rest of your program.

jraskell

Another option aside from utilizing a wrapper function is to utilize a static method within the class.  Static methods are class level functions, not instance level functions, and thus there are no hidden instance parameters being passed in.

You still have to deal with how to reference any instances of the class your interrupt routine is intended to be utilized with though.  There are a variety of options there.  Make the entire class static, utilize a singleton pattern, encapsulate everything in a higher level class, use static volatile class variables...

Go Up