複数入力を処理する(Arduino詳解)

詳しく解説!!Arduino-その9です。前回の記事はこちらです。

hirocom777.hatenadiary.org

複数のボタン入力に対応する

前回はチャタリング対策を関数化してスケッチをシンプルにまとめてみました。 でも、ボタン入力は必ず一つだけということはないですよね。複数のボタンを処理する時はどうするのでしょうか?ボタンの数だけ関数を用意するのは、スマートな方法ではありません。そこで、今回は複数のボタン入力にチャタリング対策を施せるように、関数を改善していきたいと思います 。

準備

 ハードウェアですが、ベースモジュールのD2,D3.D4のコネクタにそれぞれボタンモジュールを接続します。D2,D3.D4と表示されているコネクタに繋げてください。 今回、LEDモジュールは使いません。

f:id:HiroCom777:20200327203719j:plain
そして、今回用意したスケッチは以下になります。

void setup() {
  pinMode(2, INPUT);
  pinMode(3, INPUT);
  pinMode(4, INPUT);
  Serial.begin(9600);
}

void loop() {
  int key = keyCheck(50);
  if (key != 0) {
    Serial.print("No ");
    Serial.print(key);
    Serial.println(" ON!");
  }
}

int buttonCount = 3;
int pinNumber[] = {2,3,4};
int buttonState[] = {0,0,0};
unsigned long lastTime[] = {0,0,0};

int keyCheck(int waitTime) {
  for (int i = 0 ; i  <= buttonCount - 1 ; i++ ) {
    if (digitalRead(pinNumber[i]) == LOW) {
      buttonState[i] = 0;
      lastTime[i] = 0;
    } else { //digitalRead(pinNumber[i]) == HIGH
      if (lastTime[i] == 0) {
        lastTime[i] = millis();
      } else {//lastTime[i] != 0
        if (buttonState[i] == 0 && (millis() - lastTime[i]) > waitTime) {
          buttonState[i] = 1;
          return (pinNumber[i]);
        }
      }
    }
  }
  return (0);
}

動かしてみる

早速書き込んで動かしてみましょう 。書き込みが完了したら、起動しているArduinoIDEのメニューから ツール→シリアルモニターと選択してください。以下のような画面が立ち上がると思います 。

f:id:HiroCom777:20200504191100j:plain
右下に数字とbps と書かれている欄があると思いますが、ここは9600 bps と選択してください。
f:id:HiroCom777:20200504191208j:plain
この状態でボタンモジュールを押してみてください。 シリアルモニターに以下のように表示が出ると思います。
f:id:HiroCom777:20200504191655j:plain
Arduino Unoが押されたボタンモジュールの番号をシリアルモニターに返信しているんですね。

スケッチの解説

 さて、setupなんですが、ボタンモジュールにつながったピンは入力に設定するというのは分かるのですがその後のSerial.begin(9600);というのこれ一体何なんでしょう?あと、loopの中にもSerial.print()とか、Serial.println()とかありますね。

Serialオブジェクト

 皆さんのArduino UnoはUSBケーブルでPCと接続されていると思います。スケッチを書き込む時には USB ケーブルを通して書き込まれます。PC とArduino Unoが(仮想的に)シリアル通信という状態で接続されていて、この接続を通して通信を行っているからです。 Arduinoでは、この通信をコントロールする仕組みとしてSerialオブジェクトが用意されています。
Serialオブジェクトにはいくつかの関数が用意されています。今回はそのうち以下の関数を使用します。

Serial.begin()

 シリアル通信を開始します。引数には通信速度を指定します。通信速度の詳細については、別の機会に説明します。

Serial.print()

 引数に指定したASCII文字列をPCに送信します。引数はダブルクォーテーション(")で括られた文字列を指定します。

Serial.println()

  Serial.print()と同じく引数に指定したASCII文字列をPCに送信しますが、最後に改行コードを付与します。

今回のスケッチは、ボタンモジュールが押された状態を USB ケーブルで接続されている PC のシリアルモニターに映す動きをします。setupではボタンモジュールとシリアル通信の設定を行います。loopではkeyCheck()関数を使ってキーの状態を繰り返しチェックして押されたボタンモジュールの番号をPCに送信します。

keyCheck()関数の改善

 keyCheck()関数は、押されたボタンモジュールが接続されているピン番号を返します。何も押されていない場合は0を返します。前回は変数buttonState とlastTime をstaticに設定して関数内に記述しましたが、今回は、関数の前に記述されています。また、buttonCountという変数が追加されています。引数はwaitTimeだけになってしましました。どうしてでしょう?
 実は、今回複数のボタンモジュールに対応するために変数を配列で持たせているんです。

配列

 配列は変数の集合です。[]の中に数字を入れることでそれぞれの変数にアクセスできます。
int pinNumber[ ] = {2,3,4};
とすると、pinNumber[0]には2、pinNumber[1]には3、pinNumber[1]には4が設定されます。配列は0から始まります。呼び出すときもpinNumber[0]等とすればいいです。
 今回は、複数のボタンモジュールを扱うのですが、モジュールの数によって必要となる変数の配列数が変わります。関数の中をあまり変更したくないので配列の宣言を先頭に配置しました。buttonCountはボタンモジュールの数、pinNumber配列にはどのピン番号が割り当てられるか、buttonState配列にはそれぞれのボタンモジュールの状態、lastTime配列にはそれぞれのボタンモジュールが押された時間が記録されます。
 keyCheck()関数の中では、この配列を使ってそれぞれのボタンモジュールについて所定の時間押されているかを確認しています。この処理はfor文を使って実行されています。

for文

 for文を使用すると、指定された条件で繰り返しの処理が実行できます。以下のように記述します。

for (初期値; 条件; 増分) {
 処理内容
}

初期値で繰り返しカウントに使う変数を初期化。条件が成立している間処理内容を実行します。処理が実行されるたびにカウントに使う変数を増分の条件で変更。条件が成立しなくなるまで処理内容を実行します。
今回は、
for (int i = 0 ; i <= buttonCount - 1 ; i++ ) {
 処理内容
}
となっていますので、変数iが0から始まって i <= buttonCount - 1の条件が成立している間処理を実行します。増分は”i++”となっていますが、これは変数iを一つずつ増やすという意味です。つまり、pinNumber配列に割り当てられているピン番号を一つずつ確認しているんです。押されていることがわかったらkeyCheck()関数は該当するピン番号を返します。

シリアル通信って

 どうですか?一つの関数で複数のボタンモジュールに対応できましたね。それにしてもシリアルモニター。PCへ通信した内容が表示できるのは便利です。ところでシリアル通信って何でしょう?シリアルモニターにも他に機能がありそうだし・・・次回は、シリアル通信について紹介しようと思います。
hirocom777.hatenadiary.org


Arduino UNO入門の連載記事はコチラからどうぞ!!