如何在 Arduino 类中创建 ISR?

Posted

技术标签:

【中文标题】如何在 Arduino 类中创建 ISR?【英文标题】:How to create an ISR in an Arduino class? 【发布时间】:2017-01-03 12:36:56 【问题描述】:

我为 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 写在宏中并让他在主代码中编写它 【参考方案1】:

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

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

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 void ISR())。在第二种情况下,现代 C++ 编码风格倾向于使用匿名命名空间而不是 static

【讨论】:

将 'instance' 定义为静态成员意味着它由 MyClass 类型的所有对象共享,因此我无法在每个 MyClass 对象中分配 MyClass::instance @shayelk:你是说你不能给你的类添加静态成员变量?为什么不呢? 我可以添加一个静态成员变量,但它将成为该类的所有实例共享的单个变量。我需要类的每个实例都有自己的中断函数来改变自己的成员 @shayelk:所以你要为同一个类的不同实例注册多个不同的中断? @shayelk 必须明白,中断发生在随机(从主算法的角度来看)时间,异步。简单代码的任何一部分都无法猜测“this”指针。换句话说:中断处理程序不知道实例(“this”指针/引用) - 这是非常基本的事实。可以做一些实现,但并不简单【参考方案2】:

正如@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();
    
;

【讨论】:

以上是关于如何在 Arduino 类中创建 ISR?的主要内容,如果未能解决你的问题,请参考以下文章

如何在javascript类中创建一个静态字段[重复]

如何在 Ruby 中创建私有类常量

如何设法在 C++ 中创建矢量类?

如何在 C# 中创建 COM 可见类?

Flutter:如何在我的 Style 类中创建构造函数? [复制]

如何在 C++ 中创建一个类的多个实例