ボタンで LED を操作する入力ピンとプルアップ、押すたびに切り替えるトグルとチャタリング対策
L チカの次は「入力」。ボタンの状態を GPIO で読み、押している間だけ LED を光らせ、次に押すたびに ON/OFF を切り替える(トグル)まで進めます。トグルで必ずぶつかるチャタリング対策も、ここで身につけます。
- ESP32-S3
- Raspberry Pi 5 8GB
- M5Stack CoreS3
CONTENTSこの記事の目次+
01 — WIRING
配線
ボタンは GPIO と GND の間に接続。内部プルアップをコードで有効化するため外付け抵抗は不要です。対角線の 2 本足を使います。
| ボード | ボタン | LED |
|---|---|---|
| ESP32-S3 | GPIO5 と GND | GPIO4 |
| Raspberry Pi 5 | GPIO27(物理 13)と GND(物理 14) | GPIO17(物理 11) |
| M5Stack CoreS3 | 画面下のタッチボタン BtnA。配線不要 | 画面の色で代用 |
02 — HOLD
押している間だけ光らせる
const int BUTTON_PIN = 5;
const int LED_PIN = 4;
void setup() {
pinMode(BUTTON_PIN, INPUT_PULLUP); // 内部プルアップを有効化
pinMode(LED_PIN, OUTPUT);
}
void loop() {
bool pressed = (digitalRead(BUTTON_PIN) == LOW); // 押すと LOW
digitalWrite(LED_PIN, pressed ? HIGH : LOW);
}from gpiozero import LED, Button
from signal import pause
led = LED(17)
button = Button(27) # 内部プルアップ有効。押すと GND
button.when_pressed = led.on
button.when_released = led.off
pause() # イベントを待ち続ける「押すと LOW」が最初は逆に感じますが、プルアップ入力の標準的な形です。== LOW の結果を pressed という名前にしておくと、以降のコードが読みやすくなります。
03 — TOGGLE
押すたびに切り替える(トグル)
「押している間」ではなく「押した瞬間」を検出する必要があります。前回の状態を覚えておき、HIGH → LOW に変わった瞬間だけ反応します(エッジ検出)。
const int BUTTON_PIN = 5;
const int LED_PIN = 4;
bool ledOn = false;
int lastState = HIGH;
void setup() {
pinMode(BUTTON_PIN, INPUT_PULLUP);
pinMode(LED_PIN, OUTPUT);
}
void loop() {
int state = digitalRead(BUTTON_PIN);
if (state == LOW && lastState == HIGH) { // HIGH → LOW = 押された瞬間
delay(30); // チャタリングが収まるのを待つ
if (digitalRead(BUTTON_PIN) == LOW) { // まだ押されていれば本物
ledOn = !ledOn;
digitalWrite(LED_PIN, ledOn);
}
}
lastState = digitalRead(BUTTON_PIN);
}from gpiozero import LED, Button
from signal import pause
led = LED(17)
button = Button(27, bounce_time=0.03) # 30ms のチャタリング対策
button.when_pressed = led.toggle
pause()#include <M5Unified.h>
bool on = false;
void setup() {
M5.begin();
}
void loop() {
M5.update();
if (M5.BtnA.wasPressed()) { // チャタリング対策済み
on = !on;
M5.Display.fillScreen(on ? TFT_GREEN : TFT_BLACK);
}
}04 — CHATTERING
チャタリングで何が起きるか
delay(30) と読み直しを消して試すと、1 回押しただけなのに LED が変わらない(2 回反応して元に戻る)ことがあります。これがチャタリング。接点が数ミリ秒バウンドして、押した瞬間に HIGH/LOW が何度も入れ替わります。
- ソフト対策:変化を検出したら 20〜50ms 待って読み直す(上のコード)
- 大きなプログラムでは
delayを使わずmillis()で時間を管理する。またはライブラリ(Arduino の Bounce2、M5Unified の Button)に任せる - ハード対策:ボタンと並列に 0.1μF のコンデンサ(→ コンデンサの基本)
05 — NEXT
発展
- 長押し検出:押されてから離されるまでの時間を
millis()で測り、1 秒以上なら別の動作 - 2 つのボタンで明るさを上下させる(→ PWM で明るさを変える)
- 割り込み
attachInterrupt(pin, 関数, FALLING)で、loop が忙しくても押下を取りこぼさない
06 — WATCH OUT
注意点
INPUT だけだと押していないときの値が決まりません。INPUT_PULLUP にします。
起動時の状態で動作モードが決まるピンです。起動時に押されていると立ち上がらないことがあります。
30ms なら気になりませんが、長い delay は他の処理(LED の点滅、通信)を止めます。
07 — CHECK YOURSELF
理解チェック
Q1押していないときに 1、押すと 0 になる配線の名前は?答えを見る
プルアップ(内部プルアップ)。押すと GND に落ちるので 0。
Q2トグルが「押しても変わらないことがある」。原因と対策は?答えを見る
チャタリングで 2 回検出されて元に戻っている。30ms 待って読み直す。
