I habe a problem with an interrupt in a class. I tried several variants to write the code but i always get errors.
I use a ESP32 and I want to get a interrupt when pin 36 changes its state. Below is my actual code and i get the error: invalid conversion from 'void ()(void)' to 'void (*)()' on line "attachInterrupt(...)".
IDE is version 1.8.13
Has anyone an idea how i can do it?
Greetings
Frank
class Test
{
public:
Test();
void Init();
private:
static void IRAM_ATTR Interrupt_static(void *pInterrupt);
int x;
};
Test::Test()
{
}
void Test::Init()
{
pinMode(36,INPUT_PULLUP);
int t=digitalPinToInterrupt(36);
attachInterrupt(t,&Test::Interrupt_static,CHANGE);
}
void IRAM_ATTR Test::Interrupt_static(void *pInterrupt)
{
Test* self = static_cast<Test*>(pInterrupt);
self->x++;
}
Good point, the only problem then is how can I access the variable (x) in the class...
error: invalid use of member 'Test::x' in static member function
When I declare x as static the Linker says undefined reference to `Test::x
interrupts are not executed with arguments. they are simply a function pointer located in an interrupt vector. that function can be hardcoded with variables
not sure what the overhead is accessing a class member within the interrupt
The method attachInterrupt() will not allow you to specify an argument for the ISR. If you want to pass a pointer to an object to the ISR, you must use a different approach which includes gpio_isr_handler_add, here is an example.
It's one of those "Modern C++" black magic things. My hand-waiving explanation is that the signature of class member functions include a hidden 'this' parameter so that the function can know which instance to operate on. std::bind(&TestClass::classIsr, this)
Creates an object of the std::bind class that specifies ("binds") the function pointer and instance pointer.
The "FunctionalInterrupt.h" header includes an overload of attachInterrupt() that accepts a std::function<> --- yet more "Modern C++" black magic. The std::function constructor has an overload that accepts a std::bind.
@gfvalvo : Good example of why people hate C++ :-/
A lambda would work for encapsulation but the OP wants a contextual and conditional variable so the lambda would have to have access to a outer/global variable. However, even though it's "private", it's the same thing with the class (a function pointer could work too). Since it's all about the intention of usage, realistically, a single global variable makes this simpler than me typing this out :-/
NOTE: don't forcefully bind/tie/use a ISR with a class as there's a lot of overhead that just doesn't make sense (a vtable to boot). An ISR isn't/doesn't have polymorphism as every ISR is functionally independent and identical.
C:\stuff\SW\Arduino_Others\Tst\Tst.ino: In constructor 'TestClass::TestClass(uint8_t)':
Tst:28:52: error: 'bind' is not a member of 'std'
attachInterrupt(digitalPinToInterrupt(pin), std::bind(&TestClass::classIsr, this), RISING);
I'm not aware of any C++ police that would force you to use this technique ... or even use C++ for that matter.
There's no vtable or polymorphism required for the code I posted. The overload of attachInterrupt simply stores a std::function object that is invoked when the interrupt occurs and is processed by the initial ISR that's vectored based on the specific interrupt. I doubt there's much more processing overhead than the regular attachInterrupt technique that stores a function pointer.