ブロックプログラミングの「もし」ブロック:Arduinoのボタンとif/elseでLEDを制御
ArduinoのボタンとLEDで学ぶブロックプログラミングの「もし」ブロック。ピンの読み取り、if/else、=、≠、<、>、入れ子の条件、オン/オフの切り替え、チャタリング対策、LDRを使った常夜灯まで解説します。
ブロックプログラミングの「もし」ブロックを使うと、プログラムは質問の答えによって2つの道のどちらかを選べます。「ボタンは押されている?押されていればLEDを点灯、押されていなければ消灯」という具合です。ArduinoのC++ではこの構造をif/elseと呼び、BlueGraysの「もし … 実行 … そうでなければ」ブロックはこれにそのまま対応しています。この記事ではArduinoのボタンとLEDのプロジェクトを使い、まずピンを入力に設定して読み取る方法、次に「もし」ブロック、比較演算子、入れ子の条件、2つの条件を「かつ」で組み合わせる方法を、ブロックごと、行ごとに見ていきます。
これまでのプログラムは、いつも同じことをしていました。LEDが点灯し、待ち、消灯し、また待つ。外の世界の様子をうかがうことは一度もありませんでした。条件が加わると、ボードはボタンや光センサー、測った距離を見て判断するようになります。ロボットプログラミングの本当のおもしろさは、ここから始まります。ここで紹介する例はすべて無料のブロック付きプロジェクトのものなので、ブロックプログラミングのページやアプリでブロックとコードを開き、記事と並べて追いかけられます。
入力と出力:ピンはどちら向きに働く?
Arduinoのデジタルピンは、2つの役割のどちらかを担います。出力に設定したピンは5 V(HIGH)か0 V(LOW)を出します。LED、ブザー、リレーはこうして駆動します。入力に設定したピンは何も出さず、かかっている電圧を見るだけです。Arduino Unoでは、約3 Vより上をHIGH、1.5 Vより下をLOWとして読み取ります。ブロックでは、この設定をセットアップの部分で行います。「ピン 13 を 入力 に設定」ブロックはC++のpinMode(13, INPUT);に、「ピン 7 を 出力 に設定」はpinMode(7, OUTPUT);になります。ピンを読み取るには「ピン 13 を読み取る」ブロックを使います。このブロックはほかと見た目が違います。縦に積み重ねる命令ではなく、角の丸い値ブロックで、別のブロックの中にあるスロットにはめ込みます。C++ではdigitalRead(13)にあたり、HIGHかLOWを返します。ArduinoではHIGHが1、LOWが0に等しいので、この結果を数値のように変数に入れることもできます。まとめると、命令ブロックは何かを実行し、値ブロックは結果を返します。そして「もし」ブロックの条件スロットには、そうした結果しか入りません。
| ブロック | C++での書き方 | 動作 |
|---|---|---|
| ピン 13 を 入力 に設定 | pinMode(13, INPUT); | ピンを読み取りモードにする(セットアップで一度だけ) |
| ピン 7 を 出力 に設定 | pinMode(7, OUTPUT); | ピンから電圧を出せるようにする |
| ピン 13 を読み取る | digitalRead(13) | HIGH(1)またはLOW(0)を返す |
| ピン 7 に HIGH を書き込む | digitalWrite(7, HIGH); | ピンに5 Vを出力し、LEDが点灯 |
| A0 をアナログ読み取り | analogRead(A0) | 0〜1023の数値を返す |
| もし … 実行 … そうでなければ | if (…) { … } else { … } | 条件によって2つの道のどちらかを実行 |
配線:ボタンは13、LEDは7、プルダウン抵抗は必須
ボタンでLEDを点灯(押している間のみ)プロジェクトでは、ボタンをD13に、LEDをD7につなぎます。ボタンの片方の足を5Vに、もう片方をD13につなぎ、D13とGNDの間に10 kΩのプルダウン抵抗を入れます。ボタンを離しているときは、抵抗がピンをGNDに引き下げるので、LOWと読み取られます。ボタンを押すと5Vが直接ピンに届き、HIGHと読み取られます。抵抗の値が大きいので、ボタンを押している間に5VからGNDへ流れる電流は0.5 mAほどにすぎません。LEDの長い足は220 Ωの抵抗を通してD7に、短い足はGNDにつなぎます。
| 部品 | 接続先 | Arduino Unoのピン |
|---|---|---|
| ボタン、足1 | 直接 | 5V |
| ボタン、足2(対角) | 直接 | D13 |
| 10 kΩの抵抗(プルダウン) | D13とGNDの間 | D13 – GND |
| LEDの長い足(アノード) | 220 Ωの抵抗を通して | D7 |
| LEDの短い足(カソード) | 直接 | GND |
「もし」ブロックとif/else:ボタンを押している間LEDを点灯
このプロジェクトのブロック版は2つの部分からなります。「セットアップ(1回だけ実行)」ではピン13を入力、ピン7を出力に設定します。「ずっと繰り返す」には大きなブロックが1つだけあります。もし … 実行 … そうでなければです。その六角形の条件スロットには「ピン 13 を読み取る = HIGH」という比較が入っています。条件が真なら「実行」の枝にある「ピン 7 に HIGH を書き込む」ブロックが、偽なら「そうでなければ」の枝にある「ピン 7 に LOW を書き込む」ブロックが実行されます。

1void setup() {
2 pinMode(13, INPUT); // Buton girişi (harici pull-down) / Button input (external pull-down)
3 pinMode(7, OUTPUT); // LED çıkışı / LED output
4}
5
6void loop() {
7 if (digitalRead(13) == HIGH) { // Buton basılı mı? / Is the button pressed?
8 digitalWrite(7, HIGH); // Basılı: LED yanar / Pressed: LED on
9 } else {
10 digitalWrite(7, LOW); // Bırakıldı: LED söner / Released: LED off
11 }
12}
13コードをブロックの横に並べると、対応関係は一目瞭然です。ifという語がブロックの「もし」に、かっこ内の条件digitalRead(13) == HIGHが条件スロットに、最初の波かっこの組が「実行」の枝に、elseとそれに続く波かっこが「そうでなければ」の枝に対応します。枝に置いたブロックはどれも、コードでは対応する波かっこの中の1行になります。loop()は1秒間に何万回も実行されるので、ボードはボタンを何度も読み直します。指を離した瞬間、次の周回で条件は偽になり、LEDは消えます。プロジェクト名に「押している間のみ」とあるのはこのためで、LEDはボタンを押し続けている間だけ点灯します。「そうでなければ」の枝は必須ではありません。「実行」の枝だけの「もし」ブロックは、elseのないifになります。ただしこのプロジェクトで「そうでなければ」の枝を消すと、LEDは一度点灯したら二度と消えません。消灯させる行がなくなるからです。どの条件でも両方の枝を考えるのは、よい習慣です。
比較ブロック:=、≠、<、>
| ブロックの記号 | C++ | 意味 | プロジェクトでの例 |
|---|---|---|---|
| = | == | 等しい | digitalRead(13) == HIGH(ボタンでLEDを点灯) |
| ≠ | != | 等しくない | button != lastButton(ボタンでLEDの点灯・消灯を切り替え) |
| < | < | より小さい | value < 50(LDRで作る常夜灯) |
| > | > | より大きい | distance > minDistance(HC-SR04で距離を測定) |
ボタンでオン/オフ:入れ子の「もし」と状態変数
押している間だけ点灯するプロジェクトでは、LEDはボタンを押している間しか点灯しませんでした。本物の照明スイッチのように「1回押すと点灯、もう1回押すと消灯」にしたいなら、プログラムは2つのことを覚えておく必要があります。いまLEDが点灯しているかどうかと、前の周回でボタンがどう読み取られたかです。ボタンでLEDの点灯・消灯を切り替えプロジェクトでは、そのために「グローバル変数(最初に宣言)」の部分で2つの整数を宣言しています。ledState(0 = 消灯、1 = 点灯)とlastButton(前回の読み取り値)です。回路は前と同じで、ボタンは外付けのプルダウン抵抗とともにD13に、LEDはD7につなぎます。

1int ledState = 0; // LED durumu: 0 = sönük, 1 = yanık / LED state: 0 = off, 1 = on
2int lastButton = 0; // Butonun önceki okuması / Previous button reading
3
4void setup() {
5 pinMode(13, INPUT); // Buton girişi (harici pull-down) / Button input (external pull-down)
6 pinMode(7, OUTPUT); // LED çıkışı / LED output
7}
8
9void loop() {
10 int button = digitalRead(13); // Butonu oku / Read the button
11 if (button != lastButton) { // Buton durumu değişti / Button state changed
12 if (button == 1) { // Yalnız basış anında (LOW -> HIGH) / Only at the press (LOW -> HIGH)
13 ledState = !ledState; // Durumu ters çevir / Flip the state
14 digitalWrite(7, ledState);
15 }
16 delay(50); // Sıçramayı atlamak için kısa bekleme / Short wait to skip the bounce
17 lastButton = button; // Bu okumayı sakla / Store this reading
18 }
19}
20| ブロック | C++の行 | 役割 |
|---|---|---|
| 宣言:整数(int) ledState = 0 | int ledState = 0; | LEDの状態を保存 |
| 宣言:整数(int) lastButton = 0 | int lastButton = 0; | ボタンの前回の読み取り値を保存 |
| button に ピン 13 を読み取る を代入 | int button = digitalRead(13); | ボタンの現在の状態を読む |
| もし button ≠ lastButton | if (button != lastButton) { | ボタンの状態が変わったら中に入る |
| もし button = 1 | if (button == 1) { | 変化が押した瞬間(0から1)なら中に入る |
| ledState に ledState ではない を代入 | ledState = !ledState; | 0を1に、1を0にする |
| ピン 7 に ledState を書き込む | digitalWrite(7, ledState); | LEDを新しい状態にする |
| 50 ms待つ | delay(50); | 接点のチャタリングをやり過ごす |
| lastButton に button を代入 | lastButton = button; | この読み取り値を次の周回のために保存 |
プログラムの核心は、入れ子になった2つの「もし」ブロックです。外側の条件button ≠ lastButtonは、ボタンの状態が変わった周回でだけ真になります。ボタンを押し続けている間や触れていない間の何千回もの周回では、何も起きません。変化には2つの向きがあります。押したとき(0から1)と離したとき(1から0)です。内側の条件button = 1は、そのうち押したときだけを選びます。こうしてLEDは1回押すごとに1回だけ切り替わり、離したときにはまったく変わりません。コードでは、入れ子のifは波かっこの中の波かっことして現れます。ブロックでは、内側の「もし」が外側の「もし」の「実行」の枝に収まるので、どの行がどの条件に従っているかが一目でわかります。
ledState ではないブロックは、C++では!ledStateと書きます。感嘆符は論理的な反対をとります。0の反対は1で、0以外の数の反対は0です。ledStateに自分自身の反対を代入すると、押すたびに状態が反転します。次の「ピン 7 に ledState を書き込む」ブロックはdigitalWrite(7, ledState);の行です。HIGHが1、LOWが0に等しいので、変数の値をそのままピンに書き込めます。最後に、次の周回での比較が正しく行われるように、lastButtonにこの周回の読み取り値を代入します。この代入を忘れるとlastButtonは0のままになり、ボタンを押し続けている間は外側の条件が毎回真になって、LEDが速く点滅してしまいます。
アナログの条件:LDRを使った常夜灯
条件はHIGHとLOWだけのものではありません。LDRで作る常夜灯プロジェクトでは、「value に A0 をアナログ読み取り を代入」ブロックが、LDRのつながったA0の電圧を0〜1023の数値に変換します。C++ではvalue = analogRead(A0);の行です。続いて「もし」ブロックがvalue < 50を調べます。値が50未満なら暗いとみなしてD13のLEDを点灯し、そうでなければ消灯します。構造は押している間だけ点灯するプロジェクトと同じで、違うのは条件スロットの比較だけです。

1int value; // Işık okuması (0-1023) / Light reading (0-1023)
2
3void setup() {
4 pinMode(13, OUTPUT); // LED çıkışı / LED output
5}
6
7void loop() {
8 value = analogRead(A0); // Işık seviyesini oku / Read the light level
9
10 // Eşik 50: altı karanlık sayılır, hassasiyeti bu sayıyla ayarla
11 // Threshold 50: anything below counts as dark. Tune the sensitivity with this number
12 if (value < 50) {
13 digitalWrite(13, HIGH); // Karanlık: LED yanar / Dark: LED on
14 } else {
15 digitalWrite(13, LOW); // Aydınlık: LED söner / Bright: LED off
16 }
17}
18LDRと回路の抵抗の値によっては、しきい値50が部屋の明るさに対して低すぎたり高すぎたりすることがあります。適切な数値を見つけるには、まずLDRで光の強さを測定プロジェクトで、明るいときと暗いときの値をシリアルモニタで確認し、その間にしきい値を設定します。値がしきい値のすぐ近くで行き来するとLEDがちらつくことがあります。点灯用と消灯用に別々のしきい値を使うと、すっきり解決できます。LDRのしくみはLDR光センサーの記事で解説しています。
条件を組み合わせる:「かつ」ブロックと&&
条件が1つでは足りないこともあります。HC-SR04で距離を測定(シリアルモニタ表示)プロジェクトでは、測った距離が3 cmから100 cmの間にあるときだけシリアルモニタに表示します。ブロックでは、2つの比較をかつブロックで横に並べてつなぎます。「distance > minDistance かつ distance < maxDistance」です。C++ではこの行はif (distance > minDistance && distance < maxDistance)になります。&&演算子は、両側がどちらも真のときだけ結果を真にします。どちらか一方でも偽なら条件は偽です。こうして、センサーの測定範囲外の意味のない値が画面に出ることはありません。C++では「または」は||と書き、どちらか1つの条件が真なら十分です。AND、OR、NOTの真理値表は論理ゲートツールで試せます。
ESP32での同じ条件:内部プルアップと反転した論理
ESP32でボタンによるLED制御(押している間だけ点灯)プロジェクトは、同じ「もし」ブロックをESP32で使いますが、違いが2つあります。LEDはGPIO 5、ボタンはGPIO 4につながっていて、ボタンのピンにはピン設定ブロックの「入力(PULLUP)」を選びます。C++ではpinMode(BUTTON_PIN, INPUT_PULLUP);です。チップ内部の抵抗がピンをHIGHに引き上げるので、外付けの抵抗は要りません。今回はボタンをGNDにつなぐため、押すとピンはLOWと読み取られ、条件は「ピン BUTTON_PIN を読み取る = LOW」になります。ESP32でボタンによるLED制御(トグル)プロジェクトは、オン/オフの切り替えを50 msの待ちではなく「起動からの経過ミリ秒」ブロック、つまりmillis()で行い、ここでも2つの条件を「かつ」ブロックでつなぎます。ESP32のピンは3.3 Vで動作するので、ボタンを5 Vにつながないでください。
よくあるミスと直し方
| ミス | 症状 | 対処 |
|---|---|---|
| プルダウン抵抗がない | LEDが勝手にちらつき、手を近づけると点灯する | D13とGNDの間に10 kΩを入れるか、INPUT_PULLUPを使って論理を反転させる |
| 条件の等号が1つ:if (button = 1) | LEDがボタンに関係なくずっと点灯する | 比較には==を使う |
| ifの行の末尾にセミコロン | 波かっこ内のコードが条件に関係なく毎回実行される | if (…)のあとの;を消す |
| ボタンの同じ側の足を使っている | ピンが常にHIGH、または常にLOWと読み取られる | 対角の足を使う |
| オン/オフ切り替えでlastButtonを更新していない、または待ちがない | 押し続けるとLEDが点滅する、または状態がランダムになる | lastButton = buttonと50 msの待ちを追加する |
| INPUT_PULLUPでHIGHを押した状態だと思い込む | LEDが逆に動作し、離すと点灯する | 内部プルアップでは、LOWが押した状態 |
| LDRのしきい値が部屋に合っていない | LEDがまったく点灯しない、または点灯したまま | シリアルモニタで値を確認し、しきい値を選び直す |
アプリでブロックとコードを並べて開く
この記事のプロジェクトはすべて、BlueGraysアプリの無料のブロック付きプロジェクトです。プロジェクトのコードの欄でブロックで表示のスイッチをオンにすると、コードの代わりに同じプログラムがブロックで表示されます。画像をタップすると全画面で開きます。ブロック解説タブでは、プログラムをステップごとに説明します。各ステップではそのステップのブロックと、その働きだけが表示されるので、入れ子の「もし」ブロックも1つずつ追いかけられます。コードガイドのif/elseとdigitalReadの例もブロックで表示されます。ブロックはボードに直接書き込まれるわけではなく、今のところブロックを並べて自分のプログラムを作ることもできません。いつもプロジェクトの実際のC++コードをArduino IDEにコピーして書き込みます。学んだことを復習したいなら、今日のクイズでA1からC2までのレベルの問題が毎日5問出題されます。
条件がわかったら、次のステップは繰り返しとカウンターの扱いです。ループと変数の回では、「ずっと繰り返す」とloop()の関係、「数える」ブロックとforループの関係を見ていきます。それまでは、BlueGraysアプリでボタンでLEDを点灯するプロジェクト、LDRで作る常夜灯、ESP32のボタンのプロジェクトの回路図とコードを確認し、ブロックで表示でブロック表示に、ブロック解説でステップごとの説明に切り替えてみてください。
よくある質問
ブロックプログラミングの「もし」ブロックは何をするものですか?
「もし」ブロックはプログラムに判断をさせます。条件が真なら「実行」の枝のブロックが、偽なら「そうでなければ」の枝のブロックが実行されます。Arduinoのプロジェクトでは、ボタンが押されているかどうかや、センサーの値がしきい値を超えたかどうかを調べるのによく使われます。C++ではif/else文にあたります。
Arduinoのifとelseの違いは何ですか?
ifは、かっこ内の条件が真のときに波かっこの中のコードを実行します。elseは省略でき、条件が偽のときだけ実行されるコードを入れます。elseがない場合、条件が偽なら何も起きず、プログラムは次の行に進みます。
Arduinoの=と==の違いは何ですか?
等号1つ(=)は変数に値を代入し、等号2つ(==)は2つの値を比較します。if (x = 1)と書くとxに1が代入され、条件は常に真になります。正しくはif (x == 1)です。ブロックでは、比較ブロックの「=」がコードでは==に変換されます。
ボタンを押していないのにArduinoのLEDが点灯するのはなぜですか?
ボタンのピンがフローティング状態、つまりプルダウン抵抗もプルアップ抵抗もない可能性が高いです。その場合、ピンは周囲のノイズを読み取り、ランダムにHIGHやLOWに見えます。ピンとGNDの間に10 kΩの抵抗を入れるか、pinMode(pin, INPUT_PULLUP)を使ってボタンをGNDにつないでください。
Arduinoでボタンを使ってLEDをオン/オフするには?
LEDの状態を1つの変数(ledState)に、ボタンの前回の読み取り値を別の変数(lastButton)に保存します。ボタンの状態が変わり、新しい状態が押された状態なら、ledState = !ledStateで状態を反転させ、digitalWriteでLEDに書き込みます。接点のチャタリングをやり過ごすために、50 msほどの短い待ちを入れます。ボタンでLEDの点灯・消灯を切り替えプロジェクトは、まさにこの処理をしています。
BlueGraysのブロックをArduinoに書き込めますか?
いいえ、ブロックがボードに直接書き込まれることはありません。ブロックはプロジェクトの実際のコードに1対1で対応していて、プログラムを理解するためのものです。いつもプロジェクトのC++コードをArduino IDEにコピーして、ボードに書き込みます。
この記事を読んだ後に作れるプロジェクト
全プロジェクトを見る
ボタンでLEDを点灯(押している間のみ)
呼び鈴のように、押している間は点灯し、離すと消灯します。Arduinoはボタンの状態を常に読み取り、押されている間はLEDを点灯させ、指を離した瞬間に消灯させます。このシンプルな回路で、ボードが外部からの操作を検知する仕組みを学べます。

ボタンでLEDの点灯・消灯を切り替え
部屋の照明スイッチのように、ボタンを1回押すと点灯し、もう1回押すと消灯します。Arduinoはボタンが押されるたびにLEDの状態を反転させます。ボタン内部の小さな接点の振動で誤動作しないよう、短い待ち時間も設けます。1つのボタンでオン・オフを切り替える、シンプルな仕組みです。

LDRで作る常夜灯
暗くなると自動で点灯し、朝になると消灯する小さな常夜灯です。光センサーが部屋の明るさを測定し、Arduinoが十分に暗くなったらLEDを点灯させ、明るくなったら消灯させます。街灯が夕方になると自動で点灯する仕組みも理解できます。

HC-SR04で距離を測定(シリアルモニタ表示)
HC-SR04センサーは、コウモリが暗闇で道を見つけるのと同じ仕組みで動作します。人には聞こえない音を出し、その反響を捉えて前方の物体までの距離を測ります。Arduinoは0.5秒ごとに距離をセンチメートル単位でコンピューターの画面に表示し、3〜100センチメートルの測定値を示します。駐車センサーや障害物を避けるロボットなどのプロジェクトの基礎になります。

ESP32でボタンによるLED制御(押している間だけ点灯)
ボタンを押している間はLEDが点灯し、離すと消灯します。ESP32のデジタル入力ピンと内蔵プルアップ抵抗の使い方を学びます。INPUT_PULLUPモードを使うため、外付け抵抗は不要です。

ESP32でボタンによるLED制御(トグル)
ボタンを押すたびにLEDの状態が切り替わり、点灯中なら消灯し、消灯中なら点灯します。基本的なトグル動作です。チャタリング対策でボタンの機械的なノイズを除去し、1回の操作で1回だけ切り替わるようにします。

LDRで光の強さを測定
部屋の明るさを数値で見てみませんか?光に反応する小さな部品、LDRで周囲の光を測定し、Arduinoが0.5秒ごとにその値をコンピューターの画面に表示します。手で覆うと数値が変わる様子を確認できます。自動で点灯する常夜灯などのプロジェクトへの第一歩です。

LEDの点滅
電子工作の第一歩は、1個のLEDを点けたり消したりすることです。Arduinoで短い間隔で点灯と消灯を繰り返すと、LEDが素早く点滅します。ボードが光を制御する仕組みを最もシンプルな形で確かめ、これから取り組むプロジェクトの基礎を身につけます。
ほかの記事
BlueGraysアプリ
この回路をスマホでステップごとに作る
回路図、コード、部品リストを1つの画面で確認できます。Arduino、ESP32、Picoのプロジェクトを200件以上用意しています。

