2017年6月7日 星期三

[Arduino] millis() 使用注意事項

最近在在Arduino上每隔五分鐘要用MQTT傳一次資料給SERVER,所以

millis() 這個函式來取得arduino執行程式到目前過了幾個milliseconds 

但這個值是用unsign long (32bit) 儲存的,所以大概在約50天左右就會overflow,

從0開始,但是如果程式寫法是如下,那就好笑了。


unsigned long start=millis();
int delaytime=3000;
void loop() {
  

while (millis()<start+delaytime)
{
    ;
}
sendData();

}


當五十天後,你就永遠不會傳送資料了,因為millis()可能會遠小於sendtime。等到大於sendtime時,差不多又overflow了。

但是以下的寫法是不會有問題的


unsigned long start=millis();
unsigned long delay=3000;
if (millis()-start>delay)
{
    sendData();
    start=millis();
}

我們先來了解一下unsigned long 到底可以放的下什麼

0 to 4,294,967,295 (2^32 - 1)


那如果overflow 後會發生什麼事

unsigned long number=4294967295;  
void setup() {
  // put your setup code here, to run once:
Serial.begin(9600);


  Serial.println("number is :"+String(number));
  number+=1;
  Serial.println("number+1 is :"+String(number));
}


輸出結果如下,當大於2^32 -1 後,就會歸零。

number is :4294967295
number is :0

我們來模擬一下overflow之後的運算


unsigned long number=4294967295; 
unsigned long testNumber=4294967295; 
void setup() {
  // put your setup code here, to run once:
Serial.begin(9600);


  Serial.println("number is :"+String(number));
  number+=1;
  Serial.println("number+1 is :"+String(number));
  Serial.println("number- 2^32-1 :"+String(number-testNumber));

}

number is :4294967295
number+1 is :0
number- 2^32-1 :1

所以0-(2^32-1) 會是1  ,

以此類推,當overflow後,即使millis()比較小,相滅之後仍然會是正值。

number is :4294967295
number+10000 is :9999
number- 2^32-1 :10000

我們來測試一下,若是millis()比較小時做相減會怎樣

number is :0
number+10000 is :10000
number- 2^32-1 :10001

所以2數運算時要考慮到unsigned long 能裝的下的空間,unsigned long 面對運算結果負值也會出現問題。

number is :0
number+10000 is :10000
number-10001 :4294967295



參考資料:

millis() 溢出(overflow)歸零(rollover)有沒問題?(教程)定时器相關http://www.arduino.cn/thread-12506-1-1.html

沒有留言:

張貼留言