詳しく解説!!Arduino-その8です。前回の記事はこちらです。
もう少し整理したい
前回はボタンモジュールの入力をきっかけとして使うときについて考えてみました。millis()の機能を使用して本格的な対応がとれたんじゃないでしょうか?でも、少しスケッチが複雑になってしまいましたね。チャタリング対策はプログラム本体の動きとは直接関係ありません。それをスケッチ本体に書くとわかりずらいものになってしまいます。そこで今回は、関数という手法を使用してスケッチをシンプルにする方法をご紹介します。
関数
関数って学校で数学の時間に習いましたよね。何か値を入れると処理をして値を返してくれるやつです。Arduinoでは関数を以下のように書きます。
返す値の型 関数名(引数){
処理内容
}
引数(ひきすう)とは、関数に渡す値のことです。引数を複数渡す場合もあるし何も渡さない場合もあります。関数は引数で渡された値を処理して返す値の型で値を返します。また、処理だけをして値を返さない関数もあります。その場合には返す値の型は"void"と指定します。"void"ってもう出てきていますよね。setupとloopです。
void setup() {
}
void loop() {
}
setupもloopも引数が無くて返す値もない関数だったんですね。ざっくり言うと、スケッチって関数の集まりなんです。で、今回は他にも関数を用意してチャタリング対策機能をまとめちゃおうって話です。
今回のスケッチ
さて、今回のスケッチは以下のようになりました。
void setup() { pinMode(3, OUTPUT); pinMode(2, INPUT); } void loop() { if (keyCheck(2, 50) == 2) { digitalWrite(3, !digitalRead(3)); } } int keyCheck(int pinNumber , int waitTime) { static int buttonState = 0; static unsigned long lastTime = 0; if (digitalRead(pinNumber) == LOW) { buttonState = 0; lastTime = 0; } else { //digitalRead(number) == HIGH if (lastTime == 0) { lastTime = millis(); } else { //lastTime != 0 if (buttonState == 0 && (millis() - lastTime) > waitTime) { buttonState = 1; return (pinNumber); } } } return (0); }
loopはずいぶんシンプルになりましたね。書き込んで実行してみてください。if文の中にあるkeyCheck()っていうのが今回作った関数です。その内容は以下のようになります。
関数 keyCheck()
keyCheck()はボタンが押された(OFFからONに変わった)ことを知らせる関数です。チャタリング防止機能付きです。引数はint pinNumber (ボタンを検出するピン番号)と, int waitTime(チャタリング回避のための待ち時間:単位ミリ秒)です。今回は2番ピンを50ミリ秒で確認することになります。処理の内容については前回説明した内容とほぼ同じなのですが、関数keyCheckの中の初めに以下のような記述があります。
static int buttonState = 0;
static unsigned long lastTime = 0;
変数の宣言っぽいんですが、今回は関数の中に書かれていますよね・・・そして、先頭にあるstatic って何でしょう?
スコープ
実は、変数は記述している場所によって参照できる範囲が変わってきます。今までのスケッチは先頭で変数の宣言をしていました。このような宣言の仕方(関数の外で宣言)すると、すべての関数でその変数を参照できます。どこからでも参照できるのは便利なようですが、それってどの関数からでも変数を変更できるってことになるので好ましくないんです。スケッチが大きくなると変数の管理がうまくいかなくなっちゃうんですよ。関数の中で宣言した変数は、基本関数の中でしか使用できません。値を共有したいときは引数で渡すようにしたほうがいいんですね。
・static
static って静的なって意味なんですが、ちょっと分かりずらいですね。関数の中で宣言した変数は、関数の終了時(今回の場合はreturn()で値を返したとき)に内容が破棄されてしまいます。再度関数が呼ばれた時には、前回の値は保持されていません。でも、今回の関数keyCheck()では、ボタンの状態(buttonState )と最初にボタンが押された時間(lastTime )を記憶しておかなければなりません。変数を宣言するときに先頭にstatic をつけておくと、関数が終了した後も変数の内容を保持しています。
・return ()
関数は値を返すとお話ししましたが、値を返すにはreturn ()を使います。かっこの中に値を記述すると関数はその値を返して終了します。今回は、ボタンが押されたことを認識すればピン番号(2)を、そうでなければ0を返します。
つまり、関数 keyCheck()は指定されたピンのボタンが指定された時間押し続けられているとピン番号を1度だけ返す(そうでなければ0を返す)関数ということです。便利になりましたね!!
さらなる改善
うまくいったのですが、更に使い勝手を良くしていきたいと思います。ボタンモジュールの数って必ずしも一つだけじゃありませんよね。次回は複数のボタン入力にも対応してみたいと思います。
hirocom777.hatenadiary.org