首页 > 解决方案 > ESP32:异步倒数

问题描述

我编写了一个从 5 倒数到 0 的小程序,然后执行 println。我已经包装了一点,但请让我展示我的代码:

主程序

#include "MyObject.h"
#include <string>
using namespace std;

MyObjekt *myObject;

void setup() {
  Serial.begin(115200);

  string trigger = "triggering";
  myObject = new MyObject(trigger);
}
void loop(){}

我的对象.h

#ifndef MYOBJECT_H
#define MYOBJECT_H

#include <string>
using namespace std;

class MyObject{
  public: 
    string field;

    MyObject(string trigger);
    
    string GetField(){ return field; }
    void SetField(string trigger);
};

#endif

我的对象.cpp

#include "MyObject.h"
#include <string>
using namespace std;
#include "Timer.h"

MyObject::MyObject(string trigger){
    SetField(trigger);
}
void MyObject::SetField(string trigger){

    field = trigger;

    auto f = []() {std::cout << "---------------- I waited to print! ----------------\n"; };
    Timer t1{10000,f};
}

定时器.h

#include <iostream>
#include <chrono>
#include <thread>
#include <functional>
#include <mutex>
#include <condition_variable>

class Timer {
public:
    Timer(size_t time, const std::function<void(void)>& f) : time{std::chrono::milliseconds{time}}, f{f} {}
    ~Timer() {wait_thread.join();}

private:
    void wait_then_call()
    {
        std::unique_lock<std::mutex> lck{mtx};
        for(int i{5}; i > 0; --i) {
            //std::cout << "Thread " << wait_thread.get_id() << " countdown at: " << '\t' << i << '\n';
            cv.wait_for(lck, time / 10);
        }
        f();
    }
    std::mutex mtx;
    std::condition_variable cv{};
    std::chrono::milliseconds time;
    std::function <void(void)> f;
    std::thread wait_thread{[this]() {wait_then_call();}};
};

不幸的是,这阻塞了主线程,因此在此期间没有做任何其他事情(如另一个 println)。是否有可能在后台执行此倒计时并且仅f在前台执行 println ( )(换句话说:在工作时进行侦听,如果检测到后台 println 并将其发送给侦听器,则执行,然后再次侦听并继续工作)?

对每一个答案和帮助工作都会感到非常高兴。对不起,如果我表达自己的问题,我希望它变得清楚我想要实现的目标^^

此致

标签: c++asynchronoustimeresp32

解决方案


首先,new如果你从不调用delete,不要使用关键字,因为它会导致内存泄漏。你想要什么可以通过两种方式实现:

1.使用计数器

这仍然在 loopTask 上运行,但它让其他代码运行。

long lastMillis = 0;
long interval = 1000;
long counter = 5;

void setup() {
  Serial.begin(115200);
}

void loop() {
  if (millis() - lastMillis > interval && counter >= 0) {
    lastMillis = millis();
    Serial.println(counter--);
  }

  //Other code would still run
}

2.创建另一个任务

这将是完全异步的,即使您在另一个任务上调用 delay(),loopTask 上的代码仍然会运行。

int counter = 5;
int interval = 1000;

void vTask(void *param) {
  while (counter >= 0) {
    delay(1000);
    Serial.println(counter--);
  }
  vTaskDelete(NULL);
}

void setup() {
  Serial.begin(115200);
  xTaskCreate(vTask, "vTask", 4096, NULL, 1, NULL);
}

void loop() {}

推荐阅读