PR

Arduinoの割り込みの使い方を徹底解説!これで使い方をマスター

mastering-arduino-interrupt-processing-eyecatch

 今回も前回の記事から引き続き、Arduinoの割り込み処理について解説してきます。
前回の記事で割り込み処理についてのイメージと、
使い道や、どんな時に使うべきかを解説しました。
もしまだご覧いただいていない場合は、
こちらにリンクをご用意しましたのでぜひご覧ください。

 今回の記事では、Arduinoの割り込み処理の
実際の使い方について徹底解説します。

 具体的には、Arduinoの種類と対応する割り込み処理のハード的な対応関係、
コードの書き方、割り込み処理の種類についてを解説します。

 Arduinoの割り込み処理は、
一見すると理解するのが難しいですが、
ポイントを押さえれば「そんなもんか…」ときっとなります。

 実際わたしもArduinoを始めてすぐの時は、
割り込み処理を敬遠して、割り込み処理をせずに
何とか済ませられないか?とやっていました。

 ただ、少し割り込み処理を触ってみたら
案外難しくないことが分かったので、
この記事を読んでいるあなたにもぜひマスターしてもらいたいです!

この記事を読むことでわかること

Arduinoの割り込み処理についてマスターできる

自己紹介

サラリーマンしてます。

主に工場(生産現場)で使用する検査装置のアプリケーション開発してます。

ヒトの作業を自動化して簡略化するアプリケーションを日々開発中。

2022年5月に転職。現在は超大手企業の新規事業分野で装置の研究・開発をしています。

Youtubeチャンネルにさまざまな動画を上げています

↓↓↓こちらからYoutubeチャンネルにアクセス!! ↓↓↓

注意

本ブログはアフィリエイトを用いた広告を掲載しています。

Arduinoの割り込み処理の制限:ハード編

 まずは、Arduinoと割り込み処理の関係について解説します。
Arduinoにバリエーションがいくつもあるのはご存知でしょうか?

 たとえば、こちらはArduino UNOのR3の互換機です。
一般的にArduinoというとUNOが出てくることが多いです。

ArduinoUNO

 他にも、こんなコンパクトなArudinoもあります。

Arduino_NanoAndEvery-94

 左側がArduino Nano Every。右側がArduino Nanoです。

 では、Arduinoと割り込み処理の関係とはなんなのか?
実は、Arduinoの種類によって、
割り込み処理のトリガーにできるピンが変わるんです…

Arduinoは、種類によって若干扱いが変わる。

 まずはこちらの表をご覧ください↓↓

Arduinoの種類割り込み処理のトリガーにできるピン番号NOTES
Uno Rev3, Nano, Mini, other 328-based2, 3
UNO R4 Minima, UNO R4 WiFi2, 3
Uno WiFi Rev2, Nano EveryAll digital pins
Mega, Mega2560, MegaADK2, 3, 18, 19, 20, 21(pins 20 & 21 are not available to use for interrupts while they are used for I2C communication; they also have external pull-ups that cannot be disabled)
Micro, Leonardo0, 1, 2, 3, 7
Zero0-3, 5-13, A0-A5Pin 4 cannot be used as an interrupt.
MKR Family boards0, 1, 4, 5, 6, 7, 8, 9, A1, A2
Nano 33 IoT2, 3, 9, 10, 11, 13, A1, A5, A7
Nano 33 BLE, Nano 33 BLE Sense (rev 1 & 2)all pins
Nano RP2040 Connect0-13, A0-A5
Nano ESP32all pins
GIGA R1 WiFiall pins
Dueall digital pins
101all digital pins(Only pins 2, 5, 7, 8, 10, 11, 12, 13 work with CHANGE))
https://www.arduino.cc/reference/en/language/functions/external-interrupts/attachinterrupt/

 この表は、Arduinoの公式ページから引用したものです。
こちらをご覧いただくと、Arduino UNO R3は、表の一番上にあります。
そちらを見てみると、
ピン番号2,3が割り込みのトリガーにできることがわかります。

 そもそも割り込みのトリガーにできるとは?
割り込み処理には、トリガーとなるきっかけが必要になります。
具体的には、スイッチでもセンサーでもなんでもいいです。
そのきっかけをArduinoのどこに接続するかが重要です。

 イメージとしては、Arduinoの空いているpinに接続
するだけでいいように思いますが、
実はArduinoの機種によって使えるところが決まっているよ。
という話です。

全ピンが割り込みに対応しているArduinoもある。

 先ほど紹介したArduino Nano Everyだと、
全てのdigitalピンがトリガーにできると記載がありますから、
割り込み処理だけで考えると、
Arduino UNOよりもArduino Nano Everyの方が
自由度が上であることがわかりますね。

 Arduino Nano Everyは、すべてのdigitalピンが
割り込みのトリガーとして使えますが、
中には、すべてのpinが割り込みのトリガーにできるものもあります。

 例えば、Arduino Nano33 BLEなどですね。
こちらは比較的新しいArduinoです。
特徴としては、DC5Vではなく、DC3.3Vで駆動するArduinoですね。
BLEとあるように、BluetoothLowEnergyに対応していますので、
無線が使える機種です。

割り込み処理のコードの書き方

 では、Arduinoのどの機種がどのピンで
トリガーが入れられるかわかったところで、
次に実際にコードを書いてみましょう。

 今回は、Arduino UNO R3をターゲットとして
割り込みの処理を書いてみましょう。

割り込み処理の基本的なコードの構成

 割り込みの処理の基本的なコードの構成は、
次の2つがポイントになります。

割り込み処理の基本的な構成
  • 割り込みが発動した時の処理の関数を作る。
  • setup関数の中で割り込みのトリガーを宣言する。

 慣れてきたら逆の順番で書いていってもいいのですが、
今回読んでくれているあなたは、必ずしもプログラミングが得意とは限らないので、
この順番で解説していきます。

割り込みが発動した時の処理の関数を作る。

 まずは、割り込みが発動した時に、何をしたいか決める必要があります。
例えば、モーターの制御で、割り込みされるトリガーが入るのが、
ここまで入ってきたら危険だというセンサーだったとしましょう。

 この場合は、危険なところに来たと割り込みで検知しているわけですから、
モーターを停止するというのが最重要ですよね。
ですから、モーターを動かす指令を止めるのが、
割り込みが発動した時の処理になります。

 関数の作り方ですが、
setupやloop関数と同じように書いてあげれば大丈夫です。

void setup() {
  // put your setup code here, to run once:

}
void interruptDo(){
  // ここが割り込みのトリガーが発動したら実行されるところ。
}
void loop() {
  // put your main code here, to run repeatedly:

}

 今回は、interruptDoという名前にしていますが、
好きな名前でOKです。ただし、setupやloopなど、
すでにArduino側で先に定義している関数名については重複になるので使えません。
ただ、それ以外であれば問題なく使えます。

setup関数の中で割り込みのトリガーを宣言する。

 さて、次に割り込みが発生した場合に実際に実行される関数を、
割り込みのトリガーと紐づけましょう。

 さきほどのinterruptDo()という関数は、
あくまでも、ただ関数を作っただけで、
割り込みのトリガーとの紐付けがされていませんから、
極端に言ってしまうと、この関数があってもなくても
実行結果は何も変わりません。

 では、トリガーとの紐付けについて解説しましょう。
今回はArduino UNO R3をターゲットとしていますから、
先ほどの割り込み処理のトリガーとできるのは2番ピンと3番ピンでしたね。

 具体的にsetup関数の中身は、このようにします。

void setup() {
  // put your setup code here, to run once:
  pinMode(ledPin, OUTPUT);// LEDは出力なのでOUTPUTに設定。
  pinMode(interruptPin, INPUT_PULLUP);// ここでトリガーのピンを入力ピンに設定。
 // ここで割り込みする条件と、割り込みした場合の関数を設定。
  attachInterrupt(digitalPinToInterrupt(interruptPin), interruptDo, FALLING);
}

 この書き方だと、
digitalPinの2番ピンがFalling=GNDに落ちると、
割り込み処理に入る。という流れになります。

 次の章で、完成形のプログラムも配線も含めて
実験環境についてご紹介しますのでそこでマスターしてください。

Arduinoの割り込み処理の種類は4つ存在する。

 念の為ここで少し小ネタを紹介しておきます。
Arduinoの割り込み処理ですが、
4つほど種類が存在します。それぞれについて知っておいた方が良いです。

名前内容
LOWトリガー用のピンがLOWに落ちていたら割り込みが発動。
CHANGEトリガー用のピンがHIGH→LOWまたはLOW→HIGHで割り込みが発動。
FALLINGトリガー用のピンがHIGH→LOWに変化すると割り込みが発動。
RISINGトリガー用のピンがLOW→HIGHに変化すると割り込みが発動。
Arduinoの割り込みが発動する4種類。

割り込み処理を手軽に体験する方法

 それでは、ここで具体例として、
Arduino UNO R3を使って、配線方法から
プログラムの書き方までご説明します。

 こちらで動作確認はしていますから、
全く同じようにやってもらえれば必ずうまくいきます。

Arduinoも含めた今回使用したもの

 それでは今回使用したものをご紹介します。

名称説明Amazonのリンク
Arduino UNOArduino本体です。R3でもR4でもできます。ここから飛べます
配線の小物ブレッドボードや、ジャンパーワイヤーです。ここから飛べます
モーメンタリスイッチ押している間だけ通電するスイッチです。ここから飛べます
Arduinoの割り込み処理を試してみるのに必要な道具

 説明でも書いていますが、
Arduino UNOはR3でもR4でもどちらでも全く同じです。
ピン配置も一緒ですし、割り込みできるピン番号も同じで互換性があります。

 今回割り込みが動作しているか確認するために、
LEDをチカチカしますが、Arduinoのボード上にあらかじめ
搭載されているLEDを使いますので、特に別にLEDを用意する必要はありません。

 また、スイッチを使いますが、
ソフト上でpullupしますので、GNDに落とすために抵抗を用意する必要もありません。

配線関係

 道具を準備したところで、
配線しましょう。こちらのように配線してみてください。
シンプルで簡単ですね。

Arduinoの割り込み処理を実験するための配線。

 もしスイッチを1回しか押していないのに、
複数回押したような反応が出る場合があります。
この現象はチャタリングと呼ばれる現象です。

 人間としては1回スイッチを押したと思っていても、
微小な電圧の変化が短時間に起こって
Arduino側が何回もスイッチを押したと認識する現象です。

 この場合、コンデンサを間に挟むと改善したりしますが、
今回の件とは少しズレるので、また今度ご紹介します。

使用したコード(プログラミング)

 それでは、割り込みを使うためのソースコードを
こちらにご紹介します。

const int ledPin = 13;// ボード上のLEDを指定。
const int interruptPin = 2;// 割り込みのトリガーを2番ピンに設定。
volatile byte state;
void setup() {
  // put your setup code here, to run once:
  state = LOW;// ONとOFFをトグル変換するための箱。

  pinMode(ledPin, OUTPUT);// LEDは出力なのでOUTPUTに設定。
  pinMode(interruptPin, INPUT_PULLUP);// ここでトリガーのピンを入力ピンに設定。
 // ここで割り込みする条件と、割り込みした場合の関数を設定。
  attachInterrupt(digitalPinToInterrupt(interruptPin), interruptDo, FALLING);
}
void interruptDo(){
  // ここが割り込みのトリガーが発動したら実行されるところ。
  if(state == LOW){
    state = HIGH;
  }
  else
  {
    state = LOW;
  }  
}
void loop() {
  // put your main code here, to run repeatedly:
  digitalWrite(ledPin,state);
}

 ちょっと注意する点がいくつかあるので、
その解説をしておきます。

const int ledPin = 13;// ボード上のLEDを指定。
const int interruptPin = 2;// 割り込みのトリガーを2番ピンに設定。
volatile byte state;

 まず、volatile byte state;とありますが、
volatileとは、割り込み処理とセットと考えてください。

 このvolatileは、割り込み処理の中でも使える特殊な変数だと思ってください。
普通の変数だと、割り込み処理の中で参照できません。

 今回だと、stateという名前で状態変数のように使っています。
これは、割り込み処理が実行されたら値を変更する前提ですから、
volatileを頭につけておく必要があるということですね。

// ここで割り込みする条件と、割り込みした場合の関数を設定。
  attachInterrupt(digitalPinToInterrupt(interruptPin), interruptDo, FALLING);

 次にこの行ですが、
こちらの中で引っかかりそうな内容としては、
digitalPinToInterrupt(interruptPin)という引数ではないでしょうか?

 じつはこれは、Arduino上のピン番号と、
マイコンの割り込みのピン番号との紐付けをしています。

 Arduinoの種類によって、搭載されているマイコンが異なる場合があります。
そんな時でも同じソースコードでも動くように。という思想があります。
その思想としてこのような変換があるようです。

 今回だと、interruptPin=2ですが、
内部では変換されてINT.0となっています。

Arduino.orgより引用。

 注意としては、ATmega32U4だと、INT.0とINT.1の順番と
ピンの番号がUNOと逆になっているところでしょうか。
ただ、配線を逆にしたところで、内部で勝手に変換してくれるので
こちらとして気を付ける必要はありません。

今回のまとめ:割り込み処理はポイントを押さえれば怖くない!

 今回はArduinoの割り込み処理について解説しました。
以前の記事でイメージを掴んで、
今回は実際の使い方を配線・プログラミングを使ってご紹介しました。

 ここまで読んでいただいて、
実際に手を動かしてみると意外と難しくないですよね?

 もちろん初めての場合は、一行一行の意味がわからなくて
時間がかかるかと思います。
ただ、ある程度わかってくると、他のプログラムをやろうとしたときに、
あ。これ割り込み処理の時にやったな!となる日がいつか来ます。

 次回は、さらに踏み込んで、
ただ割り込みをしてLEDをつけるのではなく、
実践で起こりうる課題について解決する方法をご説明していこうと思います。

コメント

  1. 初心者 より:

    コメント失礼致します。
    アルディーノ初心者で直動ステージを使用したモノを製作中です。
    割り込み処理を発動後は、ループの途中から再開ではなく、
    ループを最初からやり直す事は可能でしょうか?

    • hobbyhappy hobbyhappy より:

      コメントありがとうございます!
      割り込み処理発動後は確かにループの途中から再開します。
      もしもループの最初に戻すのであれば、フラグを用意しておき、割り込み処理に入ったらフラグをたてる(1にする)します。
      ループの各所でそのフラグを確認して、もしフラグが1になっていたらそのあとの処理をしないようにすれば実現可能です。
      ただし、ループのどこでそのフラグを確認するのか?という問題が発生します。1行ごとに確認するのはちょっと現実的ではないかもしれませんが、
      もしそこまで複雑なスケッチでないなら、そういったやり方でループの最初から始めるのもいいかもしれません。

タイトルとURLをコピーしました