天下一反省会!

電子工作、プログラミング、読書など

\今月のイチオシ記事/

おススメ記事1
おススメ記事2
おススメ記事3
おススメ記事4

[Arduino入門]スイッチを1回押すごとにLEDの点灯・消灯が切り替わる回路の作り方を解説します!

今回は、スイッチを1回押すごとにLEDの点灯・消灯が切り替わる回路の作り方を紹介します。

この記事は前回の続きになります。前回の記事はこちらから↓
potala123.hatenablog.com



配線図とスケッチの全文を公開しているのでよかったら最後までご覧ください。

スイッチを押すたびにON、OFFが切り替わる機能を実装したい!

ここまでのおさらいをすると、タクトスイッチは"押している間だけON"となるスイッチでした。しかし、我々の身の回りにある一般的なスイッチ、たとえば部屋の電気をつけるためのスイッチなどは、"一度押すとON,もう一度押すとOFF"というように押すたびにONとOFFが切り替わるようになっています。

タクトスイッチも、"一度押すとON,もう一度押すとOFF"となったら便利ですよね。


そこでここからは、"タクトスイッチを押すたびにON、OFFが切り替わる"機能を実装していきたいと思います。

どのようなスケッチを書けばいいか構想を立ててみる

タクトスイッチは"押している間だけON"ですが、今回実装したいのは"押すたびにON,OFFが切り替わる"機能です。
この機能を実装するためにはどうすればよいでしょうか。


例えば、「ボタンが押されたことを検知するたびに、LEDへの出力のHIGH,LOWを切り替える」というように考えてみると、今回必要となる機能は、「ボタンが検出されたことを検知する」という機能と、「LEDへの出力のHIGH,LOWを切り替える」という機能の2つということになります。

今回使用する配線図とスケッチ

今回使用する回路です。

今回使用する回路の図

今回使用するスケッチ(プログラム)です。コピペすればすぐに実行できます。

int switch_status = 1;//スイッチの状態。最初はLOWが入力されている
int LED_status = 0;//LEDの状態。最初は消灯している

void setup() {
pinMode(8,INPUT_PULLUP);//8PINを受信用に設定、プルアップ抵抗付き
pinMode(13,OUTPUT);//13PInを出力用に設定
}

void loop() {
 if (digitalRead(8) != switch_status && digitalRead(8) == 0){//スイッチの状態が変わった,かつスイッチが押されている状態
  if (LED_status == 0){
    digitalWrite(13,HIGH);
    LED_status = 1;
  }else if (LED_status == 1){
    digitalWrite(13,LOW);
    LED_status = 0;
  }
}
switch_status = digitalRead(8);//8ピンの状態を変数に保存
delay(100);
}


この部分では、switch_statusという変数と、LED_statusという変数をそれぞれ定義しています。頭についている"int"は”整数型”、すなわち整数を入れるための変数であるということを意味しています。

今回はスイッチのON,OFFを識別するための変数をswitch_status、回路内のLEDが点灯しているかどうかを示す変数をLED_statusとします。

最初はスイッチが押されておらず、この状態ではHIGH(=1)の信号が入力されるので、switch_statusの初期値は1とします。また、LEDは最初は点灯していないので、LED_status の初期値は0とします。

最初スイッチが押されていない状態からスタートするなら、switch_statusの初期値はLOW(=0)ではないのか、と疑問に思われる方もいるかもしれませんが、この点については後ほど解説します。




それでは次に、setup関数の部分を見てみましょう

setup関数

void setup() {
pinMode(8,INPUT_PULLUP);//8PINを受信用に設定、プルアップ抵抗付き
pinMode(13,OUTPUT);//13PInを出力用に設定
}

setup関数内では、8ピンと13ピンの設定を行っています。

pinMode(8,INPUT_PULLUP) の部分では、8ピンをINPUT(入力用)に設定しています。なお今回は、INPUTではなくINPUT_PULLUPとすることで、プルアップ抵抗機能を用いています。

プルアップ抵抗機能は、Arduinoとスイッチを接続する際に重宝する機能です。ここではプルアップ抵抗に関する解説は行いませんが、私が参考にしたページを紹介します。

burariweb.info


pinMode(13,OUTPUT); の部分では、13ピンをOUTPUT(出力用)に設定しています。そのままですね。


それではいよいよメインとなるloop関数の説明に入ります。

loop関数


loop関数内は記述が多いうえに動作も複雑なので、何か所かに分割して解説していきます。

まずは最初のif文から。

if (digitalRead(8) != switch_status && digitalRead(8) == 0){

急に難易度が跳ね上がったように見えますが、よく見ると簡単なのでご心配なさらず。

まずdigitalRead(8) != switch_statusの部分。

ここではdigitalRead(8)、すなわち8ピンの入力の状態(すなわちスイッチが押されているかどうか)と変数”switch_status”の状態を比較しています。



通常のイコールではなく"!="で結ばれているので、スイッチの状態と変数”switch_status”の状態が異なれば真ということになります。



なお、この後解説しますが、変数”switch_status”には、直前のボタンの状態(押されているかいないか)を記録してあります。



つまり「スイッチの状態と変数”switch_status”の状態が異なる」とは、「直前までスイッチが押されていなかったが、今は押されている」
または「直前までスイッチが押されていたが、今は押されていない」と言いかえることができます。


回りくどい言い方になりましたが、要するに「スイッチのON,OFFが切り替わったかどうか」を表しています。





次にdigitalRead(8) == 0の部分について。この部分では、8ピンの入力がゼロ、すなわちスイッチが押されている状態を真としています。



以上2つの条件が&&、すなわち「かつ」でつながれているため、if (digitalRead(8) != switch_status && digitalRead(8) == 0)の部分を日本語で表現すれば、



「スイッチのON,OFFが切り替わった」かつ「スイッチが今まさに押されている状態」 


と表せます。またまた回りくどい表現ですが、これを簡単な言葉に言いかえると



「スイッチを押した瞬間」ということです。



注意したいのは、「スイッチから指を離した瞬間」はif文の条件を満たさないということです。なぜなら「スイッチから指を離した瞬間」は「スイッチが今まさに押されている状態」という条件を満たさないからです。


以上をまとめると、if (digitalRead(8) != switch_status && digitalRead(8) == 0)の部分は「スイッチが押された場合」という条件を意味しているということです。


それでは、次の部分について解説します。

if (LED_status == 0){
    digitalWrite(13,HIGH);
    LED_status = 1;
}else if (LED_status == 1){
    digitalWrite(13,LOW);
    LED_status = 0;

まず1行目について。if (LED_status == 0) は、変数"LED_status"の値がゼロ、すなわち”LEDが消灯しているとき”を意味しています。
この時、 digitalWrite(13,HIGH);で13ピンからの出力をHIGHにすることで13ピンに接続されたLEDを点灯させます。その後、LEDの店頭状態を表す変数” LED_status”の値を1にしておきます。

一方で、else if (LED_status == 1)、すなわちLEDが点灯している場合は、digitalWrite(13,LOW);とすることで13ピンからLEDへの出力をゼロにし、変数"LED_status" の値をゼロに変更します。



そして最後の部分について。

switch_status = digitalRead(8);//8ピンの状態を変数に保存
delay(100);

switch_status = digitalRead(8)の行では、8ピンの様子(スイッチが押されているか否か)を変数"switch_status"に記憶しています。

ここで記憶されたスイッチの状態は、 if (digitalRead(8) != switch_status && digitalRead(8) == 0)の部分でスイッチが押されたかどうかの判定に用いられます。

例えば、”一つ前のloopではスイッチは押されていなかった(switch_status = 1)が、今は押されている(digitalRead(8) = 0)”みたいな感じです。(この回路ではプルアップ抵抗を用いているので、スイッチが押されたときが0,押されていないときが1であることに注意。)


そして最後の行では、delay(100);とすることで100ミリ秒、すなわち0.1秒の間プログラムを一時停止させています。



なぜわざわざ一時停止を挟まなければいけないのか、と疑問に思う方もいるかもしれませんが、ここはこういうものだと覚えてください。



気になった方はdelay(100)の部分を消去してから実行してみるといいでしょう。たまにではありますが、ボタンを押した時の反応がおかしくなるはずです。



解説は以上になります。押すたびにON,OFFが切り替わる仕組みは様々な場面で活用できるはずです。ぜひマスターしていただければと思います。