「スイッチが押されたら、LEDをピカッと光らせる」というプログラムが思った通りに動作しなかった原因を解明します。
プログラムの確認部分
前回の記事で「スイッチが押されたら、LEDをピカッと(50ms)点灯する」というプログラムを作成したはずなのに、動作確認したところ「スイッチを押している間、LEDが点灯する」という結果になってしまいました。
今回の記事では、なぜそのような動作になってしまうのか、原因を解明していきます。
プログラムの中で「スイッチが押されたら、LEDを50ms点灯する」ように書いた部分を取り出してみます。ピカッと光るはず、と思って作成したプログラムは以下の部分です。
void loop() {
// 左スイッチ状態を読み取り、ONだったらLEDを一定時間点灯する
if( digitalRead(SWITCH_HIDARI) == ON ) {
// LEDを点灯
digitalWrite(LED_BLUE, HIGH);
// 一定時間待つ
delay(TENTOU_JIKAN);
// LEDを消す
digitalWrite(LED_BLUE, LOW);
}
}
これから、この部分がなぜ「スイッチが押されたら、LEDを50ms点灯する」というような動作にならないのか、考えていきます。
スイッチを押す動作
このプログラムは、人が操作するスイッチの状態を確認しながら動作しています。そこで、人がスイッチを操作する様子を振り返ってみましょう。
ここで質問ですが、このプログラムの動作確認をしたとき、どの程度の時間スイッチを押したでしょうか?
おそらく「プチッ」っという感じで短い時間押したと思います。この「プチッ」と押した時間はどのぐらいでしたか? おそらく長くて1秒程度、短くても0.2〜0.3秒程度ではないでしょうか。
これからプログラムの動作を追っていきますが、人がスイッチを押す時間は0.5秒と仮定して話を進めたいと思います。スイッチの状態は、以下のように最初はOFF、0.5秒間ON、そのあとOFFとして話を進めます。
プログラムの動作速度
人がスイッチを押す時間は0.5秒としました。
ところで、Arduino Microはプログラムをどのぐらいの速度で実行するのでしょうか?
void loop() {
// 左スイッチ状態を読み取り、ONだったらLEDを一定時間点灯する
if( digitalRead(SWITCH_HIDARI) == ON ) {
// LEDを点灯
digitalWrite(LED_BLUE, HIGH);
// 一定時間待つ
delay(TENTOU_JIKAN);
// LEDを消す
digitalWrite(LED_BLUE, LOW);
}
}
このプログラムでは if
、digitalRead()
、digitalWrite()
、delay()
を利用しています。
このうち、if
、digitalRead()
、digitalWrite()
は処理時間がほとんどかかりません。厳密な計算はしていませんが、いずれの命令も大体1秒間に数十万回〜100万回程度実行できます。つまり、1つの命令にかかる時間はだいたい0.000001秒程度といったところでしょうか。
一方、delay()は引数の数字によって処理にかかる時間が変わります。今回のプログラムでは引数に50を指定していますので、0.05秒かかっています。
delay()
命令は他の命令にくらべて5万倍程度の時間がかかっていることになります。
プログラム上では、いずれの命令も1行で書かれていますが、同じ1行でも処理時間にはかなり差がある、ということを頭に入れておいてください。
これからプログラムのこの部分について、スイッチがOFFのときとONのときのプログラムの動作をそれぞれ確認します。
スイッチがOFFのとき
このプログラムで、スイッチがOFFの時、つまり「digitalRead(23)」が1の時はif文は成立しません。
loop()はArduino Microが動作している限り何度も繰り返し実行しますので、条件判断式の「digitalRead(23) == 0」が成立するか、1秒間に何十万回もずっと確認し続けているわけです。
スイッチがONのとき
次に、このプログラムでスイッチがONの時、つまり「digitalRead(23)」が0の時はif文が成立します。
先ほどのスイッチがOFFのときと異なり、if文の条件成立時の以下の命令が実行されます。
// LEDを点灯
digitalWrite(LED_BLUE, HIGH);
// 一定時間待つ
delay(TENTOU_JIKAN);
// LEDを消す
digitalWrite(LED_BLUE, LOW);
これらの命令のうち、digitalWrite()
は1秒間に100万回程度実行できるほどの速度ですので、実行する時間はほとんど無視できるでしょう。時間がかかるのはdelay()
で、このプログラムでは引数として50を指定していますので、delay()
命令で0.5秒かかります。
人がスイッチを押す時間の長さと、Arduino Microが命令を処理する時間の長さはかなり違う、ということがわかりました。
次にこれらの情報を元にして、スイッチを押すとLEDがピカッと光らない原因を考えていきます。
ピカッと光らない原因
それでは、スイッチが押されたときにArduino Microの内部でどのような処理がされているのか、図で考えてみましょう。
Arduino Microが動作を開始した後、しばらくしてから人がスイッチを押しますので、それまでの間スイッチはOFFです。先ほどのプログラム動作で説明した通り、このスイッチがOFFの間、膨大な回数のif文の条件成立を確認しています。
次に、人がスイッチを押すと、押したタイミングでif文が成立してif文の中の命名を処理します。
この部分を詳しく考えていきます。上の図の赤い矢印を拡大すると、以下のような処理をしています。
この部分の処理時間は、delay(50);
以外はほとんど時間がかかりませんので、ほぼ0.05秒の処理時間です。
この処理が終わると、Arduino Microはloop()を繰り返します。繰り返すとき、スイッチはONのままですから、if文が成立して再度if文の中身を繰り返します。
ここで、1回目のif文と2回目のif文の境目の命令を見ると、いずれも時間がほとんどかからない命令です。
上の黒点線枠で囲んだ部分は、「LEDをOFF」「if文判断」「LEDをON」にしていますが、いずれも時間がほとんどかかっていないため、見た目ではLEDは一瞬消えたようには見えず、LEDは点灯したままに見えます。
つまり、以下のようにLEDが点灯したままに見えてしまっているわけです。
さらにこのあとも、スイッチが押されている間はif文が成立して同じような処理が続くため、LEDは点灯したままに見えるわけです。
スイッチを押している間、LEDが点灯してしまう原因がわかりました。それでは、スイッチを押すと、LEDがピカッと光る(50ms点灯する)というプログラムはどのように考えればいいのでしょうか。
次回の記事で、対策を考えてスケッチを作成していきます。
ミニチャレンジ課題
最後に、ミニチャレンジ課題に取り組んでみてください。
今回の記事では、前回作成したプログラムが思い通りに動作しない原因を考えてきました。ところで、最初に作成した「スイッチが押されたら、LEDを3秒間点灯する」というプログラムでは、スイッチを押してからLEDが3秒間点灯して正しく動作したはずです。
なぜ「スイッチが押されたら、LEDを3秒間点灯する」というプログラムはうまく動いたのか、理由を明らかにしてみてください。
「スイッチが押されたら、LEDを3秒間点灯する」というプログラムで、スイッチを5秒押してから離すと、LEDはトータルで何秒点灯するか考えてみてください。考えがまとまったら実際にプログラムを動作させて確認してみてください。
更新履歴
日付 | 内容 |
---|---|
2021.8.6 | 新規投稿 |