Алгоритм должен оставлять свободными почти все ресурсы ресурсы контроллера.
То есть при добавлении нового функционала он должен продолжать работать как будто он остался единственным.
Для этого берут какой нибудь захудалый таймер и делают его СИСТЕМНЫМ. То есть организуют на нем системный тик, который сводится к некоему периоду входа в прерывания по этому таймеру, где и организуют опрос кнопок, мигания светодиодами и всякую прочую медленную хрень.
Интервал опроса кнопок должен быть БОЛЬШЕ, чем их дребезг. Обычно хватает 20...30 мс.
Одновременно в этом же прерывании организуют программный счетчик времени нажатия (или отпускания). По каждому событию (нажатие или отпускание) счетчик сбрасывают и затыкают его при некоем таймауте (когда время слишком велико, чтобы он не сбросился при переполнении).
Сами события фиксируют в прерывании по системному таймеру следующим образом:
Код: Выделить всё
//после опроса button =1 - нажатая кнопка, button = 0 - отпущенная
if (button) {statButton = ((statButton<<1) + 1) & 0x3;} else {statButton = (statButton<<1) & 0x3;}
switch (statButton) {
case 1:
if (timerButton> N) { исполнение кода при нажатой кнопке после времени N}
timerButton = 0;
case 2:
if (timerButton> N) { исполнение кода при отпущенной кнопке после времени N}
timerButton = 0;
default:
if (timerButton<TIMEOUT) {timerButton++;}
}
Это просто пример, в кейсах можно делать все что заблагорассудится и не обязательно по таймеру.
statButton - это всего два разряда. Старший - это прежнее положение кнопки, а младший - текущее.
Ветка default может быть разделена на 0 - удерживается отпущенной и 3 - удерживается нажатой.