Arduino для начинающих. Урок 2. Подключение кнопки


Кнопка является простейшим устройством, при помощи которого можно управлять ходом программы на микроконтроллере, но физически она выполняет очень простую функцию: замыкает и размыкает контакт. Кнопки бывают нескольких типов:
  • С фиксацией – кнопка остаётся нажатой после отпускания, без фиксации – отключается обратно.
  • Нормально разомкнутая (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):

void setup() { Serial.begin(9600); pinMode(3, INPUT_PULLUP); } void loop() { // выведет 0, если кнопка нажата // и 1, если нет Serial.println(digitalRead(3)); delay(10); }

Программа для кнопки-триггера

Еще один пример, заслуживающий внимания — кнопка-триггер. Работает она так: один раз нажали кнопку — светодиод загорелся, второй раз нажали — потух.

Чтобы реализовать такое поведение кнопки, нам потребуется дополнительная переменная, которую часто называют «переменной состояния» или «флагом».

const int led = 2; const int button = 3; int val = 0; byte state = 0; // переменная состояния void setup(){ pinMode( led, OUTPUT ); pinMode( button, INPUT ); } void loop(){ // записываем в переменную val состояние кнопки val = digitalRead( button ); // если состояние кнопки — истина, выполняем действие if( val == HIGH ){ // меняем состояние на противоположное state = !state; if( state == HIGH ){ // если текущее состояние — истина, зажигаем светодиод digitalWrite( led, HIGH ); } else { // если текущее состояние — ложь, гасим светодиод digitalWrite( led, LOW ); } delay( 300 ); } }

Загружаем программу на Ардуино и проверяем работу схемы. Быстро нажмем кнопку — светодиод зажжется. Снова нажмем — погаснет. А вот если нажать кнопку и не отпускать, то светодиод начнет мигать с периодом 600мс! Почему так? Попробуйте разобраться.

Алгоритмы

Отработка нажатия

В большинстве реальных применений работать с текущим состоянием кнопки очень неудобно, например когда действие должно быть выполнено однократно при нажатии на кнопку, т.е. по клику. Чуть усложним конструкцию, добавив один флаг, который будет помнить состояние кнопки. Такая конструкция позволяет отслеживать нажатие и отпускание кнопки и реагировать на них однократно:

void setup() { Serial.begin(9600); pinMode(3, INPUT_PULLUP); } bool flag = false; void loop() { // читаем инвертированное значение для удобства bool btnState = !digitalRead(3); if (btnState && !flag) { // обработчик нажатия flag = true; Serial.println(«press»); } if (!btnState && flag) { // обработчик отпускания flag = false; //Serial.println(«release»); } }

Дребезг контактов

Кнопка не идеальна, и контакт замыкается не сразу, какое-то время он “дребезжит”. Прогоняя данный алгоритм, система опрашивает кнопку и условия приблизительно за 6 мкс, то есть кнопка опрашивается 166’666 раз в секунду! Этого достаточно, чтобы получить несколько тысяч ложных срабатываний.


Избавиться от дребезга контактов можно как аппаратно, так и программно: аппаратно задача решается при помощи RC цепи, то есть резистора (~1-10k) и конденсатора (~100nF). Выглядит это следующим образом:

Программно можно ввести простейший таймер нажатия, основанный на millis(), время гашения дребезга примем 100 миллисекунд. Вот так будет выглядеть код:

void setup() { Serial.begin(9600); pinMode(3, INPUT_PULLUP); } bool flag = false; uint32_t btnTimer = 0; void loop() { // читаем инвертированное значение для удобства bool btnState = !digitalRead(3); if (btnState && !flag && millis() — btnTimer > 100) { flag = true; btnTimer = millis(); Serial.println(«press»); } if (!btnState && flag && millis() — btnTimer > 100) { flag = false; btnTimer = millis(); //Serial.println(«release»); } }

Рекомендуется конечно же использовать аппаратный способ, так как он не нагружает ядро лишними расчетами. В 99.99% проектов будет достаточно программного антидребезга, так то смело используйте конструкцию с millis().

“Импульсное” удержание

В устройствах с управлением кнопкой очень часто бывает нужна возможность изменения значения как однократно кликом по кнопке, так и “автоматически” с тем же шагом – при удержании. Такой вариант реализуется очень просто, добавлением ещё одного условия в наш предыдущий алгоритм, а именно: если кнопка была нажата, но ещё не отпущена, и прошло времени больше, чем задано – условие вернёт true. В примере ниже периодичность “нажатий” при удержании настроена на 500 миллисекунд (2 раза в секунду):

void setup() { Serial.begin(9600); pinMode(3, INPUT_PULLUP); } bool flag = false; uint32_t btnTimer = 0; void loop() { // читаем инвертированное значение для удобства bool btnState = !digitalRead(3); if (btnState && !flag && millis() — btnTimer > 100) { flag = true; btnTimer = millis(); Serial.println(«press»); } if (btnState && flag && millis() — btnTimer > 500) { btnTimer = millis(); Serial.println(«press hold»); } if (!btnState && flag && millis() — btnTimer > 500) { flag = false; btnTimer = millis(); //Serial.println(«release»); } }

Пользоваться таким кодом напрямую будет неудобно, поэтому можно “обернуть” его в класс (читай урок про классы и урок про написание библиотек).

Простейший класс кнопки

Вот так предыдущий пример можно сделать классом (мы делали это вот в этом уроке), положить его в отдельный файл (button.h) и пользоваться:

button.h

class button { public: button (byte pin) { _pin = pin; pinMode(_pin, INPUT_PULLUP); } bool click() { bool btnState = digitalRead(_pin); if (!btnState && !_flag && millis() — _tmr >= 100) { _flag = true; _tmr = millis(); return true; } if (!btnState && _flag && millis() — _tmr >= 500) { _tmr = millis (); return true; } if (btnState && _flag) { _flag = false; _tmr = millis(); } return false; } private: byte _pin; uint32_t _tmr; bool _flag; };

И пример с этой “библиотекой”: // файл лежит в одной папке со скетчем #include «button.h» button btn1(3); // указываем пин button btn2(4); void setup() { Serial.begin(9600); } void loop() { // метод click() «срабатывает» однократно при клике // и импульсно при удержании if (btn1.click()) Serial.println(«press 1»); if (btn2.click()) Serial.println(«press 2»); }

Другие возможности кнопки

Кнопка только с виду кажется простым устройством, дающим 0 и 1, но, подключив фантазию и время, можно придумать гораздо больше применений обычной кнопке. В моей библиотеке GyverButton реализовано очень много всяких интересных возможностей по работе с кнопкой, вот список:

  • Работа с нормально замкнутыми и нормально разомкнутыми кнопками
  • Работа с подключением PULL_UP и PULL_DOWN Опрос кнопки с программным антидребезгом контактов (настраиваемое время)
  • Отработка нажатия, удерживания, отпускания, клика по кнопке (+ настройка таймаутов)
  • Отработка одиночного, двойного и тройного нажатия (вынесено отдельно)
  • Отработка любого количества нажатий кнопки (функция возвращает количество нажатий)
  • Функция изменения значения переменной с заданным шагом и заданным интервалом по времени
  • Возможность работы с “виртуальными” кнопками (все возможности библиотеки используются для матричных и резистивных клавиатур)

Подробное описание библиотеки можно почитать в заголовочном файле на странице библиотеки, также там есть много примеров.

Как отличаются выключатели по конструкции и способу монтажа

Кроме функционала электровыключатели разнятся по конструкции и способу монтажа. Это влияет на сложность установки и место эксплуатации.

Наружные выключатели

Такие выключатели располагаются на поверхности стены. Проводка может быть наружной (чаще всего) или внутренней. Монтаж простой, поскольку не требуется высверливать отверстие для коробок выключателей. Используются там, где нет возможности углубить корпус выключателя или в качестве временного коммутатора.


Наружный выключатель.

Встраиваемые выключатели

Для монтажа в стене выполняется крупное отверстие. В образованную полость вставляется корпус выключателя так, чтобы он был заподлицо с поверхностью или немного выступал над ней. Это обеспечивает более аккуратный вид и за такой выключатель невозможно случайно зацепиться одеждой. Однако такая установка предусматривает скрытый монтаж проводки и подготовку отверстий для коробок в которые устанавливаются выключатели.


Встраиваемый выключатель.

Герметичные выключатели

Такие устройства защищены от влаги и пыли. В зависимости от степени защиты они обозначаются буквами IP с определенными значениями. Предназначены такие выключатели для установки в помещения с повышенным уровнем влаги, пыли, брызгами жидкости и т. д. Обеспечивают безопасность, надежно изолируя контакты от проникновения воды. Для установки в санузлах класс защиты выключателя должен быть не менее IP-44.

Если вы заметили ошибку, не рабочее видео или ссылку, пожалуйста, выделите фрагмент текста и нажмите Ctrl+Enter.

0

Важные страницы

  • Набор GyverKIT – большой стартовый набор Arduino моей разработки, продаётся в России
  • Каталог ссылок на дешёвые Ардуины, датчики, модули и прочие железки с AliExpress у проверенных продавцов
  • Подборка библиотек для Arduino, самых интересных и полезных, официальных и не очень
  • Полная документация по языку Ардуино, все встроенные функции и макросы, все доступные типы данных
  • Сборник полезных алгоритмов для написания скетчей: структура кода, таймеры, фильтры, парсинг данных
  • Видео уроки по программированию Arduino с канала “Заметки Ардуинщика” – одни из самых подробных в рунете
  • Поддержать автора за работу над уроками
  • Обратная связь – сообщить об ошибке в уроке или предложить дополнение по тексту ([email protected])

5 / 5 ( 12 голосов )

Принцип действия


Принцип действия переключателя
Чтобы понять, что такое переключатель, требуется рассмотреть принцип его работы и назначение. Устройство служит для перенаправления потока электричества на другую цепь – одна цепь разъединяется и одновременно замыкается другая. Поэтому минимальное количество контактов для такого прибора – три. Для механизмов с двумя и более «клавишами» число удваивается.

Переключатель – это коммутатор между электрическими проводниками реверсного напряжения. Назначение – управление одним источником света из разных мест. В основном используют для помещений со значительной площадью, например, стадионы, производственные цеха или склады.

Рейтинг
( 1 оценка, среднее 5 из 5 )
Понравилась статья? Поделиться с друзьями:
Для любых предложений по сайту: [email protected]