ELEGOO (Arduino)で始めるマイコン入門6:押しボタンスイッチと割り込み処理

 今回は前回のLED点灯を押しボタンスイッチで制御します。押しボタンスイッチは、ボタンを押すことであらかじめ決まっているピン同士が接続されます。今回は押しボタンスイッチを押すことで、GND(0V)に接続されたピンとマイコンボードと繋がっているピンを接続されるよう、回路を作りました。

IMG_20201129_104506 - コピー

ボタン検知プログラム(問題あり)

コードは以下です。

 #define  BLUE 3 #define  GREEN 5 #define  RED 6 #define  RIGHT 18 #define  LEFT 19

void setup()
{
 pinMode(RED, OUTPUT);
 pinMode(GREEN, OUTPUT);
 pinMode(BLUE, OUTPUT);  
 pinMode(13, OUTPUT);
 
 pinMode(RIGHT, INPUT_PULLUP);
 pinMode(LEFT, INPUT_PULLUP);
 digitalWrite(RED, HIGH);
 digitalWrite(GREEN, LOW);
 digitalWrite(BLUE, LOW);
}

int i, green, blue,delay_time;
int red = 255;

void loop() {
 green = 0;
 blue = 0;
 delay_time = 10;

 if ( digitalRead(RIGHT) == LOW ){
   for (i = 0; i < 255; i++){
     analogWrite (RED, red);
     analogWrite (GREEN, green);
     green++;
     red--;
     delay(delay_time);
   }
   for (i = 0; i < 255; i++){
     analogWrite (GREEN, green);
     analogWrite (BLUE, blue);
     blue++;
     green--;
     delay(delay_time);
   }
   red = 0;
   for (i = 0; i < 255; i++){
     analogWrite (RED, red);
     analogWrite (BLUE, blue);
     blue--;
     red++;
     delay(delay_time);
   }  
 }
 if ( digitalRead(LEFT) == LOW ){
   digitalWrite(13, HIGH);
 } else {
   digitalWrite(13, LOW);
 }
}

以前、pinMode関数の引数は3種類あると述べましたが、今回は3つ目のモードであるINPUT_PULLUPを使います。PULLUPとは、入力がないとき、HIGHを入力されているとみなす、という意味です。入力がされていないとき、普通は0Vが入力されているとみなします。ですが、この回路では”ボタンを押したときに、0Vが入力される”のです。このままでは、ボタンを押していないときも0V、押しても0V、となりボタンの意味がなくなります。そこで、PULLUPにより0Vの入力がないときはHIGHに保つことで、ボタンが押されたとき、ちゃんと0Vが入力された、とマイコンは判断できるようになります。このPULLUPは、一般的な回路ではPULLUP抵抗(プルアップ抵抗)という抵抗を電源電圧とプルアップしたい入力端子の間に入れて実現しています。

 さて、これで完成ではありません。上のプログラムを実行すると、右のボタンを押したら3色LEDが光り始めます。しかし、3色LEDが光っている間に左のボタンを押しても反応してくれません。これは、3色LEDを一通り光らせてからではないとボタンの入力が0かどうかを判断してくれないからです。この様子を動画で撮影したものが下です。この動画の前半では左右ボタンの確認、後半で、右のボタンを押して七色に光らせている最中に左のボタンを押してもボード上のLEDが光らないことを確認しています。

これを解決するには、一行ごとにボタンが押されたか判断すればよい、と思うかもしれません。ですが、一行ごとに判断する文を書くのはあまりに非効率ですし、プログラムが見にくくなってしまいます。また、一般的なシステムにおいて、入力の変化というものは非常に大事なプログラムの分岐点になることが多く、迅速に対応しなければなりません。

割り込みとは

 この煩雑さを解決してくれるのが割り込みです。その名の通り、今やっている作業に”割り込む”機能です。詳しい仕組みは省きますが、割り込みが起きるとシステムは現在の処理を一旦停止し、あらかじめ設定されている処理を始めます。この処理を割り込み処理と呼び、これが終わると先ほど中断した処理を再開します。図に表すとこんな感じです。

画像2


処理Aをしている最中に割り込みが発生すると、割り込み処理に移ります。その処理が終わると、処理Aが再開する、という流れです。

Arduinoでの割り込み処理

 ではArduinoではこの割り込み処理をどのように実現しているのでしょうか。Arduinoでは、割り込み処理を設定する関数が用意されています。それがattachInterrupt(interrupt, function, mode)です。interruptには割り込み番号、functionには割り込み処理を行う関数、modeは割り込みモードを指定します。順にみていきましょう。
 まず割り込み番号は、ピンと関連付けられた番号のことです。割り込みのきっかけをトリガーと呼びますが、トリガーとなる信号を入れることができるピンはボードごとに決まっています。Arduino mega 2560では、6つのピンしか割り込みのトリガーを入れられません。割り込み番号0に対応する入力ピンは2番、割り込み番号1は3番ピン、というようになっています。今回のコードでは、割り込み番号4番(対応するピンは19番)を使うため、interruptには4をいれます。
 次にfunctionです。これは割り込みが起きたときに実行したい関数を別で宣言、記述し、その関数名を入れるだけです。今回はleft_pushed関数を定義しました。
 最後にmodeです。modeは、LOW, HIGH, CHANGE, RISING, FALLINGの5種類があります。LOW, HIGHはそれぞれ、ピンの入力がLOW, HIGHのとき割り込みが発生します。これはレベル割り込み、レベルトリガーとも呼ばれ、LOWの場合、入力がLOWであり続ける限り割り込みが起き続けます。割り込み処理中に割り込みが起きることを多重割り込みと呼びますが、多重割り込みは避けなければならず、普通のマイコンでは禁止しています。つまり割り込み処理が終わるまで割り込みは入らず、割り込み処理が終わったら割り込みが発生する状態に戻るわけです。レベル割り込みの場合、割り込み処理中に入力が変化しなければ、割り込み処理が終わると同時に再び割り込み処理が始まるため、注意が必要です。
 CHANGEは、ピンの入力が変化したときに割り込みが発生し、
RISINGはピンの入力がLOWからHIGHに変わったとき、FALLINGはピンの入力がHIGHからLOWに変わったときに割り込みが発生します。信号の変化による割り込み検出を、エッジ割り込み、エッジトリガーと呼びます。こちらは変化点で一度割り込みが起こるだけなので、レベル割り込みとは異なり、永遠に割り込みが行われることがありません。エッジ割り込みは、通信の開始やセンサーの入力変化をとらえることができるため、非常に使い勝手が良いです。今回ボタンの入力をとらえるのも、エッジ割り込みを使います。

ボタン検知プログラム(割り込み付き)

割り込みを実装したコードを見てみましょう。先ほどのコードと共通点が多いため、変化点のみ記述します。

void setup()
{
 attachInterrupt(4, left_pushed, FALLING);
}

void left_pushed(){
 analogWrite(RED, 0);
 analogWrite(GREEN, 0);
 analogWrite(BLUE, 0);
 while ( digitalRead(LEFT) == LOW ){
   digitalWrite(13, HIGH);
  }
  digitalWrite(13, LOW);
}

割り込み番号は4(ピン番号は19)、割り込み処理関数はleft_pushed、割り込み検出はボタンを押すとHIGH ->LOWになることから、FALLINGを選択しました。このコードにより、3色LEDが点灯しているときに左のボタンを押すと3色LEDが消灯し、ボード内臓のLEDが点灯を開始します。左のボタンを離すと、内臓のLEDを消灯し、3色LEDを光らせる処理に戻ります。この時、3色LEDの色は左のボタンを押す前と全く同じ色から変化が開始することを確認することができます。実際に撮影したものが下です。今説明したことがちゃんと実現できていますね。

これで割り込み検出をするプログラムを書くことができました。

この記事が気に入ったらサポートをしてみませんか?