Администрация форума не несёт ответственности за достоверность информации и оставляет за собой право редактировать или в особых случаях даже удалять посты без предупреждения. Спасибо за понимание.

Программирование ATMEL в BASCOM.

Информация о пользователе

Привет, Гость! Войдите или зарегистрируйтесь.


Вы здесь » Программирование ATMEL в BASCOM. » ! Санькины ПЛЮШКИ ! » Изящный антидребезг в прерывании PCINT


Изящный антидребезг в прерывании PCINT

Сообщений 1 страница 8 из 8

1

Чаще всего в 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

Кстати, при помощи аналогичного трюка можно столь же изящно обрабатывать короткие / длинные нажатия. Достаточно лишь сдвигать регистр реже, и установить свои маски на короткое и длинное нажатие.

Как вам идея?

0

2

Если проверять по таймеру, то зачем нужно еще и прерывание от PCINT?
На каждый пин с кнопкой назначаем индивидуальную переменную или массив для всех кнопок (как кому удобнее). В прерывании таймера проверяем состояние пина и если кнопка нажата увеличиваем значение переменной (с ограничением при заданном значении), иначе уменьшаем если число больше 0.
Если переменная равна 0, кнопка не нажата, если достигла заданного значения - нажата.

0

3

Пётр написал(а):

Если проверять по таймеру, то зачем нужно еще и прерывание от PCINT?
На каждый пин с кнопкой назначаем индивидуальную переменную или массив для всех кнопок (как кому удобнее). В прерывании таймера проверяем состояние пина и если кнопка нажата увеличиваем значение переменной (с ограничением при заданном значении), иначе уменьшаем если число больше 0.
Если переменная равна 0, кнопка не нажата, если достигла заданного значения - нажата.

Пётр написал(а):

Если проверять по таймеру, то зачем нужно еще и прерывание от PCINT?

Хм. А действительно. Надо подумать.

0

4

Хотите задачу на подумать? ))
А если я хочу отличить короткое от длинного?
А если три длительности нажатия?
Как-то вы всё сложно и по уму делаете.
Всё зависит от задачи.

Ведь где-то можно тупо висеть в:
while Нажато
incr temp
if temp >= #1 then goto
wend
if temp >= #2 then goto
goto #3

0

5

Как то давно, столкнулся с проблемой дребезга контактов тактовых кнопок. И этот дребезг увеличивался со временем, особенно в носимых устройствах.
Изучая этот вопрос, наткнулся на то, что оказывается для борьбы с этим явлением существуют даже микросхемы драйверы кнопок (уже не помню название), и главное в них не фильтра и триггеры, а то, что они восстанавливают контакты!
Т.е. при нажатии кнопки, на них подаётся кратковременно ток, который разрушает окислы на контактах
По этому алгоритму написал программку, кнопки ес-но подключил через резистор, и ожидания оправдались. Сбои прекратились
Алгоритм прост. При обнаружении контакта, сначала , кратковременно переводим пин на выход, и подаём "1", потом обратно на  вход и смотрим состояние. Дребезга уже нет

Отредактировано kip (2024-03-22 18:39:37)

+1

6

Микросхема MC14490P, из внешнего обвеса 1 конденсатор (но это уже аппаратный антидребезг), сейчас подоражала на Али 200 руб. за 5 шт.

+1

7

А просто конденсатор параллельно контакту - некошерно уже ? ;)
"Слизывает" дребезг великолепно.

От 1 nF до 10 nF вполне достаточно.
Пользуюсь этим способом еще со времен "дискретной логики".

+2

8

Увы, но некошерно. Некоторые миниатюрные кнопки конденсатор сгрызает за менее чем 100 нажатий. Надо последовательно с ним ставить малоомный резистор.
Идея с импульсом на кнопку привлекательнее выглядит, но без резистора и тут не обойтись.

0


Вы здесь » Программирование ATMEL в BASCOM. » ! Санькины ПЛЮШКИ ! » Изящный антидребезг в прерывании PCINT