在我们用Arduino程序的时候会用到大量的延时,在这是通常都会使用delay()函数来做延迟,但是delay()含有有一个致命弱点,那就是会阻塞,如果延时的时间较短还没有多少影响,主要程序的执行效率要求不高倒也能接受,但是如果要求效率高的情况下delay()函数就不太适用了。这是外面可选的就必须时非阻塞的情况下还能达到延时效果,在Arduino可以使用定时器来实现延时,但是这样会额外的占用定时器,在资源紧张的情况下最好的方法接受使用millis()运行时间计数函数,这样尽量减少了额外的开销的同时还能达到延时的效果。通常使用millis()做延时的做法如下:
unsigned long previousMillis;
void setup() {
pinMode(D5_PIN, OUTPUT); // 将D5针脚配置为输出模式
}
void loop() {
outWater(); // 执行灌溉操作
}
void myDelay(unsigned long interval) {
unsigned long currentMillis=millis();
if(currentMillis-previousMillis>interval){
previousMillis=currentMillis;
//延时时间到,执行需要执行的任务
}
}
这个程序就是反复把当前值赋予给previousMillis。但是一旦millis()溢出归零,那么previousMillis是个很大的数字,
currentMillis-previousMillis>interval这句程序看似没什么问题,但是外面都知道,数字的大小是有限制的,一旦超过限制大小就会出现溢出,从这句代码看,好像也不会有太大影响,因为即使溢出,条件也会成立,因为外面申明的数据类型为无符号类型,所以条件都会成立,只是当溢出时,条件会提前满足,达不到精准延时的效果。
下面提出了另外的一种解决方法,我们都知道数字类型的大小是有边界的,那么当溢出后,计数器会从0 开始从新计数,那么这时候可用用数字最大边界值来减去历史时间戳,得到在溢出前一毫秒的持续时间长度,然后再加上从新计数的长度就得到了精确的延时时间。代码如下:
unsigned long previousMillis;
void setup() {
pinMode(D5_PIN, OUTPUT); // 将D5针脚配置为输出模式
}
void loop() {
outWater(); // 执行灌溉操作
}
void myDelay(unsigned long interval) {
unsigned long currentMillis=millis();
unsigned long elapsed;
if(currentMillis<previousMillis){
elapsed=((unsigned long)-1)-previousMillis+currentMillis;
}else{
elapsed=currentMillis-previousMillis;
}
if (elapsed >= interval) { // 比较持续时间
previousMillis=currentMillis;
//延时时间到,执行需要执行的任务
}
}