如何在Arduino类中创建ISR?
问题描述:
我有一个我为Arduino写的使用中断的类。目前我需要在主要的Arduino草图中创建一个ISR实例,然后将其传递给类的初始化函数,该函数运行“attachInterrupt”。这是非常糟糕的风格(为什么用户应该知道我甚至使用了中断?),所以我希望整个事情被包含在类的头文件和源文件中。如何在Arduino类中创建ISR?
我试图让ISR成为一个静态的朋友函数,但它不能到达任何类的非静态成员。所以现在我对这种方法的工作应该是什么也不应该是静态的有点困惑。我试图做看起来就像这样(源文件和头在这里结合,为方便阅读)
class myClass{
friend void ISR();
void init(){attachInterrupt(ISR,..,..);}
}
static void ISR(){
all sort of stuff using myClass.members;
}
但是,编译骂我在一个静态函数使用非静态成员。 我真的很感谢在理解我如何使它工作方面的一些帮助。
答
中断必须是静态函数(如果它们是成员函数)才能正常工作,所以如果要使用非静态成员,则需要获取实例。你可以切实做到的唯一方法就是使用全局变量。
这里是你如何能做到这一点草图:
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
。
答
正如@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();
}
};
“为什么要用户知道,我甚至使用中断吗?”因为你正在使用微控制器的独特功能,所以他需要知道它,所以他可以计划如何管理它。如果您针对一个引脚使用电平变化中断,并且不希望他看到该引脚,那么他将无法使用每个引脚上的电平变化中断,因为ISR已经实现由你。只需创建一个他必须在ISR中调用的函数,或者将宏写入ISR并请求他将其写入主代码 – frarugi87