如何在Arduino类中创建ISR?

时间:2017-01-03 12:36:56

标签: c++ class arduino interrupt

我有一个我为Arduino编写的使用中断的类。目前我需要在主Arduino草图中创建一个ISR实例,然后将其传递给类的初始化函数,该函数运行“attachInterrupt”。这是非常糟糕的风格(为什么用户应该知道我甚至使用中断?),所以我希望整个事情都包含在类的头文件和源文件中。

我尝试使ISR成为静态友元函数,但是它无法访问任何类的非静态成员。所以现在我对这种工作方法应该和不应该是静态的有点困惑。我尝试做的事情看起来像那样(源和标题组合在这里以便于阅读)

class myClass{
    friend void ISR();
    void init(){attachInterrupt(ISR,..,..);}
}

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

但编译器对我在静态函数中使用非静态成员大吼大叫。 我非常感谢你能帮助我理解如何让它发挥作用。

2 个答案:

答案 0 :(得分:2)

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

以下是如何做到这一点的草图:

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() {
        // ...
    }
}

这是设置此功能的众多方法之一,但您无法避免中断本身具有全局性这一事实。在上面的实现中有一些“陷阱”,我省略了,希望你知道这些。

P.S。另请注意,“静态”具有多种含义。它在声明类成员时有一个含义,在声明类外的函数时具有完全不同的含义(如在声明static void ISR()中)。在第二种情况下,现代C ++编码风格倾向于使用匿名命名空间而不是static

答案 1 :(得分:1)

正如@DietrichEpp所说,中断必须是静态功能。但是这是另一种在类中使用继承的方法。

步骤1 - 使用虚拟纯InterServ()函数和基于一组枚举的实例数组创建一个中断基类。

class IntBase {
public:
    virtual void InterServ() = 0;
};

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

static IntBase *tInstance[INT_MAX];

第2步 - 每个使用类中断都有:

  • 用于存储实例的构造函数
  • 一个静态函数ISRFunc()专门用于该类
  • 虚拟函数InterServ(),从静态ISRFunc()调用。
  

class 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();
    }
};