← До всіх проєктів
Основи Початковий

Кнопка на ESP32: INPUT_PULLUP, антидребезг і перемикання світлодіода

Кнопка без жодних резисторів завдяки внутрішній підтяжці, чому контакти «деренчать» і як програмно відрізнити одне натискання від двадцяти. Одне натискання — світлодіод увімкнено, наступне — вимкнено.

Складність
Початковий
Час
30 min
Категорія
Основи
Оновлено

Про проєкт

Кнопка — найпростіший вхід, але саме тут з'являються два підступні ефекти: «плаваючий» вхід і брязкіт контактів. Зберемо перемикач: одне натискання вмикає світлодіод, наступне вимикає.

Що знадобиться

  • ESP32 DevKit
  • Тактова кнопка 6×6 мм
  • Світлодіод і резистор 220 Ом
  • Макетна плата й перемички

Схема

Деталь Підключення
Кнопка один контакт → GPIO4, інший → GND
Світлодіод GPIO23 → резистор 220 Ом → анод; катод → GND

Зовнішній резистор для кнопки не потрібен: використаємо вбудовану підтяжку.

Чому вхід «плаває»

Коли кнопку відпущено, GPIO4 не з'єднаний ні з чим. Такий вхід ловить наводки від руки чи сусідніх проводів і читається то як 0, то як 1. Рішення — підтягувальний резистор до 3.3 В: у спокої він тримає вхід у HIGH, а натиснута кнопка замикає його на землю і дає LOW.

В ESP32 такий резистор (~45 кОм) уже вбудовано, його вмикає pinMode(pin, INPUT_PULLUP). Звідси «інверсна» логіка: натиснуто = LOW.

GPIO34–39 не мають внутрішніх підтяжок і працюють лише як входи. Для кнопок на цих виводах потрібен зовнішній резистор 10 кОм.

Брязкіт контактів

Механічні контакти не замикаються одразу: протягом 1–10 мс вони кілька разів підскакують. Без захисту одне натискання перетворюється на кілька перемикань, і світлодіод вмикається та одразу вимикається.

Антидребезг ігнорує зміни, що сталися раніше ніж через 30 мс після попередньої. Час беремо з millis(), а не з delay(), тож loop() не блокується.

Код

// Кнопка перемикає світлодіод: INPUT_PULLUP + антидребезг
const int BUTTON_PIN = 4;
const int LED_PIN = 23;

bool ledOn = false;
int lastState = HIGH;
unsigned long lastChange = 0;

void setup() {
  Serial.begin(115200);
  pinMode(BUTTON_PIN, INPUT_PULLUP);   // натиснуто = LOW
  pinMode(LED_PIN, OUTPUT);
}

void loop() {
  int state = digitalRead(BUTTON_PIN);
  if (state != lastState && millis() - lastChange > 30) {   // антидребезг
    lastChange = millis();
    lastState = state;
    if (state == LOW) {   // реагуємо лише на момент натискання
      ledOn = !ledOn;
      digitalWrite(LED_PIN, ledOn ? HIGH : LOW);
      Serial.printf("Світлодіод %s\n", ledOn ? "УВІМК" : "ВИМК");
    }
  }
}

Типові помилки

  • INPUT замість INPUT_PULLUP без зовнішнього резистора: вхід плаває, і симулятор про це попередить.
  • Кнопка між 3.3 В і GND без резистора: натискання замикає живлення накоротко.
  • Кнопка на GPIO0, GPIO2 чи GPIO12, затиснута під час увімкнення, змінює режим завантаження ESP32.

Що далі

  • Розпізнавайте довге натискання: якщо LOW тримається понад 1 с, робіть іншу дію.
  • Коли кнопок стане кілька, винесіть антидребезг в окремий клас, як у статті «Класи C++: Led і Button».