全局变量在下一个循环之前不更新
Global variable doesn't update prior to next loop
我正在尝试用 C++ 为我的 ESP32 构建一个转速计。当我在条件之外取消注释 Serial.printf("outside rev: %d \n", rev);
它起作用时,但是当我对其进行注释时,我得到的值比它们应该的值大几个数量级(700 转没有,7 转有)。我最好的猜测是 print 语句正在减慢 loop()
的速度,刚好足以让 incrementRevolutions()
在下一个循环之前将全局变量 passedMagnet
从 true 切换为 false。这是有道理的,因为延迟更新 passedMagnet 将允许 newRevCount++;
被多次触发。但这显然是我无法使用打印语句或逐步调试进行调试的事情,因为竞争条件具有时间敏感性。
bool passedMagnet = true;
int incrementRevolutions(int runningRevCount, bool passingMagnet)
{
// Serial.printf("passedMagnet: %d , passingMagnet %d , runningRevCount: %d \n", passedMagnet, passingMagnet, runningRevCount);
int newRevCount = runningRevCount;
if (passedMagnet && passingMagnet)
{ //Started a new pass of the magnet
passedMagnet = false;
newRevCount++;
}
else if (!passedMagnet && !passingMagnet)
{ //The new pass of the magnet is complete
passedMagnet = true;
}
return newRevCount;
}
unsigned long elapsedTime = 0;
unsigned long intervalTime = 0;
int rev = 0;
void loop()
{
intervalTime = millis() - elapsedTime;
rev = incrementRevolutions(rev, digitalRead(digitalPin));
// Serial.printf("outside rev: %d \n", rev);
if (intervalTime > 1000)
{
Serial.printf("rev: %d \n", rev);
rev = 0;
elapsedTime = millis();
}
}
这是 Arduino 或 C++ 编程的已知问题吗?我应该怎么做才能解决它?
我觉得是考试惹的祸。我不得不重命名并移动一些东西以可视化逻辑,对此感到抱歉。
bool magStateOld = false; // initialize to digitalRead(digitalPin) in setup()
int incrementRevolutions(int runningRevCount, bool magState)
{
int newRevCount = runningRevCount;
// detect positive edge.
if (magState && !magStateOld) // <- was eq. to if (magState && magStateOld)
// the large counts came from here.
{
newRevCount++;
}
magStateOld = magState; // record last state unconditionally
return newRevCount;
}
你也可以写成...
int incrementRevolutions(int n, bool magState)
{
n += (magState && !magStateOld);
magStateOld = magState;
return n;
}
但最经济(也是最快)的方法是:
bool magStateOld;
inline bool positiveEdge(bool state, bool& oldState)
{
bool result = (state && !oldState);
oldState = state;
return result;
}
void setup()
{
// ...
magStateOld = digitalRead(digitalPin);
}
void loop()
{
// ...
rev += (int)positiveEdge(digitalRead(digitalPin), magStateOld);
// ...
}
它是可重用的,并且节省了堆栈 space 和不必要的分配。
如果您无法从传感器获得干净的转换(正边缘和负边缘上的噪声,您需要使用计时器对信号进行一些去抖。
示例:
constexpr byte debounce_delay = 50; // ms, you may want to play with
// this value, smaller is better.
// but must be high enough to
// avoid issues on expected
// RPM range.
// 50 ms is on the high side.
byte debounce_timestamp; // byte is large enough for delays
// up to 255ms.
// ...
void loop()
{
// ...
byte now = (byte)millis();
if (now - debounce_timestamp >= debounce_delay)
{
debounce_timestamp = now;
rev += (int)positiveEdge(digitalRead(digitalPin), magStateOld);
}
// ...
}
我正在尝试用 C++ 为我的 ESP32 构建一个转速计。当我在条件之外取消注释 Serial.printf("outside rev: %d \n", rev);
它起作用时,但是当我对其进行注释时,我得到的值比它们应该的值大几个数量级(700 转没有,7 转有)。我最好的猜测是 print 语句正在减慢 loop()
的速度,刚好足以让 incrementRevolutions()
在下一个循环之前将全局变量 passedMagnet
从 true 切换为 false。这是有道理的,因为延迟更新 passedMagnet 将允许 newRevCount++;
被多次触发。但这显然是我无法使用打印语句或逐步调试进行调试的事情,因为竞争条件具有时间敏感性。
bool passedMagnet = true;
int incrementRevolutions(int runningRevCount, bool passingMagnet)
{
// Serial.printf("passedMagnet: %d , passingMagnet %d , runningRevCount: %d \n", passedMagnet, passingMagnet, runningRevCount);
int newRevCount = runningRevCount;
if (passedMagnet && passingMagnet)
{ //Started a new pass of the magnet
passedMagnet = false;
newRevCount++;
}
else if (!passedMagnet && !passingMagnet)
{ //The new pass of the magnet is complete
passedMagnet = true;
}
return newRevCount;
}
unsigned long elapsedTime = 0;
unsigned long intervalTime = 0;
int rev = 0;
void loop()
{
intervalTime = millis() - elapsedTime;
rev = incrementRevolutions(rev, digitalRead(digitalPin));
// Serial.printf("outside rev: %d \n", rev);
if (intervalTime > 1000)
{
Serial.printf("rev: %d \n", rev);
rev = 0;
elapsedTime = millis();
}
}
这是 Arduino 或 C++ 编程的已知问题吗?我应该怎么做才能解决它?
我觉得是考试惹的祸。我不得不重命名并移动一些东西以可视化逻辑,对此感到抱歉。
bool magStateOld = false; // initialize to digitalRead(digitalPin) in setup()
int incrementRevolutions(int runningRevCount, bool magState)
{
int newRevCount = runningRevCount;
// detect positive edge.
if (magState && !magStateOld) // <- was eq. to if (magState && magStateOld)
// the large counts came from here.
{
newRevCount++;
}
magStateOld = magState; // record last state unconditionally
return newRevCount;
}
你也可以写成...
int incrementRevolutions(int n, bool magState)
{
n += (magState && !magStateOld);
magStateOld = magState;
return n;
}
但最经济(也是最快)的方法是:
bool magStateOld;
inline bool positiveEdge(bool state, bool& oldState)
{
bool result = (state && !oldState);
oldState = state;
return result;
}
void setup()
{
// ...
magStateOld = digitalRead(digitalPin);
}
void loop()
{
// ...
rev += (int)positiveEdge(digitalRead(digitalPin), magStateOld);
// ...
}
它是可重用的,并且节省了堆栈 space 和不必要的分配。
如果您无法从传感器获得干净的转换(正边缘和负边缘上的噪声,您需要使用计时器对信号进行一些去抖。
示例:
constexpr byte debounce_delay = 50; // ms, you may want to play with
// this value, smaller is better.
// but must be high enough to
// avoid issues on expected
// RPM range.
// 50 ms is on the high side.
byte debounce_timestamp; // byte is large enough for delays
// up to 255ms.
// ...
void loop()
{
// ...
byte now = (byte)millis();
if (now - debounce_timestamp >= debounce_delay)
{
debounce_timestamp = now;
rev += (int)positiveEdge(digitalRead(digitalPin), magStateOld);
}
// ...
}