LinuxForum.Fans
Тема

Подавление дребезга контактов - алгоритм

Автор: Rizado 17 сообщений 1109 просмотров
01.09.2018 10:07 #429536

Радиолюбители знают, что это такое, для не знающих кратко - любая кнопка по факту при нажатии вначале выдаёт серию очень коротких импульсов, а затем уже окончательно замыкает цепь. Аналогичное поведение и при отпускании. Причина - упругость контактов и отсутствие абсолютно твёрдых материалов.

Есть самодельная схема, где ничего особо оригинального нет - AtMega328P, 7-сегментный светодиодный индикатор (пока что 4 секции, думаю расширить до 6-8), 4 кнопки и куча датчиков (пока только климатические - на них удобно отладку делать, потом будут и иные).
Основная задача - подавление дребезга контактов при нажатии. Есть два момента, делающие задачу проще:
1. Нажатия двух и более кнопок одновременно не предвидится вообще. То есть, это отслеживать не надо, хотя реализация схемы и позволит. Кнопки подключены через диоды на выходы, управляющие разрядами дисплея, и заведены на общий вход. Диоды - чтобы не было замыкания на управляющих выходах.
2. Повтор нажатий при удержании не нужен, как минимум, на текущем этапе. То есть, схема такая: "нажал - отработала - ждём отпускания".

Идея алгоритма такова:

В схеме реализовано прерывание по таймеру 50 раз в секунду (интервал 20 миллисекунд) для обновления дисплея. Это более чем достаточно для подавления дребезга и вполне устраивает меня по быстродействию.
Допустим, изначально состояние "все кнопки отпущены", назовём его начальным. Плюс имеется флаг "кнопка сработала", установлен в ноль. Если нажато несколько кнопок - сразу возврат в это состояние.
При нажатии одной кнопки (на несколько не реагируем, см. предыдущий абзац) записываем её состояние. Если не совпадает с предыдущим (была отпущена, а теперь нажата), ждём следующий опрос. Если совпадает - смотрим на флаг срабатывания: если ноль - выполняем действие и устанавливаем в единицу, если уже единица - просто ждём отпускания.
При отпускании всех кнопок сбрасываем флаг срабатывания в ноль и переходим в начальное состояние.

Просьба указать, если в логике работы есть ошибки.

01.09.2018 23:41 #429537

В общем правильно, но сравнивать лучше с несколькими предыдущими состояниями. Если они все совпадают, тогда обрабатываем. Неплохо бы 3, но это получается задержка 60..80 ms. Это уже слишком близко к пределу 100 ms

02.09.2018 10:59 #429542

s.xbatob, благодарю. Буду делать.
Вчера собрал схему на AVR (кроме кнопок), сделал обработчик прерывания, реализовал отсчёт времени (каждое 50-е прерывание). С дребезгом буду пробовать сегодня уже.

02.09.2018 12:19 #429544

Rizado, может не совсем я прав, но для сглаживания дребезга контактов используются RC цепочки на землю или триггеры Шмидта. Но, ИМХО, получить квадратную форму сигнала все равно не получится, но хороший меандр - да. *SCRATCH*

02.09.2018 12:45 #429545

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

02.09.2018 22:11 #429552
"Rizado" написал:
Но меня интересует программное подавление

Ваш длинный текст упрощаю.
Выявленное событие перехода кнопки в любое другое состояние: 0-> 1 или 1 -> 0 должно запускать таймер (таймаут), в течении которого система на другие переходы (из-за возможного дребезга) не реагирует. После таймаута возобновить "прослушку" событий переходов.

03.09.2018 00:09 #429553
Oleg65 написал:
Rizado, может не совсем я прав, но для сглаживания дребезга контактов используются RC цепочки на землю или триггеры Шмидта. Но, ИМХО, получить квадратную форму сигнала все равно не получится, но хороший меандр - да. *SCRATCH*

Проехали. Уже лет 30 как. Всё давным-давно решается программно. И клавиши сканируются, так что RC цепочки тут не поставить.

03.09.2018 08:50 #429554

user160, Вы не совсем правы. Основная проблема в том, что в это время надо выполнять другие действия, такие, как обновление экрана, вычисления, сбор информации с датчиков...

03.09.2018 19:19 #429564
Rizado написал:
user160, Вы не совсем правы. Основная проблема в том, что в это время надо выполнять другие действия, такие, как обновление экрана, вычисления, сбор информации с датчиков...

Вероятно я неточно выразился. Я описал только ту часть алгоритма, которая обрабатывает события нажатий кнопки. Это отнюдь не означает, что все ресурсы компьютера должны быть сосредоточены только на кнопках.

03.09.2018 20:37 #429565

user160, возможно, мы просто не совсем поняли друг друга :) .
В любом случае, считывание кнопок сегодня более-менее реализовал, пока разбираюсь - сделал из прибора часы :) , пусть хоть время и дату показывает. Если интересно, вот код функции, обновляющей дисплей и сканирующей кнопки. Не идеально, но работает:

Показать
text
void refreshDisplay() {
  byte i;
  boolean inLvl;

// три переменные ниже - типа byte, объявлены в теле программы; хотя последнюю можно и локально, потом перенесу keyPressedPrev = keyPressedCurr; keyPressedCurr = 0; keysPressed = 0;

// digits - byte array[27], в него пишем сегменты, которые надо включать, для единицы это 0B01100000, там ещё некоторые и буквы, и упрощённый знак градуса, и т.д. // LEDisplay - byte array[8], а здесь только коды символов, для цифр 0-9 они совпадают с цифрами, для A-F это с 10 по 15 и т.д. for (i = 0; i <=7; i++) { // сегменты пишем в регистр, экономия выводов digitalWrite(latchPin, LOW); shiftOut(dataPin, clockPin, MSBFIRST, digits[LEDisplay[i]]); digitalWrite(latchPin, HIGH); digitalWrite(i + 2, HIGH); delayMicroseconds(666); // задержки в 2/3 миллисекунды хватает для нормальной яркости, там разисторы по 330 Ом // кнопки висят только на четырёх первых выводах, так что лишнее не сканируем if (i < 4) { inLvl = digitalRead(keyInputPin) == HIGH; keyPressedCurr = (keyPressedCurr << 1) | inLvl; if (inLvl) { keysPressed++; } } digitalWrite(i + 2, LOW); } // а если нажато больше одной - нам это не надо :) if (keysPressed > 1) { keyPressedCurr = 0; } }

Что именно выводить - готовится отдельно от отображения. Проще разбить на маленькие логические блоки и их отдельно тестировать.

04.09.2018 12:29 #429570
"Rizado" написал:
код функции, обновляющей дисплей и сканирующей кнопки

По хорошему, в одной функции это делать нехорошо.
Лучше три функции:

  • одна функция на дисплей,
  • другая на прерывание от кнопок,
  • третья таймер, который вновь разрешает прерывание.

Алгоритм таков: кнопка "дёрнула" прерывание. -> 2-я функция "слушатель" прерывания запретила повторные прерывание от кнопки и вызвала третью (таймер).
Не знаю, возможен ли асинхронный вызов функций в Ардуино, а он здесь как раз нужен.
Суть в том, что 2-я функция должна вызвать 3-ю функцию (таймер), а сама 2-я должна завершиться не дожидаясь окончания работы 3-й.

3-я функция, по окончании своей работы, снова разрешает "слушать" прерывание для второй функции.

1-я функция для дисплея - за скобками.

Как-то так. ИМХО

04.09.2018 12:51 #429571

Мне так удобнее - быстродействие лучше.
Кстати, нормально работает, вчера вечером потестировал. Правки были ещё, но уже технические.

20.09.2018 22:24 #429681

В общем, задача решена. Потренировался на том, с чего начинают большинство юзеров Arduino - часы с будильником, датой (с учётом високосного года) и т.д.
Работает идеально, алгоритм был правильный. Когда нарисую схему - выложу. Да, схемы нет, собиралось на макетной плате сразу :) .

За подсказки всем спасибо!

02.10.2018 16:37 #429808

А разве стандартные SDK под контролеры не предостовляют таких средств ?

02.10.2018 16:41 #429810
"mogul82" написал:
А разве стандартные SDK под контролеры не предостовляют таких средств ?

Их сложно с программой подружить, проще было своё с нуля написать. Давно уже сделал всё.

02.10.2018 19:52 #429812
mogul82 написал:
А разве стандартные SDK под контролеры не предостовляют таких средств ?

Там нет ничего сложного. Просто сам идея чисто программная: тикер, сдвиговой регистр, кое-какая логика его выходов... Для аппаратчиков не слишком понятная.
Но надо понимать, что по мере старения кнопки, возможно, придётся вводить коррективы. Особенно. если сдвиговый регистр всего лишь двухбитный. :(

02.10.2018 20:39 #429813

s.xbatob, а там не будет частых нажатий. Включили, настроили, а дальше максимум 5 нажатий в сутки.

Войдите или зарегистрируйтесь, чтобы ответить.