Error using interrupt function from custom library

Hey all,

I was looking for some advice on attaching a function from a library I built to an interrupt function within Arduino. I'm getting this error:

** ** In function 'void setup()': error: argument of type 'void (Ergometer::)()' does not match 'void (*)()** **

The error appears whether the attachInterrupt function sits inside my library or inside the main arduino sketch. Here's the function I'm trying to attach to the interrupt:

[b]//calculates instantaneous flywheel velocity when assigned interrupt detects a click from the flywheel
void Ergometer::flyClick()
{
      unsigned long currentTime = micros();
      flyOmega = (2 * pi) / (microsToSecs(currentTime - flyTime) * _numMags);
      flyTime = currentTime;
      
      updateDistance();            //updates total distance every time the flywheel clicks
}[/b]

Looks pretty standard to me. I'll be happy to post more of the source if it helps, I'd really appreciate any advice you all have on the error.

Can you show us your 'setup()' function, which is where the error is actually located?

Sure, here it is:

[b]void setup()
{
  
          attachInterrupt(0, erg.flyClick, RISING);      //sets interrupt 0 (pin __) to monitor flywheel
      attachInterrupt(1, erg.leftClick, RISING);      //sets interrupt 1 (pin __) to monitor left pulley
      attachInterrupt(2, erg.rightClick, RISING);      //sets interrupt 2 (pin __) to monitor right pulley
  Serial.begin(9600);
  

}[/b]

The three attachInterrupt lines are throwing the errors, both when I locate them in setup() and when I keep them inside the library. Same error each time.

You haven't posted your handlers, but they must not take any arguments and they must not return anything. See the reference for an example.

Also, attachInterrupt only works with interrupts 0 and 1 on a standard Arduino board.

I'm using an Arduino MEGA, so I've got access to the extra interrupt--but the code throws that error even when I just use the first of these functions. The handler here doesn't take any parameters, or return anything... unless I can't even return "void"?

Here's my interrupt handler, using just this line within setup():

attachInterrupt(0, erg.flyClick, RISING); //sets interrupt 0 (pin __) to monitor flywheel

Handler:

//calculates instantaneous flywheel velocity when assigned interrupt detects a click from the flywheel
void Ergometer::flyClick()
{
      unsigned long currentTime = micros();
      flyOmega = (2 * pi) / (microsToSecs(currentTime - flyTime) * _numMags);
      flyTime = currentTime;
      
      updateDistance();            //updates total distance every time the flywheel clicks
}

Is it a problem that I call a separate function, updateDistance? All that does is this:

//calculates ratio of time in water to time in air--1 is all time in air, 0 is all time in water
void Ergometer::updateDistance()
{
      totalDistance = pow((dragFact / _cSplit), (1 / 3)) * (flyClicks / _numMags);
}

And this error results:

In function 'void setup()':
error: argument of type 'void (Ergometer::)()' does not match 'void (*)()'

Class member functions that appear to take no arguments actually do take an invisible argument called this. The value of this is the instance of the object you're referring here, erg. You can't attachInterrupt() to a class member function directly. You might be able to do it if the member function is static, but my approach is to have a global variable that is the instance, and the global service routine knows how to use the global variable.

MyClass theInstance = NULL;

// Somewhere, fill in an initialized copy of MyClass,
// and set theInstance to it.

ISR(TIMER1_0VF_vect)
{
    if (theInstance)
        theInstance->handleInterrupt();
}

This looks like it will work--I tried adding #include "avr/interrupt.h" to my Ergometer library and running attachInterrupt() from within the constructor. The code compiles just fine, I'm off to go test it out with my hardware; if it doesn't work I'll go with your method, Halley.

(Is this more efficient than simply creating mirror methods within the arduino sketch, and having them call the class methods?)

You need to be careful if the handler uses any arduino functionality. You can't assume the Arduino runtime configuration has completed when the constructer is called. If you have arduino functions like micros() in your handler, this may fail if the interrupt occurs before the low level initialisation is completed.

I think it is safer to have a static method in your class cpp file that is called from setup to do the attach interrupt.