В своих микроконтроллерных поделках я постоянно использую кнопки. Поэтому написал
простенький драйвер для работы с ними. В текущей версии драйвер заточен под четыре кнопки, но его довольно легко переделать. В этой статье я опишу содержимое файлов драйвера, а в следующей разберу какой-нибудь практический пример.
Схема
Схема подключения кнопок традиционная – один контакт кнопки соединен с выводом микроконтроллера, другой с нулем питания. Подтягивающие резисторы внутренние. Кнопки подключены к обычным выводам микроконтроллера, не обладающим функциями внешних прерываний.
Заголовочный файл
Заголовочный файл содержит символические имена регистров и выводов порта, к которому подключены кнопки. Коды которые будут записываться в буфер при нажатии кнопок. Прототипы функций.
void BUT_Init(void); Настраивает выводы к которым подключены кнопки на вход и включает подтягивающие резисторы. Вызывается обычно в начале main`a.
void BUT_Debrief(void); Выполняет однократный опрос кнопок. В функции реализована антидребезговая защита – чтобы номер кнопки был занесен в буфер, она должна быть нажата в течении заданного числа циклов опроса. Номер кнопки заносится в буфер однократно, даже если кнопка долго удерживается. Эта функция вызывается в прерывании таймера.
unsigned char BUT_GetKey(void); Возвращает содержимое кнопочного буфера, при этом буфер очищается. Вызывается из основного цикла программы.
void BUT_SetKey(unsigned char key); Записывает в буфер значение. Используется для имитации нажатия кнопки.
Сишный файл
Си файл содержит реализацию всех функций. Из них интерес, пожалуй, представляет только функция опроса.
Обычная тактовая кнопка может находиться в двух состояния – нажатом и отпущенном (третье состояние – сломанное, нас сейчас не интересует). В идеальном случае кнопка переходит из одного состояния в другое мгновенно, однако в реальности при нажатии ее контакты многократно замыкаются и размыкаются, прежде чем окажутся в установившемся замкнутом состоянии. Это явление называется дребезгом контактов, и оно присуще всем механическим переключателям.
Микроконтроллер работает на частоте в несколько мегагерц, и пока происходит дребезг, может опросить кнопку несколько раз. Если не принять каких-то мер, то дребезг контактов будет “воспринят” микроконтроллером как многократное нажатие. Для некоторых приложений это не критично, ну, например, если кнопка управляет включением лампы фонаря. Но в большинстве случаев это явление нежелательное.
Дребезг контактов можно устранить аппаратно, с помощью пассивного НЧ фильтра. Но гораздо проще побороть дребезг, сделав программу микроконтроллера невосприимчивой к нему. Вариант подобного алгоритма как раз и реализован в функции BUT_Debrief()
#define THRESHOLD 20
volatile unsigned char pressedKey = 0;
unsigned char comp = 0;
void BUT_Debrief(void)
{
unsigned char key;
//последовательный опрос выводов мк
if (BitIsClear(PIN_BUTTON, ENTER))
key = KEY_ENTER;
else if (BitIsClear(PIN_BUTTON, CANCEL))
key = KEY_CANCEL;
else if (BitIsClear(PIN_BUTTON, UP))
key = KEY_UP;
else if (BitIsClear(PIN_BUTTON, DOWN))
key = KEY_DOWN;
else {
key = KEY_NULL;
}
//если во временной переменной что-то есть
if (key) {
//и если кнопка удерживается долго
//записать ее номер в буфер
if (comp == THRESHOLD) {
comp = THRESHOLD + 10;
pressedKey = key;
return;
}
else if (comp < (THRESHOLD+5)) comp++;
}
else comp=0;
}
В начале функции выполняется последовательный опрос выводов. Если какая-нибудь из кнопка нажата, во временную переменную key заносится соответствующий код. Затем проверяется значение переменной comp, чтобы выяснить как долго кнопка находится в нажатом состоянии. Пока comp не достигнет некоего порогового значения THRESHOLD, она будет инкрементироваться. Как только значение comp станет равным THRESHOLD, временная переменная key будет скопирована в кнопочный буфер pressedKey. При этом comp получит новое значение, чтобы при следующих опросах кнопок микроконтроллер не инкрементировал эту переменную, и не производил запись в буфер. Таким образом, как бы долго пользователь не удерживал кнопку, микроконтроллер зафиксирует факт ее нажатия только один раз.
Довольно часто кнопки используются для установки каких-нибудь линейно меняющихся величин. В этом случае удобно использовать такой алгоритм - короткое нажатие на кнопку медленно изменяет величину, длительное нажатие быстро. Подправим часть функции опроса и получим простой вариант реализации этого алгоритма.
#define THRESHOLD2 300
...
if (key)
{
if (comp > THRESHOLD2)
{
comp = THRESHOLD2 - 40;
pressedKey = key;
return;
}
else comp++;
if (comp == THRESHOLD)
{
pressedKey = key;
return;
}
}
else comp=0;
...
Теперь, если кнопка удерживается больше 300 циклов опроса, микроконтроллер снова и снова будет записывать в буфер ее код.
На этом пока все, но тема кнопок не закрыта. Продолжение следует...