如何解决ESP32:异步向后计数
我写了一个小程序,它从 5 倒数到 0,然后执行 println。我已经稍微包装了一下,但请让我展示我的代码:
Main.ino
#include "MyObject.h"
#include <string>
using namespace std;
MyObjekt *myObject;
void setup() {
Serial.begin(115200);
string trigger = "triggering";
myObject = new MyObject(trigger);
}
void loop(){}
MyObject.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
MyObject.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)。是否有可能在后台进行这个倒计时,并且只在前台执行 println (f
)(换句话说:在做工作时监听,如果检测到/发送到监听器,执行,然后再听一遍并继续工作)?
对每个答案和帮助努力都会感到非常高兴。对不起,如果我表达自己的问题,我希望它变得清楚我想要实现的目标^^
最好的问候
解决方法
您好像在使用 Arduino。使用 arduino-timer 库,代码看起来应该类似:
#include <arduino-timer.h>
const size_t TIMER_INTERVAL_MS = 1000;
volatile int counter = 5;
auto timer = timer_create_default();
void setup() {
timer.every(TIMER_INTERVAL_MS,[](void*) -> bool { counter--; return true; });
}
void loop() {
timer.tick();
if (counter <= 0) {
Serial.println("Counter is 0");
counter = 5; // Reset counter
}
抱歉,无法验证或运行代码,因为我没有准备好 Arduino 设置。但你应该明白这一点。
您还可以执行更复杂的解决方案,例如向定时器外设请求中断;或在 RTOS 中设置计时器服务(假设您已升级到一个)。基本原理是一样的。
,首先,如果您从不调用 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() {}