我需要检测unsigned long
的溢出。
此变量保存自设备运行以来的毫秒数(它是Arduino)。做sizeof(unsigned long)
,我发现它确实是一个32位的数字。现在,因为它每毫秒递增一次,这意味着设备将在此值溢出之前运行大约49天。
由于它适用于家庭系统,因此不太可取。现在我正在使用的数字是,比较当前时间是否大于前一次加上去抖动量。
if(timeChanged + amountOfMs < currentTime){ ... }
毋庸置疑,一旦发生溢出,这就不再适用了。什么是解决这个问题的有效方法?我已经考虑过还有一个二次计时器来检查是否有一个溢出的毫秒,但最后我会遇到同样的问题。
答案 0 :(得分:2)
似乎你已经得到了两个非常糟糕的答案......
正确的答案是,只要您正确进行计算,就不必担心millis()翻转。
这很糟糕:
if (timeChanged + amountOfMs < currentTime) { ... }
这很好(翻滚安全):
if (currentTime - timeChanged > amountOfMs) { ... }
它起作用的原因是具有无符号整数的算术(在你的情况下为unsigned long)可靠地以模数max + 1工作(ULONG_MAX+1
是2 ^ 32)。因此,currentTime
,timeChanged
及其差异始终具有正确的值,模2 ^ 32。只要您每49天测试一次按钮的频率超过一次(很可能),差异将在unsigned long
的范围内,您的测试将是正确的。
换句话说:如果millis()在timeChanged
和currentTime
之间滚动,则差异currentTime - timeChanged
将为负数。但由于差异实际上是用无符号数计算的,因此它会下溢并翻转到正确的结果。我不喜欢这个解释,因为它听起来像是一个补偿另一个错误的错误。事实是:如果你在模块化算术中考虑无符号数,那么任何地方都没有错误。
答案 1 :(得分:-1)
这是一个常见的错误(也是我自己创造的一个错误),Arduino游乐场有一个很好,彻底,正确的答案。见https://playground.arduino.cc/Code/TimingRollover
答案 2 :(得分:-3)
您可以创建一个新的if循环来检查条件:if(currentTime == 0xFFFFFFFE)
如果这是条件,则下一毫秒将溢出您的变量。所以在这一点上你可以手动将它重置为零并转到从零开始的循环。
这可能会或可能不会对您的情况有所帮助。我无法肯定地说,因为您还没有分享有关您的代码的任何进一步细节。
答案 3 :(得分:-3)
定义两个变量,我将把它们称为'now'和'lastNow'。
unsigned long now;
unsigned long lastNow = 0;
在循环中,您现在可以执行此操作:
now = millis();
if (now < lastNow) {
// rollover!
}
lastNow = now;
无论您多久(或不经常)循环,都很好而且可靠。