ESP32 类成员变量未按计时器回调函数中的预期更新

问题描述 投票:0回答:1

我有这个代码:

#include <Arduino.h>

#include "esp_timer.h"

//volatile int iCounter; <-- Uncommenting this line makes iCounter update in myTestFn()

class Test {
    public:       

        Test(void) {
            esp_timer_handle_t testTimer;
            esp_timer_create_args_t timerConfig;
            timerConfig.arg = this;
            timerConfig.callback = reinterpret_cast<esp_timer_cb_t>( testFn );
            timerConfig.dispatch_method = ESP_TIMER_TASK;
            timerConfig.name = "Test_Timer";
            esp_timer_create( &timerConfig, &testTimer );
            esp_timer_start_periodic( testTimer, 1000000 );
        }
        
        static void testFn(void *arg) {
          Test *obj = (Test *)arg;
          obj->myTestFn();
        }
          
        void myTestFn(void) {
            iCounter = iCounter +1;
            Serial.printf("Test succeeded! Counter: %d Time elapsed: %lu.%03lu sec\n", iCounter, millis() / 1000, millis() % 1000);
        }
    private:

        volatile int iCounter; // <-- This does not work, iCounter does not update in myTestFn()
};

void setup() {

    Serial.begin(115200);
    while(!Serial);
    Test justATestObject;
}

void loop() {
}

我希望每次调用 myTestFn() 时都会对 iCounter 变量进行索引,但该值仍为 1。

当我将 iCounter 的声明移到类 Test{} 之外时,它确实会更新(这对我来说似乎很奇怪)。 如何在 myTestFn() 内更新“Test”类成员变量?

timer interrupt arduino-esp32
1个回答
0
投票

您几乎已经遇到了这个问题,并尝试围绕它进行编程。这是面向 C 的 SDK 和 C++ 开发之间令人痛苦的阻抗不匹配之一。

您的问题是您没有来自中断上下文的类实例。中断回调是一个 C 函数。您的中断回调是 C++,并且因为您使用的是类数据,所以您需要一个“this”指针,但您没有这个指针,因为中断没有类实例。当您将计数器移到类之外时它会起作用,因为它是全局的而不是 this->iCounter (请记住,即使在模糊的现代 C++ 中,“this”也是可选的。)

我能想到的有两种方法可以解决这个问题。我凭记忆打字,语法很挑剔,所以这更像是“启动板”答案,而不是“将其粘贴到代码中”答案。

  1. 为中断处理程序注册一个 lambda 并捕获 [this]。语法有点模糊: timerConfig.callback = []{测试:myTestFn};
  2. 使用bind()获取包含函数指针和[this]引用的指针束。 timerConfig.callback = std::bind(&Test::myTestFn, this)

我很确定答案就在这个近似的空间内,尽管我肯定有精确的 C++ 拼写错误。像PMF(指向[静态]成员函数的指针)这样的关键字,捕获这个,并且一般来说,C++中的中断处理应该有助于进一步google-fu。

还要记住,ESP32 上的中断处理程序可以访问的数据需要标记为 IRAM_ATTR。如果你得到一个(LoadProhibited)。异常未处理。当尝试访问您的实例数据时,您就会知道您已经遇到了冲突。在中断处理程序中运行 printf 是一件非常勇敢的事情。

如果您觉得有用,请点赞。我正在努力逃离 StackOverflow n00b 监狱。

© www.soinside.com 2019 - 2024. All rights reserved.