ESP32类成员变量在定时器回调函数中无法正常更新的问题
ESP32类成员变量在定时器回调中无法递增的解决方法
我在Arduino环境下编写了ESP32代码,期望每次调用myTestFn()时类成员变量iCounter能递增,但它始终保持为1。将iCounter声明移到Test类外部时能正常更新,请问如何让Test类的成员变量在myTestFn()中正常更新?
#include <Arduino.h> #include "esp_timer.h" //volatile int iCounter; <-- 取消注释此行后iCounter可在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; // <-- 此处无法正常工作,iCounter在myTestFn()中不更新 }; void setup() { Serial.begin(115200); while(!Serial); Test justATestObject; } void loop() { }
问题根源
核心问题是justATestObject是setup()函数内的局部变量:当setup()执行完毕后,这个对象会被销毁,其占用的内存会被系统回收或复用。而定时器的回调函数还在尝试通过之前保存的this指针访问这个已销毁对象的iCounter成员,此时访问的是无效内存,导致数值始终显示为1(实际是随机的无效值)。
当把iCounter移到全局作用域时,它不受对象生命周期影响,所以能正常递增。
解决方案
只需确保Test对象在程序运行的整个周期内都存在,有两种常用方式:
将对象声明为全局变量
把Test justATestObject;移到setup()函数外面,变成全局变量:#include <Arduino.h> #include "esp_timer.h" class Test { // 类定义保持不变 }; Test justATestObject; // 全局对象,生命周期覆盖整个程序 void setup() { Serial.begin(115200); while(!Serial); } void loop() { }使用动态分配创建对象
在setup()中用new创建对象,避免局部变量被销毁:void setup() { Serial.begin(115200); while(!Serial); Test* justATestObject = new Test(); // 动态分配,对象会一直存在直到手动delete }
这样修改后,定时器回调访问的是有效的对象成员,iCounter就能正常递增了。
内容的提问来源于stack exchange,提问作者Michael Hanagan
相关产品推荐
相关产品推荐

