C++ help: How to pass a member function pointer within attachInterrupt?

Hey everyone, i'm trying to compose a library in order to make a sketch of mine look tidier and be more reusable, so i'm at the point where i need to create a function that will utilize an interrupt. The arduino code works perfectly fine, but the problems start when i'm trying to put the code in a library.

So i have:

void Smartcar::travelDistance(int centimeters){ //TO-DO
	attachInterrupt(_interruptPin, updateCounter, RISING);
}

and updateCounter is:

void Smartcar::updateCounter(){
	_pulseCounter++;
}

When i try to compile, I get the following error:

error: argument of type ‘void (Smartcar::)()’ does not match ‘void (*)()’

I do understand that my error is identical to the one described here. The solution apparently is to "pass a member function pointer", however my knowledge in C/C++ is too limited to be able to use this information in order to solve my problem. :confused:
Any C++ people that can share their lights with me? :slight_smile:
Thanks in advance!

You can only use static member functions as ISRs.

Do you suggest that i just define updateCounter as static in the header file?

You could do, but for what it's worth, you might just as well define it as a totally independent function. Within a static function you don't have access to the other class members as it's not attached to any specific instance of the class.

Basically, the problem is that an ISR can't have anything passed to it when it's invoked by the condition that causes the interrupt. Therefore, it can't even have a pointer to it's own parent object. It's just a stand alone function.

Ok, thank you very much!
I did some changes and don't get errors anymore. Haven't tried it yet (cannot until tomorrow because i will wake people up :stuck_out_tongue: ) but i'd be glad if you can verify what i did is what you meant.

Added this in the beginning of the source file, to declare the static function and the variable i will be using in it:

static void updateCounter();
volatile unsigned short _pulseCounter = 0;

And then changed the rest accordingly:

void Smartcar::travelDistance(int centimeters){
	attachInterrupt(_interruptPin, updateCounter, RISING);
}

static void updateCounter(){
	_pulseCounter++;
}

If this is correct, hopefully others with the same question will get their answer fast. :slight_smile:

Hmm, excuse my ignorance but i am not sure "what" i want in that essence. What do i gain/lose if it's NOT static?

P.S. It does compile when i remove the static reference to it, so i am really curious on which is the best option here.

To keep things simple, just create it as a simple void function. Not as a member function. Making it a static member function effectively does just this anyhow, but makes things a little more complicated.

Alright cool, thank you very very much! One relevant question though: Is there a way to declare this void function in the header file instead of the beginning of my .cpp file?

kuruki:
Alright cool, thank you very very much! One relevant question though: Is there a way to declare this void function in the header file instead of the beginning of my .cpp file?

Of course you can, but you still need to define it in a .cpp file.

Delta_G:
In the case of a non-member function I don't think the static does anything at all.

In the case of a member function, it tells the compiler that this particular member doesn't go with any one instance of the class. All instances share the same function.

So your choices are basically a normal function outside the class OR a static member of the class. The best bet would be the first. Just a normal void function like you have now but without the static keyword.

ok, same as in other object oriented languages then. Got it, thanks! :slight_smile:

KenF:
Of course you can, but you still need to define it in a .cpp file.

Hmmmm, not sure i understand what you mean, because If i remove the declaration from the beginning of the cpp file and i place it along the rest in my header file, then i get the exact same error as in the beginning!

Delta_G:
are you putting it outside the class definition in the header? Can you post what you got now?

oh.... :art:
Yeah i was used to putting it inside the class definition. Taking it outside did the trick! Thanks for the heads up! :smiling_imp:

kuruki:
cpp file and i place it along the rest in my header file, then i get the exact same error as in the beginning!

In your myLibrary.h file you put something like this

volatile int counterThing;

void updateCounter();

//Then put you class definition

In your myLibrary.cpp you put something like this

#include "myLibrary.h"

void updateCounter()
{
  //do stuff here such as
  counterThing++;
  
}

If you need to call a member function from an ISR, just handle the ISR in your application, and the ISR doesn't need to do anything BUT call that member function. The function will then have full access to the rest of the class, and its instance data.

Regards,
Ray L.

KenF:
In your myLibrary.h file you put something like this

volatile int counterThing;

void updateCounter();

//Then put you class definition




In your myLibrary.cpp you put something like this


#include "myLibrary.h"

void updateCounter()
{
  //do stuff here such as
  counterThing++;
 
}

For some reason, when i try to declare the variable there in the header, it tells me i have a multiple definition of it!

Smartcar.cpp:14: multiple definition of `_pulseCounter'

Where line 14 is my constructor... :confused:

@RayLivingston
Yeah, i got the general picture but i generally have to enhance my knowledge in C++ because i'm struggling to grasp many new concepts and terms at the moment.

kuruki:
For some reason, when i try to declare the variable there in the header, it tells me i have a multiple definition of it!

Oops yes. Sorry. This is because your main sketch includes the header and your cpp also includes the header so the declaration of the variable appears twice.

You need the reference to the variable in your header file (otherwise you won't get access to it from your main sketch) So the way around it is,

Within your .h file declare the volatile variable as an external one
eg

extern volatile int counterThingy;

Within your .cpp file you do the ACTUAL definition

volatile int counterThingy;

You will then have access to counterThingy within your sketch without having to define it there.

I see, interesting...
But anyway, what if i do not want to have access from my main (arduino) sketch to this variable, meaning that i don't want the one who's using the library to easily mess with that? Do I only declare it in the cpp file and NOT in the header?

EDIT: I tried it and indeed, when it's mentioned in both the header and the .cpp file, the user can have access to it in the arduino sketch, which I definitely don't want. So i will leave it just in the cpp file. Thanks for your valuable input! :slight_smile:

kuruki:
I see, interesting... Once I declare it as extern in the header, it doesn't through an error if i don't declare it at all in the cpp file!
But anyway, what if i do not want to have access from my main (arduino) sketch to this variable, meaning that i don't want the one who's using the library to easily mess with that? Do I only declare it in the cpp file and NOT in the header?

EDIT: I tried it and indeed, when it's mentioned in both the header and the .cpp file, the user can have access to it in the arduino sketch, which I definitely don't want. So i will leave it just in the cpp file. Thanks for your valuable input! :slight_smile:

Indeed, I think you've got it.

The extern merely lets the compiler know that there will be a variable with that name and type defined SOMEWHERE. It's only an idiosyncrasy of the compiler that keeps it from being accessed by the user in their sketch. It doesn't have any special protection in your .cpp file.

If a user REALLY still wants access to it in their sketch they can simply include
extern int variableNameHere; in their main sketch.