1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

カウントアップのオーバーフロー対策

Last updated at Posted at 2024-06-14

SS 192.png カウンタが時計の針のように循環してほしい

やること

Arduino系でタイマーなどをカウントアップする際に、最大値を超えるところの処理がちょっと面倒な感じになります。
変数の型の性質を利用して、処理手順を減らしたいと思います。

たとえば1-11=2という計算は間違っているような感じもしますが、
時計盤の上では11時と1時の差が2時間ということは明白です。
(いや10時間とか14時間とかもありえるだろうという指摘はごもっともですが、一旦無視してください。)

具体的には、タイマー割り込みで刻々とカウントアップされる値があるとして、別途並列で計算処理してカウントアップをしている値と比較する時に使いたいと考えています。
カウントの値が循環してくれれば、型の最大値を跨いでも理屈上は永久に動いてくれるはずです。

unsigned long を使おう

時刻を取得するコマンドである millis() や micros()はunsigned longの型で返されます。そこでこのunsigned longをカウンタに使おうと思います。

unsigned longは32ビットの符号無し整数型なので、ミリ秒を取得するmillis()の場合、値の最大値は4294967295となります。4294967295ミリ秒は約49日です。
もう少し実機でよく調べると、4294967295の最大値に対し、1を足すと0に戻ることがわかります。

引き算もエラーなく行うことができます。
たとえば、

1-2 = 4294967295
1-1 = 0

となります。

実験コード

2つの変数を最大値付近からカウントアップし、毎回、差を求めてみます。

arduino

unsigned long a = 4294967191;
unsigned long b = 4294967190;

void setup()
{
  Serial.begin(115200);
}

void loop()
{
  Serial.print("a=");
  Serial.print(a);
  Serial.print(", b=");
  Serial.print(b);
  Serial.print(", a-b=");
  Serial.println((a - b),DEC);
  a++;
  b++;
  delay(100);
}

実行結果

...
a=4294967292, b=4294967291, a-b=1
a=4294967293, b=4294967292, a-b=1
a=4294967294, b=4294967293, a-b=1
a=4294967295, b=4294967294, a-b=1
a=0, b=4294967295, a-b=1
a=1, b=0, a-b=1
a=2, b=1, a-b=1
a=3, b=2, a-b=1
a=4, b=3, a-b=1
...

最大値を跨いでも差分を保ってくれる時計盤のようなカウンタを実現できることがわかりました。

まとめ

49日分もあればそもそもオーバーフローすることもないだろうとタカを括っていたのですが、ロボットの展示でマイクロ秒を使った際、何十分か経つとオーバーフローでシステムが停止するというトラブルに見舞われました。そんなうっかりがありました。

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?