C函数的C++回调

lg.*_*rom 0 c c++ arduino esp32

是的,,,我知道有很多关于这个的话题,我想我已经阅读了其中的大部分,但要么我不理解答案,要么我无法将它们适应我的“案例”。

请注意,我的背景是电子设计,而不是软件设计,所以对于你们中的一些人来说,我的问题可能看起来很愚蠢,但是......我被困住了。

我设计了一块用于物联网用途的 PCB 板。它基于 ESP32 模块。我有 5 个按钮连接到 ESP。ESP32-IDF 对我来说太复杂了,所以我尝试使用 Arduino 框架。现在事情开始变得复杂了。

为了检测和消除按钮的抖动,我创建了一个名为 Button 的 C++ 类。下面可以看到一个骨架。

class Button {
..
..

private:
  void memberCallback() {
    ...
  }



public:
  Button(const uint8_t gpio ) {
    ..
    attachInterrup(digitalPinToInterrupt(gpio), memberCallback, FALLING);
    ..
  }

..

}
Run Code Online (Sandbox Code Playgroud)

我还没有找到任何方法来定义“memberCallback”,而不会导致编译错误或根本无法工作。

这一定是一个常见问题,所以请建议我解决方案:)

编辑。看来我表达得不够清楚,抱歉。- 我知道如果我将memberCallback设置为静态,它至少会编译。问题是我计划使用 5 个这样的实例。静态回调意味着所有实例将运行相同的代码。5 个实例意味着 5 个不同的中断。我如何识别它们。

rom*_*key 5

ESP32 Arduino Core 有一个关于如何做到这一点的示例,网址为

https://github.com/espressif/arduino-esp32/tree/master/libraries/ESP32/examples/GPIO/FunctionalInterrupt

我将在这里引用其中的代码:

#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;
}
Run Code Online (Sandbox Code Playgroud)

重要的是:

  • #include <FunctionalInterrupt.h>- 这让你std::bind()得到一个稍微不同的attachInterrupt()声明,使这个工作有效
  • 用于std::bind(&Button::isr,this)将中断处理程序绑定到对象。
  • 确保声明中断处理程序以IRAM_ATTR确保其代码将保持加载在 RAM 中。
  • 确保在中断处理程序中声明要修改的任何实例变量,volatile以便 C++ 编译器知道它们进行了更改而不发出警告。

std::bind()是标准C++库函数;网上有关于它的文档

也就是说,我担心你计划在中断处理程序中做什么。

中断处理程序需要运行非常短的时间,并且它们需要非常小心地调用其他函数并确保数据结构处于不一致的状态。除非您在中断处理程序之外锁定中断(您应该尽可能少地这样做),否则数据结构很容易处于不一致的状态。

Arduino Core 中的示例很好 - 它只更改了几个变量。做更多的事情 - 调用函数,例如Serial.println()分配内存或创建对象是不安全的。