ELECTRONICS

Кнопка и Arduino: схема подключения, INPUT_PULLUP и подавление дребезга

Клавиатуры и кнопкиСкетч проверен компиляцией

Тактовая кнопка — самая простая деталь в электронике: четыре ножки, внутри пружинящий контакт. Ножки соединены попарно, и нажатие замыкает эти пары между собой. Именно поэтому её вставляют в макетную плату поперёк канавки — иначе кнопка окажется закорочена сама на себя.

Несмотря на простоту, именно на кнопке новички спотыкаются чаще всего. Две причины: вход, оставленный без подтяжки, ловит наводки и срабатывает сам; а механические контакты дребезжат, и одно нажатие превращается в десяток.

Схема подключения

Наведите курсор на провод — расскажу, зачем он нужен.

Как устроены четыре ножки

ПроводКуда и зачем
Пара 1 (левая и правая)Соединены между собой всегда, даже когда кнопка не нажата. Это одна и та же точка цепи.
Пара 2 (левая и правая)Вторая такая же пара. Нажатие замыкает первую пару со второй.
ОриентацияНожки в паре смотрят в противоположные стороны корпуса. В макетную плату кнопку ставят поперёк канавки.

Характеристики

Типовой размер
6 × 6 мм, высота от 4 до 13 мм
Ресурс
от 100 тысяч нажатий
Длительность дребезга
5–20 мс
Питание
не требуется
Внешний резистор
не нужен при INPUT_PULLUP

INPUT_PULLUP: почему резистор не нужен

Вывод, к которому ничего не подтянуто, находится в неопределённом состоянии: он ловит наводки от рук, проводов и сети, и digitalRead возвращает случайные значения. Классическое решение — внешний резистор на десять килоом, подтягивающий вывод к питанию.

Внутри микроконтроллера такие резисторы уже есть, и включаются они одной строкой: pinMode с параметром INPUT_PULLUP. После этого в покое на входе единица, а нажатая кнопка притягивает его к земле и даёт ноль. Логика получается перевёрнутой — нажато значит LOW, — и это единственная плата за экономию детали.

Библиотека

не нужнаХватает digitalRead. Библиотеки вроде Bounce2 или GyverButton пригодятся, когда нужны двойные клики, удержание и обработка десятка кнопок сразу.

Готовый скетч

const int PIN_BUTTON = 2;
const int PIN_LED = 13;

const unsigned long DEBOUNCE_MS = 30;

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

void setup() {
  Serial.begin(9600);
  pinMode(PIN_BUTTON, INPUT_PULLUP);   // резистор внутри платы
  pinMode(PIN_LED, OUTPUT);
}

void loop() {
  bool state = digitalRead(PIN_BUTTON);

  // состояние изменилось — засекаем время и ждём, пока контакты успокоятся
  if (state != lastState) {
    lastChange = millis();
    lastState = state;
  }

  if (millis() - lastChange > DEBOUNCE_MS) {
    static bool stable = HIGH;

    if (state != stable) {
      stable = state;

      // реагируем только на момент нажатия, а не отпускания
      if (stable == LOW) {
        ledOn = !ledOn;
        digitalWrite(PIN_LED, ledOn);
        Serial.println(ledOn ? "Включено" : "Выключено");
      }
    }
  }
}

Скетч собирается arduino-cli под Arduino UNO

Здесь нет ни одного delay — программа не замирает в ожидании кнопки и может параллельно делать что-то ещё. Именно так подавляют дребезг в реальных проектах, а не задержкой в двести миллисекунд.

Частые ошибки

Кнопка срабатывает сама по себе

Забыт INPUT_PULLUP или внешний резистор. Вывод висит в воздухе и ловит наводки — иногда достаточно поднести руку.

Одно нажатие считается несколько раз

Дребезг контактов: они стучат от пяти до двадцати миллисекунд. Нужна выдержка по времени, как в скетче, — или delay, если проект простой.

Кнопка нажата всегда

Она вставлена в макетную плату вдоль канавки, а не поперёк. В таком положении соединены ножки одной пары, то есть цепь замкнута постоянно.

Логика кажется перевёрнутой

При INPUT_PULLUP нажатая кнопка даёт LOW, а не HIGH. Это не ошибка, а следствие подтяжки к питанию.

Светодиод мигает вместо переключения

Программа реагирует не на смену состояния, а на сам факт «кнопка нажата», и делает это в каждом проходе цикла — тысячи раз в секунду. Нужно ловить именно переход из отпущенного в нажатое.

Что понадобится