微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

全局变量不会在下一个循环之前更新

如何解决全局变量不会在下一个循环之前更新

我正在尝试用 C++ 为我的 ESP32 构建一个转速计。当我在条件之外取消注释 Serial.printf("outside rev: %d \n",rev); 时,它可以工作,但是当我对其进行注释时,我得到的值比它们应有的数量级大(没有 700 转,有 7 转)。我最好的猜测是打印语句减慢了 loop() 的速度,刚好足以让 incrementRevolutions() 在下一个循环之前将全局变量 passedMagnet 从真切换为假。这是有道理的,因为更新 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);

    // ...
}

它是可重用的,并且节省了堆栈空间和不必要的分配。

如果您无法从传感器获得清晰的转换(正边缘和负边缘上的噪声,您需要使用计时器对信号进行一些去抖动。

示例:

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);
    }

    // ...
}

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。