Существует известная многим хоббистам проблема: если uK (микроконтроллер) в процессе работы должен опрашивать клавиши, то возникает ситуация, когда он либо всё своё время тратит на эти кнопки, ожидая нажатий, либо работает рывками: пока он занят чем-то, кнопки он не “слышит”.
Эта проблема имеет изящное решение, которое наверняка хорошо известно специалистам, но совершенно не встречается в хоббийной среде.
Если Вы программируете небольшие устройства для своего удовольствия, предлагаемое дальше решениие может показаться Вам полезным, чтобы сделать свой продукт более качественным.
Общая идея клавиатуры для Arduino показана на схеме для макетирования:
Объясню на пальцах:
pinMode(BUTTONPIN, INPUT_PULLUP);
У вас будет один “особый” ввод на микроконтроллере, который будет задействован для формирования аппаратного прерывания, когда одна или несколько кнопок будут нажаты. Поэтому на один из пинов, которые разрешают аппаратные прерывания вы навешиваете все кнопки, используя обычные выпрямительные диоды. Этот пин также следует внутрисистемно подтянуть к питанию, как и кнопочные выводы. Также, нам следует навесить обработчик прерываний на этот общий, для всех вход:
pinMode(INT0PIN, INPUT_PULLUP)
cli();
attachInterrupt(0, keypadInterrupt, CHANGE);
sei();
В коде скетча следует включить библиотеку ArduinoButtons которую я написал специально, чтобы облегчить использование метода.
В коде скетча, в блоке, где вы будете делать все объявления глобальных переменных следует добавить:
#include "Buttons.h"
Buttons buttons;
//обработчик прерывания от кнопок
void keypadInterrupt(void) {
buttons.processIt();
}
а также определить методы, которые будут делать что-то, когда нажата (или отпущена) соответствующая кнопка:
void OnButtonRelease() {
// делаем здесь что-либо полезное
}
void OnButtonRelease() {
// делаем здесь что-либо полезное
}
Теперь главное. В методе setup
вам следует указать обработчики нажатия интересующей вас кнопки:
buttons.AddEventListener(BUTTONPIN, OnButtonPress, OnButtonRelease);
Такие обработчики следует навесить на все кнопки: они могут быть общими или отдельными. Они могут быть перегружены в процессе работы программы.
Метод loop
также должен содержать один вызов buttons.processIt();
. Это нужно для того, чтобы uK мог опросить кнопки в момент, когда ему удобно и отловить “пропущенные” обработчиком прерываний состояния кнопок.
Работает это следующим образом. Класс Buttons содержит методы и структуры данных, которые хранят информацию о выводах, которые вы ассоциировали с кнопками и ссылки на методы-обработчики событий для каждой из кнопок.
Библиотеки Arduino работают с вводом/выводом медленно. Однако, сама архитектура библиотеки такова, что Вы наверняка не заметите этой медленности.
Когда все кнопки отжаты, входы находятся в “высоком” состоянии. Как только какая-либо кнопка (одна или несколько) нажимаются, соответствующий ей ввод контроллера, а также общий ввод, настроенный на обработку прерывания переходят в “низкое” состояние. Обработчик прерывания вызывает чтение кнопок. И, если состояние какой-либо из них изменилось, то он инициирует вызов соответствующего метода.
Не нужно предупреждать никого, что эти методы должны быть как можно более быстрыми. Это очевидно. Если Вам нужны медленные обработчики, выставляйте флаг и продолжайте работу.
На случай, если какое-либо изменение кнопок было пропущено, в теле главного цикла следует вызвать чтение состояний.
Ваш код получится лаконичным и легко читаемым. uK будет занят решением задач, а не ожиданием кнопок. Вы даже можете перевести его в режим сна без риска пропустить нажатие кнопки.
Библиотека может быть дописана и использована кем угодно по его усмотрению.
Если выводов не хватает, можно воспользоваться сдвиговыми регистрами или расширителями портов. О них я напишу как-нибудь в другой раз.