【问题标题】:ESP32 not updating the variable when multiple cores are used使用多个内核时,ESP32 不更新变量
【发布时间】:2021-12-27 20:27:58
【问题描述】:

我的计划是从 ESP32 的 CORE-1 收集数据,并将 ESP32 的 CORE-0 用于所有其他任务。但是,我看到使用多个内核时变量没有正确更新。在这个例子中,我看到getAllData 的值只更新了一次。


const TickType_t xDelay = 1000 / portTICK_PERIOD_MS;

TaskHandle_t collectData;


bool volatile getAllData;
bool volatile dataReadyToSend;





void setup() {
  Serial.begin(115200);
  Serial.print("setup() is running on core ");
  Serial.println(xPortGetCoreID());
  xTaskCreatePinnedToCore(collectDataCode,"collectData",10000,NULL,1,&collectData,0);
  delay(500);
}

void loop() {
  if (Serial.available()) {
    Serial.flush();
    getAllData = true;
  }
  Serial.print("From loop: ");
  Serial.println(getAllData);
  if (dataReadyToSend) {
    dataReadyToSend = false;
  }
  delay(1000);
}



void collectDataCode(void * params) {
  while (1) {
    Serial.print("From collectData: ");
    Serial.println(getAllData);
    if (getAllData) {
      getAllData=0;
    }
    vTaskDelay( xDelay );
  }  
}

上述代码的输出如下。我在哪里输入xxx。观察到变量getAllData在这个实例中得到了更新,但后来没有改变。

From collectData: 0
From loop: 0
From collectData: 0
From loop: 0
From collectData: 0
From loop: 0
From collectData: 0
From loop: 0
From collectData: 0
xxx
From loop: 1
From collectData: 1
From loop: 1
From collectData: 1
From loop: 1
From collectData: 1
From loop: 1
From collectData: 1

更新

根据建议,我将atomic 与以下代码一起使用。我仍然认为没有成功。


#ifdef __cplusplus
#include <atomic>
using namespace std;
#else
#include <stdatomic.h>
#endif



TaskHandle_t collectData;



atomic<bool> getAllData;
atomic<bool> dataReadyToSend;


#include "collectData.h"




void setup() {
  Serial.begin(115200);
  Serial.print("setup() is running on core ");
  Serial.println(xPortGetCoreID());
  xTaskCreatePinnedToCore(collectDataCode,"collectData",10000,NULL,1,&collectData,0);
  delay(500);
}

void loop() {
  if (Serial.available()) {
    Serial.flush();
    atomic_store (&getAllData, true);
  }
  Serial.print("From loop: ");
  Serial.println(atomic_load(&getAllData));
  if (dataReadyToSend) {
    dataReadyToSend = false;
  }
  delay(1000);
}



void collectDataCode(void * params) {
  while (1) {
    Serial.print("From collectData: ");
    Serial.println(atomic_load(&getAllData));
    if (atomic_load(&getAllData)) {
      atomic_store (&getAllData, false);
    }
    vTaskDelay( xDelay );
  }
  
  
}

【问题讨论】:

  • volatile 对跨线程同步没有任何作用。使用std::atomic&lt;bool&gt;.
  • @PeteBecker,我认为atomic 没有成功。我用atomic 代码更新了问题。

标签: c++ core esp32 freertos arduino-esp32


【解决方案1】:

我找到了答案。问题不在于变量本身,而在于 Arduino 的Serial.flush()。从 1.0 版开始,arduino 使用Serial.flush() 清除传出的串行数据而不是传入的串行数据。所以,我用下面的代码替换了Serial.flush()


while(Serial.available()) {
  Serial.read();
}

通过此更新,我的代码运行良好。感谢@PeteBecker 的评论,我正在使用原子。最终代码和结果如下。

#ifdef __cplusplus
#include <atomic>
using namespace std;
#else
#include <stdatomic.h>
#endif



TaskHandle_t collectData;



atomic<bool> getAllData;
atomic<bool> dataReadyToSend;


#include "collectData.h"




void setup() {
  Serial.begin(115200);
  Serial.print("setup() is running on core ");
  Serial.println(xPortGetCoreID());
  xTaskCreatePinnedToCore(collectDataCode,"collectData",10000,NULL,1,&collectData,0);
  delay(500);
}

void loop() {
  if (Serial.available()) {
    while(Serial.available()) {
      Serial.read();
    }
    getAllData.store(true);
    Serial.println("Received data request");
  }
  Serial.print("From loop: ");
  Serial.println(getAllData.load());
  if (dataReadyToSend) {
    dataReadyToSend = false;
  }
  delay(1000);
}



void collectDataCode(void * params) {
  while (1) {
    Serial.print("From collectData: ");
    Serial.println(atomic_load(&getAllData));
    if (getAllData.load()) {
      getAllData.store(false);
    }
    vTaskDelay( xDelay );
  }
  
  
}

结果

From loop: 0
From collectData: 0
From loop: 0
From collectData: 0
From loop: 0
From collectData: 0
.
From loop: 0
From collectData: 0
Received data request
From loop: 1
From collectData: 1
From loop: 0
From collectData: 0
From loop: 0
From collectData: 0
From loop: 0
From collectData: 0
From loop: 0
From collectData: 0
From loop: 0

【讨论】:

  • "由于某种原因,Serial.flush() 没有清除 Serial.available()" 因为flush() 刷新了 outgoing 数据,而available() 返回传入数据的大小。
  • @gre_gor,我误解了。看起来很傻。很抱歉为大家浪费时间。
  • @gre_gor,你贡献的比我多。如果您发布答案,我将选择作为接受的答案。
  • 你可以编辑你的来澄清误解。