「スイッチを押したら、LEDをピカッと光らせる」というプログラムが思った通りに動作しなかった原因を解明します。
プログラムの確認部分
前回の記事で「スイッチを押したら、LEDをピカッと点灯する」というプログラムを作成したはずなのに、動作確認したところ「スイッチを押している間、LEDが点灯する」という結果になってしまいました。
今回の記事では、なぜそのような動作になってしまうのか、原因を解明していきます。
プログラムの中で「スイッチを押したら、LEDをピカッと点灯する」ように書いた部分を取り出してみます。
void loop() {
// 左スイッチ状態を読み取り、ONだったらLEDを一定時間点灯する
if( digitalRead(SWITCH_HIDARI) == ON ) {
digitalWrite(LED_BLUE, HIGH); // LEDを点灯
delay(TENTOU_JIKAN); // 一定時間待つ
digitalWrite(LED_BLUE, LOW); // LEDを消す
}
}
これから、この部分がなぜ「スイッチを押している間、LEDが点灯する」という動作になるのか、考えていきます。
スイッチを押す動作
このスケッチは、人が操作するスイッチの状態を確認しながら動作しています。
そこで、人がスイッチを操作する様子を振り返ってみましょう。
ここで質問ですが、スケッチの動作確認をしたとき、どの程度の時間スイッチを押したでしょうか?
おそらく「プチッ」っという感じで短い時間押したと思います。
この「プチッ」と押した時間はどのぐらいですかね…?
人によって違うと思いますが、おそらく長くて1秒程度、短くても0.2〜0.3秒程度ではないでしょうか。
これからスケッチの動作を追っていきますが、スイッチを押す時間は0.5秒と仮定して話を進めたいと思います。
スイッチの状態は、次のように最初はOFF、0.5秒間ON、そのあとOFFとして話を進めます。
プログラムの動作速度
人がスイッチを押す時間を0.5秒としました。
ところで、Arduino Microはスケッチをどのぐらいの速度で処理しているのでしょうか?(次のスケッチは#define
の定義名ではなく、端子名で書いています)
void loop() {
// 左スイッチ状態を読み取り、ONだったらLEDを一定時間点灯する
if( digitalRead(A5) == 0 ) {
digitalWrite(12, HIGH); // LEDを点灯
delay(50); // 一定時間待つ
digitalWrite(12, LOW); // LEDを消す
}
}
このスケッチでは if
、digitalRead()
、digitalWrite()
、delay()
を利用しています。
このうち、if
、digitalRead()
、digitalWrite()
は処理時間がほとんどかかりません。厳密な計算はしていませんが、いずれもだいたい1秒間に数十万回〜100万回程度処理できます。
つまり、1つの処理にかかる時間はだいたい0.000001秒程度といったところでしょうか。
一方、delay()
は引数の数字によって処理にかかる時間が変わります。今回のプログラムでは引数に50を指定していますので、delay
関数では0.05秒かかっています。
スケッチとしては、いずれの処理も1行で書かれていますが、同じ1行でも処理時間にはかなり差がある、という点に注意してください。
これから上のスケッチについて、スイッチがOFFのときとONのときの処理の様子を確認しますが、この時間感覚を頭に入れておいていただければと思います。
スイッチがOFFのときの処理のようす
最初はスイッチがOFFのとき、Arduino Microはどのような処理をしているのか確認します。
このスケッチで、スイッチがOFFのときはdigitalRead(A5)
の戻り値は1
になります。
if
の条件はdigitalRead(A5) == 0
ですので、スイッチがOFFのときは条件は成立しません。
loop
関数はArduino Microが動作している限り何度も繰り返し実行します。
つまり、スイッチがOFFの間、「if
の条件を確認し、成立しないので何もしない」という動作を1秒間に何十万回も繰り返しています。
スイッチがONのときの処理のようす
次に、スイッチがONのとき(=スイッチをONにしている0.5秒間)、Arduino Microはどのような処理をしているのか確認します。
スイッチがONのときはdigitalRead(A5)
の戻り値は0
になります。
if
の条件はdigitalRead(A5) == 0
ですので、条件成立となります。
条件が成立しますので、if
の中の次の処理が実行されます。
digitalWrite(12, HIGH); // LEDを点灯
delay(50); // 一定時間待つ
digitalWrite(12, LOW); // LEDを消す
これらの処理のうち、digitalWrite
関数は1秒間に100万回程度実行できるほどの速度ですので、処理時間はほとんど無視できます。
時間がかかるのはdelay
関数で、このスケッチでは引数として50を指定していますので、delay
で関数の処理時間は0.05秒です。
人がスイッチを押す時間の長さは0.5秒と仮定しましたので、Arduino Microの処理時間とはかなり違う、ということがわかりました。
次にこれらの情報を元にして、スイッチを押すとLEDがピカッと光らない原因を考えていきます。
ピカッと光らない原因
それでは、スイッチが押されたときにArduino Microの内部でどのような処理がされているのか、図で考えてみましょう。
Arduino Microが動作を開始した後、しばらくしてから人がスイッチを押しますので、それまでの間スイッチはOFFです。
スイッチがOFFの間は、次のイラストのように膨大な回数のif
の条件成立を確認しています。
条件は成立しないので、「条件が成立しているか確認する」という処理をすごいスピードで何度も繰り返します。
次に、人がスイッチを押すと、押したタイミング以降、最初のif
の条件判断で条件が成立し、if
の中の処理を行います。(次のイラストの赤矢印部分)

このif
の条件が成立したときの処理を詳しく考えていきます。
上のイラストの赤矢印を拡大すると、次のような処理をしています。

この部分の処理時間は、delay(50);
以外はほとんど時間がかかりませんので、ほぼ0.05秒の処理時間です。
この処理が終わるとloop
の処理は終わりますので、Arduino Microは再度loop
の処理を繰り返します。つまり、再度if
の条件判断を行います。
スイッチはONのままですから、条件が成立して再度if
の中の処理を繰り返します。(次のイラストのオレンジ部分)
ここで、1回目の処理と2回目の処理の境目をを見てみてください。(次のイラストの黒点線枠部分)
上の黒点線枠で囲んだ部分は、digitalWrite
、if
、digitalWrite
を処理しています。
ここで、とても重要なポイントがあります。
黒点線枠内の処理では、digitalWrite
関数でLEDを一度OFF、その後ONにしていますが、OFFとONの間はif
の条件判断処理しかありません。
これらの処理はほとんど時間がかかりませんので、見た目ではLEDは消えたようには見えず、LEDは点灯したままに見えてしまうんです!
つまり、上のイラストの処理は、見た目には次のようにLEDが点灯したままに見えてしまっているわけです。

さらにこのあとも、スイッチが押されている間は同じように処理が続くため、LEDは点灯したままに見えるわけです。
スイッチを押している間、LEDが点灯してしまう原因がわかりました。
それでは、「スイッチを押すと、LEDがピカッと光る」というスケッチはどのように考えればいいのでしょうか。
次回の記事で、対策を考えてスケッチを作成していきます。
ミニチャレンジ課題
課題
ミニチャレンジ課題を用意してみました。今回はスケッチ作成ではなく、考える内容にしてみました。
前回の記事で最初に作成した「スイッチが押されたら、LEDを3秒間点灯する」というスケッチは問題なく動作しました。(次のスケッチです)
/*
* スイッチ制御プログラム
* スイッチを押すと一定時間LEDを点灯する
*/
#define LED_BLUE 12 // 青色LEDの接続端子名
#define SWITCH_HIDARI A5 // スイッチの接続端子名
// スイッチの状態
#define OFF 1
#define ON 0
// LEDの点灯時間(単位:ms)
#define TENTOU_JIKAN 3000
void setup() {
pinMode(LED_BLUE, OUTPUT); // LEDのピンを出力に設定
pinMode(SWITCH_HIDARI, INPUT_PULLUP); // スイッチのピンを入力に設定
digitalWrite(LED_BLUE, LOW); // 最初はLEDをOFFに設定しておく
}
void loop() {
// 左スイッチ状態を読み取り、ONだったらLEDを一定時間点灯する
if( digitalRead(SWITCH_HIDARI) == ON ) {
digitalWrite(LED_BLUE, HIGH); // LEDを点灯
delay(TENTOU_JIKAN); // 一定時間待つ
digitalWrite(LED_BLUE, LOW); // LEDを消す
}
}
このスケッチはなぜうまく動作していたのでしょうか?
解答例
上のスケッチでは、スイッチがONのときにif
の条件が成立してif
の中の処理が実行されます。
digitalWrite(LED_BLUE, HIGH); // LEDを点灯
delay(TENTOU_JIKAN); // 一定時間待つ
digitalWrite(LED_BLUE, LOW); // LEDを消す
この処理でdigitalWrite
の処理時間はほとんどかかりませんが、delay
では3秒待ちをしています。
人がスイッチを「プチッ」と押す時間は長くても1秒程度です。
そのため、delay
の待ち時間である3秒の間に、人はスイッチを離してしまいます。
結果として、上の処理が終わる頃にはスイッチがOFFになっていて、loop
で次に処理をするときはif
の条件は成立しないため、結果としてうまく動いていました。
更新履歴
日付 | 内容 |
---|---|
2021.8.6 | 新規投稿 |
2025.2.4 | 説明内容変更 ミニチャレンジ課題内容変更・解答例追加目次に戻る |