Подключение кнопки к Arduino
Когда вы только начинаете знакомство с Arduino, то вашей первой схемой, скорее всего, будет подключение светодиода к плате и его мигание на той частоте, которую вы укажете в программном коде. А что делать, если хочется включать/выключать светодиод (или иначе говоря, подавать максимальные 5 вольт с платы) при механическом нажатии, как в выключателе в наших домах?
На помощь придет обычная тактовая кнопка, которая поможет ознакомиться с этим базовым процессом, поэтому данная статья больше подходит для самых маленьких. Но обо всем по порядку.
Тактовая кнопка представляют собой простейшее устройство, которое позволяет человеку напрямую влиять на электрическую схему. Нажатие на нее приводит к замыканию или размыканию цепи соответственно.
Для удобства подключения кнопки в цепь, к примеру, состоящую из светодиода, обычно выгодно использовать небольшую макетную плату. И еще для соединения необходимо использовать так называемый стягивающий резистор. Для чего это нужно?
Дело в том, что кнопка позволяет управлять двумя логическими значениями цифрового выхода на плате Arduino, а именно: логический ноль и логическая единица.
Если подключить кнопку напрямую без резистора, то при нажатии на нее с целью разомкнуть цепь и погасить светодиод, все равно может возникнуть напряжение, и светодиод будет включаться/выключаться хаотично (по-другому это еще называется дребезгом кнопки).
Это связано с тем, что вокруг проводников образуются шумы и по их причине может возникнуть новое электрическое поле. При подключении резистора, любой случайный и лишний ток будет уходить в землю.
Номинал резистора желательно взять в 10 кОм, и также не забудьте, что ток к светодиоду идет через отдельный резистор в 220 Ом
Схема подключения кнопки к плате, включая стягивающий резистор, изображена ниже:
Работа с кнопками
Кнопка является простейшим устройством, при помощи которого можно управлять ходом программы на микроконтроллере, но физически она выполняет очень простую функцию: замыкает и размыкает контакт. Кнопки бывают нескольких типов:
- С фиксацией – кнопка остаётся нажатой после отпускания, без фиксации – отключается обратно.
- Нормально разомкнутая (Normal Open, NO) – при нажатии замыкает контакты. Нормально замкнутая (Normal Closed, NC) – при нажатии размыкает контакты.
- Тактовые кнопки – замыкают или размыкают контакт. У обычных тактовых кнопок ноги соединены вдоль через корпус (см. картинку ниже). Переключатели – обычно имеют три контакта, общий COM, нормально открытый NO и нормально закрытый NC. При отпущенной кнопке замкнута цепь COM-NC, при нажатой замыкается COM-NO.
Подключение и подтяжка
Из урока про цифровые пины вы помните, что микроконтроллер может считывать напряжение со своей ноги. Соответственно кнопка может подать на пин тот уровень, к которому подключена её вторая нога. В том же уроке мы обсуждали, что не подключенный никуда цифровой пин принимает наводки из воздуха, и считанное с него значение будет практически случайным. То есть подключив к пину 5V (сигнал высокого уровня) через кнопку, мы ничего не добьёмся: при нажатой кнопке на пине будет считываться четкий сигнал высокого уровня, а при отпущенной – случайное значение. Для решения этой проблемы существует такое понятие, как подтяжка (pull) пина. Подтяжка выполняется к земле (pull down) или питанию (pull up) микроконтроллера при помощи резистора. Подтяжка выполняется противоположно принимаемому сигналу, т.е. если нужно ловить высокий сигнал, подтяжка выполняется к земле, если ловить нужно сигнал земли – подтяжка выполняется к питанию. Вот два варианта подключения кнопки, с подтяжкой к VCC и GND соответственно: Как выбирается сопротивление резистора? Тут всё очень просто: при нажатии на кнопку через резистор потечёт ток, так как в любом случае замыкается цепь питание-земля. Чем выше ток, больше потери энергии и нагрев резистора, а это никому не нужно, поэтому сопротивление резистора подтяжки обычно выбирается в диапазоне 5-50 кОм. Если ставить больше – подтяжка может не обеспечить стабильный уровень сигнала на пине, а если ставить меньше – будут больше потери энергии в нагрев резистора: при сопротивлении в 1 ком через него потечёт ток величиной 5 В/1000 Ом = 5 мА, для сравнения плата Ардуино с МК в активном режиме потребляет 20-22 мА. Чаще всего для подтяжки используется резистор на 10 кОм. Как вы помните из урока о цифровых пинах, у МК AVR есть встроенные резисторы для всех GPIO, эти резисторы подключены к питанию (к VCC), то есть буквально дублируют первую схему из этого урока и позволяют не использовать внешний резистор. У микроконтроллеров другой архитектуры бывает подтяжка к GND, или вообще может не быть внутренней подтяжки. При использовании подтяжки к питанию мы получим инвертированный сигнал – функция digitalRead() вернёт 1 при отпущенной кнопке, и 0 при нажатой (при использовании нормально-разомкнутой кнопки). Давайте подключим кнопку на пин D3 (и GND):
Алгоритмы
Отработка нажатия
В большинстве реальных применений работать с текущим состоянием кнопки очень неудобно, например когда действие должно быть выполнено однократно при нажатии на кнопку, т.е. по клику. Чуть усложним конструкцию, добавив один флаг, который будет помнить состояние кнопки. Такая конструкция позволяет отслеживать нажатие и отпускание кнопки и реагировать на них однократно:
Дребезг контактов
Кнопка не идеальна, и контакт замыкается не сразу, какое-то время он “дребезжит”. Прогоняя данный алгоритм, система опрашивает кнопку и условия приблизительно за 6 мкс, то есть кнопка опрашивается 166’666 раз в секунду! Этого достаточно, чтобы получить несколько тысяч ложных срабатываний. Избавиться от дребезга контактов можно как аппаратно, так и программно: аппаратно задача решается при помощи RC цепи, то есть резистора (
1-10k) и конденсатора (
100nF). Выглядит это следующим образом:
Программно можно ввести простейший таймер нажатия, основанный на millis() , время гашения дребезга примем 100 миллисекунд. Вот так будет выглядеть код:
Рекомендуется конечно же использовать аппаратный способ, так как он не нагружает ядро лишними расчетами. В 99.99% проектов будет достаточно программного антидребезга, так то смело используйте конструкцию с millis() .
“Импульсное” удержание
В устройствах с управлением кнопкой очень часто бывает нужна возможность изменения значения как однократно кликом по кнопке, так и “автоматически” с тем же шагом – при удержании. Такой вариант реализуется очень просто, добавлением ещё одного условия в наш предыдущий алгоритм, а именно: если кнопка была нажата, но ещё не отпущена, и прошло времени больше, чем задано – условие вернёт true . В примере ниже периодичность “нажатий” при удержании настроена на 500 миллисекунд (2 раза в секунду):
Пользоваться таким кодом напрямую будет неудобно, поэтому можно “обернуть” его в класс (читай урок про классы и урок про написание библиотек).
Простейший класс кнопки
Вот так предыдущий пример можно сделать классом (мы делали это вот в этом уроке), положить его в отдельный файл (button.h) и пользоваться:
Другие возможности кнопки
Кнопка только с виду кажется простым устройством, дающим 0 и 1, но, подключив фантазию и время, можно придумать гораздо больше применений обычной кнопке. В моей библиотеке GyverButton реализовано очень много всяких интересных возможностей по работе с кнопкой, вот список:
- Работа с нормально замкнутыми и нормально разомкнутыми кнопками
- Работа с подключением PULL_UP и PULL_DOWN Опрос кнопки с программным антидребезгом контактов (настраиваемое время)
- Отработка нажатия, удерживания, отпускания, клика по кнопке (+ настройка таймаутов)
- Отработка одиночного, двойного и тройного нажатия (вынесено отдельно)
- Отработка любого количества нажатий кнопки (функция возвращает количество нажатий)
- Функция изменения значения переменной с заданным шагом и заданным интервалом по времени
- Возможность работы с “виртуальными” кнопками (все возможности библиотеки используются для матричных и резистивных клавиатур)
Подробное описание библиотеки можно почитать в заголовочном файле на странице библиотеки, также там есть много примеров.
Аналоговые клавиатуры
Аналоговые клавиатуры – достаточно глубокая тема, достойная отдельного урока (у меня его пока что нет). Максимально подробный урок-исследование можно посмотреть на сайте Codius.
Видео
Arduino: Дребезг — программное и аппаратное устранение
Для того, чтобы понять, что такое дребезг, соберем очень простую схему с Arduino, кнопкой и светодиодом. При нажатии на кнопку светодиод должен загораться, если он не горит. При следующем нажатии на кнопку светодиод должен гаснуть. Схема подключения:
После сборки схемы и заливки скетча, можно убедиться в том, что схема работает не так, как задумывалось — светодиод загорается и гаснет не всегда предсказуемым образом. Почему так происходит? Ответ на этот вопрос даст осциллограф, подключенный к 8 пину Arduino и земле GND .
На самом деле смыкание-размыкание контактов кнопки в реальном мире немного отличается от того, как этого бы хотелось:
Это подтверждают данные осциллографа DSO 138:
Логический анализатор Saleae Logic 16 нагляднее отображает дребезг из-за большей частоты сэмплирования:
Итак, дребезг контактов ( англ. bounce — дребезг, debounce — устранение дребезга) — явление, происходящее в электромеханических коммутационных устройствах, длящееся некоторое время после замыкания электрических контактов и состоящее из многократных неконтролируемых замыканий и размыканий контактов, обусловленных упругостью материалов и деталей контактной системы — некоторое время контакты « подпрыгивают» при соударениях, размыкая и замыкая электрическую цепь.
Но с этим вредным явлением можно справиться. При чем, это можно сделать 2 путями — программно и аппаратно ( на уровне железа).
Программное устранение дребезга.
Для программного устранения дребезга, достаточно после первого изменения состояния кнопки, установить паузу в несколько милисекунд, для того чтобы контакт стабилизировался и дребезг был проигнорирован. Для этого дополним код функцией debounce() :
После добавления функции, стабилизирующей состояние кнопки, дребезг игнорируется.
Аппаратное устранение дребезга.
Аппаратное устранение дребезга в подавляющем большинстве случаев более предпочтительно программному, по ряду причин:
- аппаратная реализация всегда более надежна,
- высвобождаются ресурсы процессора из-за отсутствия необходимости дополнительных вычислений,
- уменьшается объем кода и упрощается процесс отладки.
Начнем с рассмотрения RC-цепочки — последовательного включения в цепь резистора ( 10 КОм) и конденсатора ( 10 мкФ):
Время, численно равное произведению RC, называется постоянной времени цепи RC и обозначается τ ( не путать с временем заряда конденсатора $t$).
При замкнутой цепи и заряде конденсатора, напряжение $U_с$ на его выводах будет увеличиваться от нуля до значения $U=5 В$ по экспоненте:
Из формулы $(1)$ можно выявить следующие закономерности ( выделены на графике):
- за время τ ( $t=RC$) происходит заряд конденсатора на 63,2% ( $U_c = U(1 — e^<-1>)= U(1 — <1\over
>)$ ) - за время 3τ происходит заряд конденсатора на 95% ( $U_c = U(1 — e^<-3>)= U(1 — <1\over
>)$ ) - за время 5τ происходит заряд конденсатора на 99% ( $U_c = U(1 — e^<-5>)= U(1 — <1\over
>)$ )
В нашем примере время зарядки конденсатора составит $10КОм \times 10мкФ = 0.1 сек$.
Исходя из этих данных необходимо подбирать номиналы резистора и конденсатора.
Для аппаратного устранения дребезга придется изменить принципиальную электрическую схему. В первую очередь необходимо резистор сделать не стягивающим, а подтягивающим, а во-вторых, параллельно с выводами кнопки, установить конденсатор. Он уберет дребезг:
Теперь в состоянии покоя на 8 пине будет 5 В, в случае нажатия на кнопку, произойдет разряд конденсатора:
После того, как кнопка будет отпущена, конденсатор начнет заряжаться за время 5τ.:
Теперь необходимо дополнить схему дополнительным резистором R2 ( он сделает работу схемы стабильнее — разрядка конденсатора будет происходить медленнее, скорость разряда зависит от номинала резистора) и инвертирующим триггером Шмитта — 74HC14N.
Основными особенностями инвертирующего триггера Шмитта являются:
- инвертирование входящего сигнала,
- преобразование аналогового сигнала в « цифровой».
Устранение дребезга на аналоговом входе
Данная ситуация отличается от вышеописанных и встречается в схемах подключения нескольких кнопок к одному аналоговому входу. Разница заключается в том, что интерпретация нажатия кнопки происходит путем вызова функции analogRead() , которая запускает механизм преобразования АЦП. И его погрешность не даст воспользоваться обычным ожиданием того момента, когда дребезг пройдет. Для устранения дребезга АЦП можно фиксировать приходящие значения и когда придет, например, 5-10 одинаковых значений можно говорить о нажатии кнопки. Но поскольку АЦП тоже имеет погрешность этот путь не очень эффективен. Эффективность метода можно повысить путем преобразования полученных данных в идентификатор кнопки, путем сравнения полученного значения с эталонным, скорректированным на допуск. И уже фиксировать полученные значения идентификатора кнопки. Таким образом погрешность АЦП будет нивелирована.
Этот метод использован в коде примера №2 статьи Arduino: Подключение нескольких кнопок к одному аналоговому входу. Схема подключения оттуда же: