You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ESP32 Arduino环境下类中FreeRTOS任务传参错误问题求助

问题:ESP32类中向FreeRTOS任务传递参数输出始终为0.00

使用ESP32开发板与Arduino IDE,尝试在类中向FreeRTOS任务传递浮点参数,但任务中输出结果始终为0.00。以下是代码示例:

class testClass {
  public:
    testClass(/*parameters*/){
      //Do some stuff...
    }
  private:
    TaskHandle_t testTask;

    static void testTaskFunction (void * pvParameters) {
      float *number = (float *) pvParameters; 

      String stringifiedNumber;
      stringifiedNumber = String(*number);

      Serial.println(stringifiedNumber); // Output 2
      Serial.println(*number); // Output 3

      vTaskDelete(NULL); // Must be there, otherwise there will be an error because the function is finished but the task still exists. Here the task is deleted and the function is aborted.
    }

  public:
    void testFunction (float number) {
      Serial.println(number); // Output 1

      xTaskCreatePinnedToCore(
        testTaskFunction, // Function to implement the task 
        "testTask", // Name of the task
        10000,  // Stack size in words
        (void *) &number,  // Task input parameter
        2,  // Priority of the task
        &testTask,  // Task handle.
        0); // Core where the task should run
    }
};

testClass testInstance1;
testClass testInstance2;


void setup() {
  // put your setup code here, to run once:
  Serial.begin(115200);
}

void loop() {
  // put your main code here, to run repeatedly:  
  for (float i = -20; i < 30; i += 0.1) {
    testInstance1.testFunction(i);
    delay(1000);
    testInstance2.testFunction(i + 21);
    delay(1000);
  }
}

输出结果(不含注释):

ets Jun  8 2016 00:22:57

rst:0x1 (POWERON_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
configsip: 0, SPIWP:0xee
clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
mode:DIO, clock div:1
load:0x3fff0030,len:1416
load:0x40078000,len:14804
load:0x40080400,len:4
load:0x40080404,len:3356
entry 0x4008059c
-20.00 // Output 1 (testInstance1)
0.00 //   Output 2 (testInstance1)
0.00 //   Output 3 (testInstance1)
1.00 //   Output 1 (testInstance2)
0.00 //   Output 2 (testInstance2)
0.00 //   Output 3 (testInstance2)
-19.90 // ...
0.00
0.00
1.10
0.00
0.00
-19.80
0.00
0.00
1.20
0.00
0.00
-19.70
0.00
0.00
1.30
0.00
0.00
-19.60
0.00
0.00
1.40
0.00
0.00
-19.50
0.00
0.00
1.50
0.00
0.00
-19.40
0.00
0.00
1.60
0.00
0.00
-19.30
0.00
0.00
1.70
0.00
0.00

已尝试的方法:

  • 移除另一个类实例后功能恢复正常,但这并非可行方案
  • 调整delay的时长也没有效果

解答

问题核心是传递了局部变量的地址:

在testFunction中,number是函数的局部参数,存储在栈内存中。当testFunction执行完毕返回后,该局部变量的内存空间会被释放或被后续代码覆盖。而FreeRTOS任务创建后不一定立即执行,等到任务运行时,&number指向的内存已经失效,读取到的就是随机值或0.00。移除一个类实例后偶尔正常,只是内存覆盖的概率降低,并非可靠解决办法。

提供两种修复方案:

方案1:直接传递值(适合单个基础类型)

ESP32中float和void*的内存大小均为4字节,可以直接把浮点值转换为指针类型传递,任务中再转换回浮点值:

修改testFunction的参数传递:

xTaskCreatePinnedToCore(
  testTaskFunction,
  "testTask",
  10000,
  (void *) number,  // 直接传递值而非地址
  2,
  &testTask,
  0);

修改任务函数:

static void testTaskFunction (void * pvParameters) {
  float number = (float) pvParameters;  // 将指针转换回浮点值

  String stringifiedNumber = String(number);
  Serial.println(stringifiedNumber);
  Serial.println(number);

  vTaskDelete(NULL);
}

方案2:动态分配内存(适合复杂类型/多参数)

通过malloc分配堆内存存储参数,任务使用完成后释放内存,避免局部变量失效问题:

修改testFunction:

void testFunction (float number) {
  Serial.println(number);

  float* param = (float*)malloc(sizeof(float));
  *param = number;

  xTaskCreatePinnedToCore(
    testTaskFunction,
    "testTask",
    10000,
    param,  // 传递动态分配的内存地址
    2,
    &testTask,
    0);
}

修改任务函数,使用后释放内存:

static void testTaskFunction (void * pvParameters) {
  float *number = (float *) pvParameters; 

  String stringifiedNumber = String(*number);
  Serial.println(stringifiedNumber);
  Serial.println(*number);

  free(number);  // 释放动态分配的内存,避免泄漏
  vTaskDelete(NULL);
}

额外注意事项

  • 任务名称建议唯一,可添加实例标识避免冲突
  • 栈大小可根据实际需求调整,10000 words对于简单任务过大,可改为2048左右

内容的提问来源于stack exchange,提问作者Pr77Pr77

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.08 05:44:55