Подключение кнопки к Arduino: INPUT_PULLUP, дребезг и схема без лишних деталей
Кнопка это вторая деталь после светодиода, и именно на ней новички теряют вечер: «вроде нажимаю, а Serial печатает ерунду». Причин всего две: вход без подтяжки читает не кнопку, а воздух, а нажатия считаются по три раза из-за дребезга контактов. Обе лечатся схемой из одного провода и пары строк кода.
Разбираем схему кнопка и GND с внутренней подтяжкой, таблицу «нажата и отпущена» для INPUT_PULLUP, дребезг с честными миллисекундами и готовый скетч. Всё работает в симуляторе: кнопки там появляются сами, когда скетч вызывает digitalRead().
Отдельные разделы ниже отвечают на вопросы, которые возникают позже: почему кнопка работает через раз, сколько сигналов приходит на одно физическое нажатие, какую кнопку вообще стоит покупать и как проверить, что схема собрана правильно.
Опрос строк и столбцов: как подтяжки ловят нажатия и почему дребезг не страшен.
Подгружаем интерактив…
Схема с INPUT_PULLUP: одна кнопка и два провода
Вход микроконтроллера нельзя оставлять висящим в воздухе: он ловит наводки и читает случайные единицы. Подтяжка привязывает вход к земле или к питанию, а кнопка в свободном состоянии перекидывает его на противоположную сторону. У Uno есть встроенные подтяжки к питанию, и включаются они одной строкой: pinMode(2, INPUT_PULLUP). Провод от пина 2 к одной ноге кнопки и провод от другой ноги к GND это вся схема, никаких внешних резисторов не нужно.
| Состояние | digitalRead() | Почему |
|---|---|---|
| Кнопка отпущена | HIGH (1) | Внутренняя подтяжка тянет вход к 5 В |
| Кнопка нажата | LOW (0) | Пин соединён с GND, читаем землю |
Три схемы подключения: что выбрать
| Схема | Детали | Когда оправдана |
|---|---|---|
| INPUT_PULLUP, кнопка на GND | Кнопка и 2 провода | Стандарт: 99% проектов, детали не нужны |
| Внешний pull-up 10 кОм, кнопка на GND | Кнопка и резистор | Нужен именно высокий уровень в покое (чужой код, шина) |
| Pull-down 10 кОм, кнопка на 5 В | Кнопка и резистор | Когда логика «нажата = HIGH» уже зашита в код и не переписывается |
Внутренняя подтяжка ATmega328P это 20–50 кОм, и у неё есть цена: вход получается медленным, а длинный провод работает как антенна. В комнате это незаметно, но если кнопка стоит на столе, а плата в другой комнате, провод надо вести коротким и рядом с земляным. Надёжнее поставить внешний резистор 10 кОм: сигнал становится резче, а поведение предсказуемым. Второе отличие внешней подтяжки в том, что её номинал вы контролируете, а не оставляете на усмотрение производителя микросхемы.
Скетч: читаем кнопку без глюков
void setup() { pinMode(2, INPUT_PULLUP); Serial.begin(9600);} void loop() { if (digitalRead(2) == LOW) { Serial.println("nazhata"); delay(300); }}delay(300) это учебный костыль: скетч на треть секунды слепнет к миру и пропускает остальные события. Настоящее лечение дребезга и блокировки это millis-таймер, он разобран в уроке про дебаунс кнопки, а переключение «нажал, режим сменился, отпустил, и снова можно нажать» в уроке про кнопку-тумблер. Начало пути с кнопками это урок про digitalRead.
Дребезг: почему нажатий больше, чем было
Контакты механические, и при замыкании они пару миллисекунд дребезжат: сигнал скачет между нулём и единицей, пока контакт не «устаканятся». Цифровой вход успевает посчитать это как несколько нажатий, и в мониторе порта на одно физическое нажатие приходится несколько строк. Лечится программно: игнорировать изменения короче 20–50 мс, это и называется debounce. Второй способ аппаратный: конденсатор 100 нФ параллельно кнопке, он заряжается через сопротивление контактов и сглаживает фронт. Урок про дебаунс показывает millis-вариант без блокировки loop().
Тупик: кнопка нажимается, а Serial молчит
Первый наш опыт с кнопкой выглядел так: схема собрана по картинке, скетч залит, а в мониторе порта ничего. Мы проверяли провода, переставляли кнопку на другой пин, переписывали условие, перечитывали документацию про digitalRead. Казалось, что кнопка не работает вообще.
Дело было в двух словах в коде: pinMode(2, INPUT). С таким режимом вход болтается в воздухе и читает что попало, а если бы мы ещё и ждали HIGH, то ловили бы наводки вместо нажатий. Как только в строке режима INPUT поменяли на INPUT_PULLUP, а в условии HIGH на LOW, кнопка заработала с первого нажатия. С тех пор мы проверяем кнопку по порядку: сначала режим пина, потом инверсия логики, потом провода и только потом сам вывод.
Личный опыт: сколько сигналов приходит на одно нажатие
Дребезг мы оценивали не на глаз, а по монитору порта: ставили рядом с кнопкой счётчик и смотрели, сколько строк появляется за одно физическое нажатие. На стенде с тактовыми кнопками число скачков менялось от нажатия к нажатию, и это зависело от того, с какой силой и насколько быстро нажимали. Именно эта нестабильность и есть дребезг: он не имеет фиксированного числа импульсов.
После включения debounce по времени с окном 30 мс на одно нажатие приходила ровно одна строка. Мы выбрали 30 мс не потому, что это точное значение, а потому, что оно заведомо больше времени дребезга и при этом меньше времени, за которое человек успевает отпустить кнопку и нажать снова. Слишком большое окно даёт другой дефект: быстрые нажатия начинают теряться, и кнопка «не реагирует на быстрые клики». Ориентир такой: окно 20–50 мс для обычных кнопок, 5–10 мс для дорогих тактовых с хорошим механизмом.
Авторская позиция: какую кнопку взять
Берите обычные тактовые кнопки 6×6 мм с четырьмя выводами и припаивайте любую пару: внутри корпуса выводы попарно соединены, поэтому ножки напротив друг друга всегда имеют общий контакт, и ошибиться можно только если замкнуть ножки с разных сторон. Крупные кнопки 12×12 мм удобнее нажимать пальцем, но в макетку без переходной платы они не встают.
Отдельно про кнопки с фиксацией и о герметичных корпусах. Кнопка с фиксацией (такой форм-фактор есть у кнопок на панели) залипает в нажатом состоянии, для обычного меню она неудобна. Герметичные кнопки с резиновым колпачком нужны там, где вода и пыль, а колпачок добавляет свою упругость, которую тоже приходится учитывать в окне дебаунса. И ещё: покупайте кнопки партиями по десять штук. Они теряются, ломаются при пайке и заканчиваются именно тогда, когда проект уже написан.