如何在Arduino类中创建ISR?

4
我写了一个基于Arduino的类,使用中断。目前我需要在主Arduino代码中创建ISR的实例,然后将其传递给该类的初始化函数,该函数运行“attachInterrupt”。这是非常糟糕的风格(为什么用户需要知道我使用了中断?),因此我希望整个过程都包含在类的头文件和源文件中。
我尝试将ISR作为静态友元函数,但是它无法访问类的任何非静态成员。所以我现在有点困惑,关于这种方法应该是静态的还是非静态的。我的尝试看起来像这样(将源代码和头文件合并在此以方便阅读):
class myClass{
    friend void ISR();
    void init(){attachInterrupt(ISR,..,..);}
}

static void ISR(){
    all sort of stuff using myClass.members;
}

但是编译器在静态函数中使用非静态成员时报错。 我希望能得到一些帮助,了解如何使它正常运行。


“为什么用户需要知道我正在使用中断?”因为您正在使用微控制器的独特功能,所以他需要知道它,以便他可以计划如何管理它。如果您正在为一个引脚使用中断变化,并且您不希望他看到它,那么他将无法为每个其他引脚使用中断变化,因为ISR已经由您实现。只需创建一个函数,他必须在ISR中调用该函数,或者编写一个宏ISR并要求他在主代码中编写它。 - frarugi87
2个回答

3

中断必须是静态函数(如果它们是成员函数),才能正常工作。因此,如果您想使用非静态成员,则需要获取实例。唯一可以实现这一点的方法是使用全局变量。

以下是如何实现的简要概述:

class MyClass {
    static MyClass *instance;

    void init() {
        instance = this;
        attachInterrupt(...)
    }

    // Forward to non-static member function.
    static void ISRFunc() {
        instance->ISR();
    }

    // Do your work here.
    void ISR() {
        // ...
    }
}

这是其中一种设置方式,但无法避免中断本质上是全局的这一事实。上述实现存在许多“陷阱”,我将忽略它们,希望您已经意识到了这些问题。
另外请注意,“static”有多重含义。在声明类成员时有一种含义,在声明类外函数时(如您的声明static void ISR())则完全不同。现代C++编码风格倾向于在第二种情况下使用匿名命名空间而非static

将“instance”定义为静态成员意味着它被MyClass类型的所有对象共享,因此在每个MyClass对象中没有可以分配给的MyClass::instance。 - shayelk
@shayelk:你是说你不能向你的类添加静态成员变量吗?为什么不行? - Dietrich Epp
我可以添加一个静态成员变量,但那将被所有类实例共享的单个变量。我需要每个类实例都有自己的中断函数,该函数更改其自己的成员变量。 - shayelk
@shayelk:所以你正在使用同一类的不同实例注册多个不同的中断? - Dietrich Epp
@JacekCz,明白了,我正在寻找的是每次创建类对象时创建函数的静态实例(使用“this”),以便在初始化时将指针发送到ISR。不确定我正在寻找什么是否清楚 :) - shayelk
显示剩余3条评论

1
作为@DietrichEpp所说,中断必须是静态函数。但是另一种方法是使用类中的继承。
步骤1-创建一个Interrupt基类,该类有一个虚拟纯InterServ()函数和一个基于枚举集合的实例数组。
class IntBase {
public:
    virtual void InterServ() = 0;
};

enum eIntNum {
    INT_DEV1 = 0,
    INT_DEV2,
    // ...
    INT_MAX
};

static IntBase *tInstance[INT_MAX];

步骤2 - 每个使用类中断都将具有:

  • 一个构造函数来存储实例,
  • 一个专门为该类设计的静态函数ISRFunc()
  • 一个从静态ISRFunc()调用的虚函数InterServ()

IntDev1类,编号为INT_DEV1

class IntDev1 : public IntBase {
public:
    IntDev1() {
        tInstance[INT_DEV1] = this;
        // attachInterrupt(...)
    }
    virtual void InterServ() {
        // access to local members
    }
    static void ISRFunc() {
        tInstance[INT_DEV1]->InterServ();
    }
};

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接