ArduinoでSTEM教育​ 応用編:割り込みタイマーで時間を計測する

ArduinoでSTEM教育​ 応用編:割り込みタイマーで時間を計測する

時間を操作するときにdelay関数をよく使いますが、これを使うとdelayで指定した時間が経過するまで、プログラムが止まってしまいます。メインのプログラムは動かし続けた状態で、 時間を計測したい場合は、割り込みタイマーを使うと良いです。

目次

Timerの種類

Arduino Unoは、AVR ATmega328Pというマイコンを搭載しており、このマイコンにはTimer0, Timer1, Timer2の3つのタイマーがあります。このタイマーを利用して、時間を計測することが出来ます。ただし、使用する際には注意が必要です。各タイマーは、PWM波形を出力するために使用したり、delay関数などに使用します。各タイマーの割当を以下に記載します。

bit数対応ピン対応関数
Timer08bit5pin, 6pin (PWM)delay, millisなど
Timer116bit9pin, 10pin (PWM)(Servoライブラリ)
Timer28bit3pin, 11pin (PWM)tone

Timer0はdelay関数で使うので、これを使用できる機会はなかなか無いと思います。よく使われるのはTimer2です。今回はTimer2を使用したプログラムを書きます。

MsTimer2

Timerのライブラリはいくつかありますが、ここでは「MsTimer2」を紹介します。MsTimer2は、Arduino-IDEの[ツール]->[ライブラリを管理]からインストールできます。下記のウィンドウが開いたら、検索ボックスにmstimer2と入力すれば、下記のように表示されると思いますので、クリックしてインストールして下さい。

MsTimer2のインストール

使い方は非常に簡単です。

①MsTimer2::set(unsigned long ms, void (*f)())
 第一引数にタイマーの時間をミリ秒単位で入力します。第二引数は、タイマーの時間が経過したとき(割り込み)に呼び出す関数です。

②MsTimer2::start()
 タイマーによる割り込みを有効にします。

③MsTimer2::stop()
 タイマーによる割り込みを無効にします。

FlexiTimer2

FlexiTimer2は、マイクロ秒単位のタイマーを使いたい場合に使用します。

FlexiTimer2::set(unsigned long units, double resolution, void (*f)());

第一引数は時間を入力し、第ニ引数は分解能を入力します。例えば、 FlexiTimer2::set(1, 1/100000, INT)の場合、100us毎にINT関数を呼び出します。使用する場合には精度に注意が必要です。精度が出るのは40us~1000usの間だけで、それよりも短い領域や長い領域では誤差が大きという報告があります。短い領域については、マイコンのクロック周期に近づくので厳しいのはわかりますが、1000us以上で誤差が大きいのは意外でした。1000us以上の場合は、MsTimer2を使用したほうが良さそうです。

プログラム

サンプルプログラムは、1ms毎にtimerFire関数を呼び出して、timeCountをカウントアップします。timeCountは1000でクリアされます。これは、メインのloop関数とは別で動作を続けます。loop関数内では、シリアルプロッタ用にSerial.printを常時実行します。timeCountが500~600のときだけ、flagIntを100にセットします。

//www.stemship.com
//2020.1.19
#include <MsTimer2.h>
unsigned int timeCount = 0;

void setup() {
  Serial.begin(9600);

  //1ms毎にtimerFire関数を呼び出す
  MsTimer2::set(1, timerFire);

  //タイマー開始
  MsTimer2::start();
}

void loop() {
  unsigned int flagInt = 0;

  if(timeCount>=500 && timeCount<600) {
    //タイマカウントが500~600の間だけフラグを立てる
    flagInt = 100;
  }
  
  Serial.print(timeCount);
  Serial.print(",");
  Serial.print(flagInt);
  Serial.println();
}

void timerFire() {
  if(timeCount >= 1000){
    //タイマーをゼロカウントに戻す
    timeCount = 0;
  }
  else {
    //1ms毎にタイマーをカウントアップ
    timeCount++;
  }
}

上記のプログラムを実行して、シリアルプロッタ画面を開くと以下のようなグラフが表示されます。今回は画面で出力確認を行いましたが、flagIntを出力ポートに割り当てて、LEDを点灯させたり、音を鳴らしたりする応用ができます。

実行時のシリアルプロッタ画面

Arduino応用編カテゴリの最新記事