Arduino と外部信号の入力

プログラムを作っていると、外部信号を使ってボードを制御したいことがあります。

防犯システムで、センサーが何か物体を捉えたとき、照明を点けたいときなど、こんな場合は、どうしますか?


特別なしかけのないプログラムでは、センサーの信号が入ったかどうかを、めんどうでも定期的に調べることが必要です。

たとえば、一定時間ごとにその信号がないかどうかをみる方法が考えられます。この方法をポーリング法(polling method)と言います。

その一定時間は、たとえば 1秒ごとか、またはもっと短い時間にする必要があるかもしれません。

いずれにしても、この方法はうまいやり方ではありません。時間を指定しなければならず、細かいことをいうとシステムのリソースを浪費する欠点もあります。


そこでもっと別のうまい方法があります。

割り込み (Interrupt) を使うものです。

割り込みは、マイクロ・コントローラが備えるハードウェアの機能です。この方法は、めんどうなタイミングの問題を解消できます。


Arduino ボードの多くは二つの外部割り込みを使えます。具体的には2本のピンという意味で、ディジタルI/Oピン2とピン3です。

プログラムでは attachInterrupt() 命令を使います。この命令は指定するピンの状態がどう変わるのかを検出することができます。

  attachInterrupt(0, detectObject, RISING)

この例は、センサーが信号を検出すると detectObject() 関数を呼び出します。応答するまでの最小時間は、たとえば Arduino Unoでは5クロックです。この事は Unoに搭載されるチップのデータシートに書いてあります。Arduino Uno のクロック周波数は 16MHzですから 1/16MHz x 5 =62.5n x5=312n秒かかります。

多くの場合は、この程度の遅れ時間は無視できます。
また、Arduino Due などはさらに早いはずです。

実際に、トリガー信号を検出して大パワーのLED光源が発光するフラッシュ装置を製作した経験では、遅れ時間はまったく問題になりません。

カッコのなかの最初の数字は、割り込みの番号で 0または1のどちらかです。3番目は、信号の立ち上がりか下がりのどちらかを、その信号に応じて指定します。

呼び出した関数の中には照明を点灯する命令を、次のように書いておきます。

  void detectObject() {
    digitalWrite (LED_Light, ON);
  }
  
ちなみに、void は関数の戻り値を使わないという意味です。もっとエレガントなプログラム言語なら「関数」ではなく「手続き」を使えばこんなことは必要ありませんが。

注意点

attachInterrupt()が呼び出す関数の内容は、上記の例では detectObject()関数ですが、いくつかの注意が必要です。

・できるだけ短くして簡潔にまとめる
・delay()命令などは使えない
・main()関数と共有する変数はvolatileをつけて宣言する

などが主な注意点ですが、まだ他にもあります。