for(){}
と micros()
関数を組み合わせることで、Arduino の動作速度の簡易的な測定が可能です。ただし、高速な処理の測定を行う場合、かなり不正確な値が得られることがあります。より正確な測定のために気をつける点と計測方法により結果の違いをまとめました。
簡易的な測定方法
最も簡単な測定方法は micros()
関数で測定対象の処理を挟んでやって、その差分から処理時間を求めます。ただし、16 MHz 動作の Arduino Uno の場合、micros()
関数は 4 us の分解能しかありませんので、複数回処理を行ってその合計の処理時間から 1 回当たりの処理時間を求めます。
unsigned long ts, te;
ts = micros();
for (int i; i=1000; i++) {
// 測定したい処理
}
te = micros();
Serial.println(te - ts); // ns
測定対象の処理がそれなりに時間がかかる場合(例えば 100 us 以上かかる analogRead()
とか)はこの方法で問題ありませんが、処理時間が短い場合(digitalWrite(13, HIGH)
の代わりに PORTB |= _BV(5)
を使う場合とか)は for(){}
部分にかかる時間を考慮する必要があります。
より正確な測定方法
より正確に測定対象部分のみにかかる時間を測定するためには、以下のようなコードを使います。
unsigned long ts1, te1, dt1;
unsigned long ts2, te2, dt2;
ts1 = micros();
for (int i; i=1000; i++) {
// 測定したい処理 1 回だけ
}
te1 = micros();
dt1 = te1 - ts1; // 1 回だけの処理時間 + for(){}
ts2 = micros();
for (int i; i=1000; i++) {
// 測定したい処理 1 回目
// 測定したい処理 2 回目
}
te2 = micros();
dt2 = te2 - ts2; // 2 回分の処理時間 + for(){}
Serial.println(dt2 - dt1); // 1 回分の処理時間
for(){}
の中で測定したい処理を一度だけ行う場合と 2 回行う場合で時間を計測し、その差分を取ります。
こうすることで for(){}
部分に必要な処理時間が相殺されますので、より正確に測定したい処理部分だけの時間が得られます。
測定例
いくつかの処理の測定結果です。使用ボードは Arduino Uno、Arduino IDEを使用しています。
コンパイルオプションは -Os で行いました。
analogRead()
dt1 = 112000 us
dt2 = 224004 us
dt2 - dt1 = 112004 us
analogRead()
1 回当たりの処理時間 112 us
digitalWrite()
dt1 = 3208 us
dt2 = 6164 us
dt2 - dt1 = 2956 us
digitalWrite()
1 回当たりの処理時間 2.956 us
PORTB |= _BV(5)
dt1 = 384 us
dt2 = 504 us
dt2 - dt1 = 120 us
PORTB |= _BV(5)
1 回当たりの処理時間 0.12 us (120 ns)
digitalWrite()
ぐらいなら大丈夫かなと思いましたが、digitalWrite()
でも 10 % ぐらいの差が出ました。予想していたよりも気を付けないといけないなという印象です。
より良い Arduino ライフを!