我有这个代码:
#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”类成员变量?
您几乎已经遇到了这个问题,并尝试围绕它进行编程。这是面向 C 的 SDK 和 C++ 开发之间令人痛苦的阻抗不匹配之一。
您的问题是您没有来自中断上下文的类实例。中断回调是一个 C 函数。您的中断回调是 C++,并且因为您使用的是类数据,所以您需要一个“this”指针,但您没有这个指针,因为中断没有类实例。当您将计数器移到类之外时它会起作用,因为它是全局的而不是 this->iCounter (请记住,即使在模糊的现代 C++ 中,“this”也是可选的。)
我能想到的有两种方法可以解决这个问题。我凭记忆打字,语法很挑剔,所以这更像是“启动板”答案,而不是“将其粘贴到代码中”答案。
我很确定答案就在这个近似的空间内,尽管我肯定有精确的 C++ 拼写错误。像PMF(指向[静态]成员函数的指针)这样的关键字,捕获这个,并且一般来说,C++中的中断处理应该有助于进一步google-fu。
还要记住,ESP32 上的中断处理程序可以访问的数据需要标记为 IRAM_ATTR。如果你得到一个(LoadProhibited)。异常未处理。当尝试访问您的实例数据时,您就会知道您已经遇到了冲突。在中断处理程序中运行 printf 是一件非常勇敢的事情。
如果您觉得有用,请点赞。我正在努力逃离 StackOverflow n00b 监狱。