Arduinoで遊ぶページ

Arduinoで遊んだ結果を残すページです。
garretlab
millis()のオーバーフローの実験

概要

Arduinoのmillis()がオーバーフローしたときの挙動に関する実験です。Arduino UnoとESP-WROOM-32について試してみました。

Arduinoのmillis()は、プログラムを起動してから経過した時間をミリ秒単位で返す関数ですが、32ビットの整数型なので、約49日でオーバーフローします。実際にオーバーフローしたらどうなるのかを確認してみました。

と言っても、実際に約49日動かし続けたわけではなく、unsigned longの変数の最大値付近の動作を軽く試してみただけです。

結論としては、他の数値との差分をとり、一定時間経過したことを調べるだけなら、何も考えなくてもOK、です。

実験

スケッチ

以下のスケッチを、Arduino UnoとESP-WROOM-32で動かしてみました。timerというunsigned longの変数に、4294967290を代入し、prevというunsigned longの変数に代入した4294967285を引いた結果を、diffというunsigned longの変数に代入して、それぞれの値を10進数と2進数で表示するものです。

void setup() {
  unsigned long timer;
  unsigned long prev;
  unsigned long diff;

  // put your setup code here, to run once:
  Serial.begin(115200);
  timer = 4294967290;
  prev = 4294967285;

  for (int i = 0; i < 10; i++, timer++) {
    diff = timer - prev;
    Serial.print("timer = ");
    Serial.print(timer);
    Serial.print(", prev = ");
    Serial.print(prev);
    Serial.print(", timer - prev = ");
    Serial.print(diff);
    Serial.print("\n");
  }

  Serial.print("\n");

  timer = 4294967290;
  for (int i = 0; i < 10; i++, timer++) {
    diff = timer - prev;
    Serial.print("timer = ");
    Serial.print(timer, BIN);
    Serial.print(", prev = ");
    Serial.print(prev, BIN);
    Serial.print(", timer - prev = ");
    Serial.print(diff, BIN);
    Serial.print("\n");
  }
}

void loop() {
  // put your main code here, to run repeatedly:

}

結果

Arduino UnoとESP-WROOM-32で試した結果を、以下に示します。COM3がUnoで、COM4がESP-Wrrom-32です。

Arduino UnoでもESP-WROOM-32でも、同じ結果となりました。

  • timerは、4294967295になった後、0に戻る。
  • prevは、timerが0に戻った後も、単調に増加している。

このため、例えば、ある時点でのmillis()の値を保存しておき、その後、現在のmillis()の値を引いて、時間の差分を取得する処理では、オーバーフローを考えなくてもOKです。もちろん、約49日以上待つことはできませんが。

とはいえ、unsignedの引き算はいろいろ考えることがあり、難しいですね。

バージョン

Arduino 1.8.4/Arduino Uno/Arduino core for the ESP32/ESP-WROOM-32



メニューを表示するためにJavaScriptを有効にしてください。

Arduinoで遊ぶページ
Copyright © 2017 garretlab all rights reserved.
inserted by FC2 system