Кнопка и 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. Это не ошибка, а следствие подтяжки к питанию.
Светодиод мигает вместо переключения
Программа реагирует не на смену состояния, а на сам факт «кнопка нажата», и делает это в каждом проходе цикла — тысячи раз в секунду. Нужно ловить именно переход из отпущенного в нажатое.
Что понадобится
- Тактовая кнопка 6×6 мм
- Arduino UNO
- Провода «папа-папа»
- Макетная плата