Чаще всего в BASCOM для устранения дребезга контактов используют встроенную функцию debounce.
Однако она не годится для работы в прерываниях.
Тогда обычно прибегают к некоторой задержке, порядка 30...50 мс, используя waitms.
Но и этот способ плох в прерываниях, которые должны исполняться максимально быстро.
Кроме того, прерывания PCINT реагируют на любое изменение уровня на пине (что вытекает из самого названия - pin change interrupt), так что при нажатии кнопки их может прилетать сразу множество. Более того, непонятно, а как вообще проверять статус? Случилось у нас нажатие и, допустим, мы ожидаем на пине НИЗКИЙ, но пока мы вошли в прерывание и стали выполнять проверку, за счет дребезга у нас на пине уже ВЫСОКИЙ. Значит, выжидать и снова проверять бесползено, такое нажатие просто не будет нами обработано по нашим же собственным правилам.
Ок, ждем N мс (плохо в прерывании!), проверяем, если на пине ожидаемое значение, то ждем еще сколько-то (опять плохо), и снова проверяем.
Есть также вариант с запоминанием предыдущего статуса кнопки.
Все это ну такое себе.
Поэтому предлагаю обсудить другой способ. Правда, для него нам понадобится прерывание таймера - впрочем, там всего одна операция, и оно с успехом может выполнять и другие действия.
Итак, в чем идея?
1. Мы заводим 8- или 16-разрядную переменную, которая будет служить виртуальным сдвиговым регистром.
2. По прерыванию таймера сдвигаем содержимое регистра на 1 шаг налево.
3. По прерыванию PCINT мы заносим в 0-й бит нашего регистра уровень, который присутствует на ножке порта.
4. И проверяем: если наша переменная содержит несколько подряд единиц в младших разрядах (вплоть до полного заполнения регистра), то фиксируем УСТОЯВШИЙСЯ ВЫСОКИЙ, если несколько подряд нулей - УСТОЯВШИЙСЯ НИЗКИЙ.
Количество нулей или единиц равно времени антидребезга / период таймера. Допустим, таймер у нас срабатывает и сдвигает регистр влево раз в 1 мс. Значит, регистр заполняется за 16 прерываний таймера, и антидребезг сработает, когда устойчивый сигнал на пине держится более 16 мс.
Пример кода:
' // в определениях: dim debounce_reg as word ' // в коде: ' обработчик прерывания таймера: ' ... код shift debounce_reg, left, 1 ' ... код return ' обработчик pcint: debounce_reg.0 = pinX.Y ' set 0-bit as port value if debounce_reg = 0xFFFF then ' // the button is definitely pressed elseif debounce_reg = 0 then ' // tne button is definitely unpressed end if
Кстати, при помощи аналогичного трюка можно столь же изящно обрабатывать короткие / длинные нажатия. Достаточно лишь сдвигать регистр реже, и установить свои маски на короткое и длинное нажатие.
Как вам идея?
