Управление светодиодом кнопкой на ESP32 (переключение)
При каждом нажатии кнопки состояние светодиода меняется: если горел — гаснет, если не горел — загорается. Классический шаблон переключения. Антидребезг убирает механический шум кнопки, чтобы одно нажатие давало одно переключение.

Видео
Схема

Исходный код
1// ─────────────────────────────────────────
2// BlueGrays · bluegrays.com
3// Управление светодиодом кнопкой на ESP32 (переключение)
4// ─────────────────────────────────────────
5// Каждое нажатие кнопки переключает светодиод: горел — гаснет, не горел —
6// загорается. Антидребезг 50 мс гарантирует, что одно нажатие даёт ровно
7// одно переключение.
8//
9// Пины:
10// GPIO 5 -> Красный светодиод (с резистором 220 ohm)
11// GPIO 4 -> Кнопка (другая ножка к GND)
12
13const int LED_PIN = 5; // Выход светодиода
14const int BUTTON_PIN = 4; // Вход кнопки
15
16bool ledState = false; // Горит ли светодиод сейчас
17bool lastButton = HIGH; // Предыдущее чтение кнопки
18bool stableButton = HIGH; // Устойчивое (без дребезга) состояние кнопки
19unsigned long lastChange = 0; // Время последнего изменения показания (мс)
20const unsigned long DEBOUNCE = 50; // Время антидребезга (мс)
21
22void setup() {
23 pinMode(LED_PIN, OUTPUT);
24 pinMode(BUTTON_PIN, INPUT_PULLUP); // Без нажатия читается HIGH
25}
26
27void loop() {
28 bool buttonState = digitalRead(BUTTON_PIN);
29
30 // Перезапускать таймер при каждом изменении показания
31 if (buttonState != lastButton) lastChange = millis();
32
33 // Показание, которое не меняется DEBOUNCE мс, считается устойчивым. Светодиод переключается один
34 // раз, только когда устойчивое состояние становится LOW (новое нажатие).
35 if (millis() - lastChange > DEBOUNCE && buttonState != stableButton) {
36 stableButton = buttonState;
37 if (stableButton == LOW) {
38 ledState = !ledState;
39 digitalWrite(LED_PIN, ledState);
40 }
41 }
42 lastButton = buttonState;
43}
44
Частые вопросы
Какой должна быть длительность антидребезга?
Для большинства кнопок достаточно 20–50 ms. Если пауза слишком короткая, дребезг всё равно будет замечен; если слишком длинная, быстрые нажатия подряд будут пропадать.
Какой момент ловить для переключения?
Лови только момент «нажатия» (переход из HIGH в LOW при INPUT_PULLUP). Чтобы светодиод не переключался снова и снова, пока кнопка зажата, храни прежнее состояние кнопки в переменной.
Правильно ли использовать `delay()` для антидребезга?
Для простых проектов работает, но delay() приостанавливает текущее выполнение loop(), задерживая другие операции в том же потоке. Другие задачи на ESP32 при этом могут выполняться. Отсчёт времени на millis() подходит, чтобы выполнять операции в loop() без блокировки.
Может ли светодиод помнить последнее состояние после выключения и включения?
Да, на ESP32 можно с помощью библиотеки Preferences записывать состояние в энергонезависимую память и читать его при запуске. Тогда даже после отключения и возврата питания светодиод начнёт с последнего состояния.
