[英]C++ callback for c function
Yes,,, I know there is many threads about this, and I've think I've read most of them, but either I don't understand the answers or I have not been able to adapt them to my "case".是的,我知道有很多关于这个的话题,我想我已经阅读了其中的大部分,但要么我不明白答案,要么我无法将它们改编成我的“案例”。
Be aware, my background is electronic design, not software design so for some of you, my question maybe seem to be stupid, but... I am stuck.请注意,我的背景是电子设计,而不是软件设计,所以对于你们中的一些人来说,我的问题可能看起来很愚蠢,但是......我被卡住了。
I have designed a pcb board for iot purposes.我设计了一个用于物联网的 pcb 板。 It is based on a ESP32 module.
它基于 ESP32 模块。 I have 5 buttons connected to the ESP.
我有 5 个按钮连接到 ESP。 ESP32-IDF is far to complicated for me so I've tried to go for the Ardiuno framework.
ESP32-IDF 对我来说太复杂了,所以我尝试使用 Ardiuno 框架。 Now it starts to get complicated.
现在它开始变得复杂。
To detect and debounce the buttons I created a C++ class called Button.为了检测和消除按钮的抖动,我创建了一个名为 Button 的 C++ 类。 A skeleton can be seen below.
下面可以看到一个骨架。
class Button {
..
..
private:
void memberCallback() {
...
}
public:
Button(const uint8_t gpio ) {
..
attachInterrup(digitalPinToInterrupt(gpio), memberCallback, FALLING);
..
}
..
}
I have not found any way to define "memberCallback" without not causing compile errors or not working at all.我还没有找到任何方法来定义“memberCallback”而不会导致编译错误或根本不工作。
This must be a common problem so, please suggest i solution :)这一定是一个常见问题,所以请建议我的解决方案:)
Edit.编辑。 Seems like I not have expressed myself clearly enough, sorry.
好像我表达的不够清楚,抱歉。 - I am aware that if I make memberCallback static, it will at least compile.
- 我知道如果我将 memberCallback 设为静态,它至少会编译。 Problem is that I planned to use 5 instances of this.
问题是我计划使用 5 个实例。 A static callback means that all instances will run same code.
静态回调意味着所有实例都将运行相同的代码。 5 instances means 5 different interrupts.
5 个实例意味着 5 个不同的中断。 How do I identify them.
我如何识别它们。
The ESP32 Arduino Core has an example of how to do exactly this at ESP32 Arduino Core 有一个如何做到这一点的例子
https://github.com/espressif/arduino-esp32/tree/master/libraries/ESP32/examples/GPIO/FunctionalInterrupt https://github.com/espressif/arduino-esp32/tree/master/libraries/ESP32/examples/GPIO/FunctionalInterrupt
I'll quote code from it here:我将在这里引用它的代码:
#include <Arduino.h>
#include <FunctionalInterrupt.h>
#define BUTTON1 16
#define BUTTON2 17
class Button
{
public:
Button(uint8_t reqPin) : PIN(reqPin){
pinMode(PIN, INPUT_PULLUP);
attachInterrupt(PIN, std::bind(&Button::isr,this), FALLING);
};
~Button() {
detachInterrupt(PIN);
}
void IRAM_ATTR isr() {
numberKeyPresses += 1;
pressed = true;
}
private:
const uint8_t PIN;
volatile uint32_t numberKeyPresses;
volatile bool pressed;
}
The important things are:重要的是:
#include <FunctionalInterrupt.h>
- this gets you std::bind()
and a slightly different attachInterrupt()
declaration that makes this work #include <FunctionalInterrupt.h>
- 这让你得到std::bind()
和一个稍微不同的attachInterrupt()
声明,使这项工作std::bind(&Button::isr,this)
to bind your interrupt handler to your object.std::bind(&Button::isr,this)
将您的中断处理程序绑定到您的对象。IRAM_ATTR
to ensure the code for it will remain loaded in RAM.IRAM_ATTR
以确保它的代码将保持加载到 RAM 中。volatile
so that the C++ compiler will know they make change without warning.volatile
以便 C++ 编译器知道它们会在没有警告的情况下进行更改。 std::bind()
is a standard C++ library function; std::bind()
是标准的 C++ 库函数; there's documentation about it online .网上有关于它的文档。
That said, I'm concerned about what you plan to do inside your interrupt handler.也就是说,我担心您打算在中断处理程序中做什么。
Interrupt handlers need to run for a very brief amount of time, and they need to be very careful about calling other functions and making sure that data structures are in an inconsistent state.中断处理程序需要运行很短的时间,他们需要非常小心地调用其他函数并确保数据结构处于不一致的状态。 Unless you lock out interrupts (which you should do as little as possible) outside of the interrupt handler, data structures can easily be in inconsistent states.
除非您在中断处理程序之外锁定中断(您应该尽可能少做),否则数据结构很容易处于不一致状态。
The example in the Arduino Core is good - it just changes a couple of variables. Arduino Core 中的例子很好——它只是改变了几个变量。 Doing more than that - calling functions like
Serial.println()
or allocating memory or creating objects is not safe.做更多的事情 - 调用
Serial.println()
类的函数或分配内存或创建对象是不安全的。
When you look at the documentation of attachInterrupt
it says that the ISR is a function taking no argument.当您查看
attachInterrupt
的文档时,它说 ISR 是一个不带参数的函数。 Its type is void(*)()
(or most likely actually extern "C" void(*)()
but I haven't researched the exact type thoroughly enough).它的类型是
void(*)()
(或者很可能实际上是extern "C" void(*)()
但我还没有足够彻底地研究确切的类型)。 Your memberCallback
looks as if it does not take an argument but that is actually not true: in a [non- static
] member function you got an implicit argument: this
, the pointer to the object which is need to determine which Button
object is used.您的
memberCallback
看起来好像不带参数,但实际上并非如此:在 [非static
] 成员函数中,您有一个隐式参数: this
,指向需要确定使用哪个Button
对象的对象的指针. The type of memberCallback
is void (Button::*)()
and is incompatible with void(*)()
. memberCallback
的类型是void (Button::*)()
并且与void(*)()
不兼容。 Th implication is that you will not be able to use a [non- static
] member function directly.这意味着您将无法直接使用 [非
static
] 成员函数。
As was suggest in other answers, you could use a static
member function.正如其他答案中所建议的那样,您可以使用
static
成员函数。 However, that has two problems:但是,这有两个问题:
static
members (both function and variables).static
成员(函数和变量)。extern
"C"`.extern
"C"`。 You will need one function for every Button
you want to register.对于要注册的每个
Button
您都需要一个功能。 For just one Button
that would look like that:对于一个看起来像这样的
Button
:
class Button
{
// ....
public:
void memberCallback();
Button(int gpio, Button*& ptr, void(*isr)()) {
ptr = this;
attachInterrupt(digitalPinToInterrupt(gpio), isr, FALLING);
}
};
Button* button1;
extern "C" void button1ISR() {
button1ISR->memberCallback();
}
// create you Button somewhere, e.g.:
int main() {
Button b1(gpio, button1, button1ISR);
// ...
}
Make your memberCallback
function static.将您的
memberCallback
函数设为静态。 Change your code to this:将您的代码更改为:
class Button {
..
..
private:
static void memberCallback() {
...
}
public:
Button(const uint8_t gpio ) {
..
attachInterrup(digitalPinToInterrupt(gpio), memberCallback, FALLING);
..
}
..
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.