首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >C函数的C++回调

C函数的C++回调
EN

Stack Overflow用户
提问于 2020-03-12 06:45:31
回答 3查看 970关注 0票数 0

是的,我知道这方面有很多线索,我想我读过其中的大部分,但要么我不明白答案,要么我无法使它们适应我的“案例”。

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

我为物联网设计了一个pcb板。它基于一个ESP32模块。我有5个按钮连接到ESP。ESP32 32-以色列国防军对我来说太复杂了,所以我试着采用Ardiuno框架。现在事情开始变得复杂起来。

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

代码语言:javascript
复制
class Button {
..
..

private:
  void memberCallback() {
    ...
  }



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

..

}

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

这必须是一个常见的问题,因此,请建议我的解决方案:)

编辑。好像我表达得不够清楚,抱歉。-我知道,如果我使memberCallback是静态的,它至少会编译。问题是,我计划使用这5个实例。静态回调意味着所有实例都将运行相同的代码。5个实例意味着5个不同的中断。我怎么才能认出他们。

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2020-03-12 15:27:50

ESP32 Arduino Core有一个示例说明了如何在

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

我将在这里引用代码:

代码语言:javascript
复制
#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;
}

重要的是:

  • #include <FunctionalInterrupt.h> -这让您可以使用std::bind()和一个稍微不同的attachInterrupt()声明来完成这项工作。
  • 使用std::bind(&Button::isr,this)将中断处理程序绑定到对象。
  • 请确保将中断处理程序声明为IRAM_ATTR,以确保其代码将始终加载在内存中。
  • 确保将要在中断处理程序中修改的任何实例变量声明为volatile,以便C++编译器知道它们在没有警告的情况下进行更改。

std::bind()是一个标准的C++库函数;有网上有关资讯科技的文件

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

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

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

票数 5
EN

Stack Overflow用户

发布于 2020-03-12 09:23:31

当您查看attachInterrupt的文档时,它说ISR是一个不带任何参数的函数。它的类型是void(*)() (或者很可能是extern "C" void(*)(),但我还没有对确切的类型进行足够深入的研究)。您的memberCallback看起来好像不带参数,但实际上并非如此:在非static成员函数中,您得到了一个隐式参数:this,这是指向需要确定使用哪个Button对象的对象的指针。memberCallback的类型是void (Button::*)(),与void(*)()不兼容。这意味着您将无法直接使用非static成员函数。

正如其他答案中所建议的那样,您可以使用static成员函数。然而,这有两个问题:

  1. 该函数只能访问static成员(函数和变量)。
  2. 函数不会是extern“C”‘。

要注册的每个Button都需要一个函数。只有一个看起来像这样的Button

代码语言:javascript
复制
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);
    // ...
}
票数 1
EN

Stack Overflow用户

发布于 2020-03-12 07:04:17

使您的memberCallback函数保持静态。将代码更改为:

代码语言:javascript
复制
class Button {
..
..

private:
  static void memberCallback() {
    ...
  }



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

..

}
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/60648871

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档