在这里,我们讨论如何使用millis()和micros()与他们的主要优势相比delay()。
与C / C ++中的变量溢出不是一个很好的类比,但是您知道了…
我们提到的一点需要注意这些功能,那就是millis()和micros()溢出后50天左右70分钟,分别。从上次对代码进行很小的改动就可以很容易地避免这个潜在的问题。
millis()贯穿本帖子的用法与可以互换micros()。
目录
简易修复
让我们看一下我们以前的文章中包含的简单非阻塞示例:
int period = 1000;
unsigned long time_now = 0;
void setup() {
Serial.begin(115200);
}
void loop() {
if(millis() > time_now + period){
time_now = millis();
Serial.println("Hello");
}
//Run other code
}
在大约50天后,当millis()我们从返回一个非常高的数字(接近(2 ^ 32)-1)到一个非常小的数字时,我们将得到一个溢出行为。这称为溢出或翻转。
现在,让我们看看如何解决此问题:
int period = 1000;
unsigned long time_now = 0;
void setup() {
Serial.begin(115200);
}
void loop() {
if(millis() - time_now > period){
time_now = millis();
Serial.println("Hello");
}
//Run other code
}
我们基本上只是移到time_now不等式运算符的另一端。为了使方程仍然有意义,我们必须更改变量的符号,因此要减去。您可以将持续时间与我们的period变量进行比较,而不是使用时间戳来查看。
稍安毋躁!
您可能想知道:“这怎么工作?” 这不是一个愚蠢的问题。这看起来很容易,因为我们只是在解决问题而不是解决问题。
从数学上看这没有多大意义,因为当millis()溢出发生时,左侧将变为负数(非常小的整数减去很大的整数的结果)。
起作用的原因
令人高兴的是,我们完全不必为此担心。由于计算的两个输入均为unsigned long数据类型,因此答案也将为unsigned long,因此结果将溢出,且返回值为millis()。记住两者millis()和micros()返回unsigned long:
这将打印2到串行监视器。Serial.print()在这种情况下,该功能不会以任何方式修改答案。
附加信息
为确保此方法可跨多个平台和体系结构使用,您可以将计算结果显式转换为正确的数据类型,如下所示:
int period = 1000;
unsigned long time_now = 0;
void setup() {
Serial.begin(115200);
}
void loop() {
if((unsigned long)(millis() - time_now) > period){
time_now = millis();
Serial.println("Hello");
}
//Run other code
}
不同的数据类型
在Arduino Uno(及想同类型产品)上,您必须在进行处理时显式强制转换计算uint8_t。否则,如果输入正确,则减法的结果将变为负数。
uint16_t和uint32_t(与unsigned long Arduino Uno和等效版本相同)具有不需要显式强制转换的行为。处理millis()或micros()时,除unsigned long(uint32_t)以外的其他数据类型均不相关。
摘要
如前所述,这是在处理millis()或时潜在问题的真正简单“解决方案” micros()(我们并没有真正解决问题,只是避免了它)。
如果您不确定数据类型和溢出,我们建议您尝试一下,看看在使用不同数据类型的不同边缘情况下会发生什么。确保打印功能不会以任何方式影响您的结果(有时会)。请记住,这种行为在不同的平台,编译器和/或体系结构上可能有所不同。