我有一个我为Arduino编写的使用中断的类。目前我需要在主Arduino草图中创建一个ISR实例,然后将其传递给类的初始化函数,该函数运行“attachInterrupt”。这是非常糟糕的风格(为什么用户应该知道我甚至使用中断?),所以我希望整个事情都包含在类的头文件和源文件中。
我尝试使ISR成为静态友元函数,但是它无法访问任何类的非静态成员。所以现在我对这种工作方法应该和不应该是静态的有点困惑。我尝试做的事情看起来像那样(源和标题组合在这里以便于阅读)
class myClass{
friend void ISR();
void init(){attachInterrupt(ISR,..,..);}
}
static void ISR(){
all sort of stuff using myClass.members;
}
但编译器对我在静态函数中使用非静态成员大吼大叫。 我非常感谢你能帮助我理解如何让它发挥作用。
答案 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();
}
};