Debouncing это часто задаваемые вопросы. Вы должны быть в состоянии найти ... почти неограниченное количество веб-страниц по этой теме. Смит также прокомментировал широко читаемый PDF Джек Гэнсл по этой теме. И со всеми этими ответами у вас есть как аппаратные, так и программные методы.
Я немного добавлю к этой «литературе», говоря в основном об идеях, которые еще недостаточно освещены. Но прежде чем я сделаю, один или два вопроса:
- Устранение неполадок в аналоговом оборудовании может привести к результатам, которых вы не можете достичь с помощью переключателя, «наблюдаемого» только в цифровой форме на периодической основе, путем опроса или даже событиями аппаратного изменения контактов. Но вы можете сделать «достаточно хорошо» для всех намерений и целей, в цифровом виде. Почти никто в наши дни не использует внешние аналоговые решения для устранения неполадок. Но я использовал все: от импульсного растяжения с использованием одного удара (74121) до техник, упомянутых здесь Джеком Гэнслом .
- Для тех, кто занимается только встроенным программированием и совсем не интересуется изучением электроники, дебасинг переключателей, вероятно, является одним из двух основных необходимых навыков. Рабочие светодиоды, вероятно, другой. И под этим я не имею в виду иметь только один навык в этом. Я имею в виду возможность сделать это несколькими способами. Таким образом , вы действительно делаете необходимость в полной мере воспринять то , что Джек Ganssle пишет о, и еще более, в отношении переключателей.
Поскольку я упомянул растяжение импульса с помощью 74121, а Джек Гэнсл не упоминает об этом, и никто из них здесь еще не упоминал, я могу также предоставить эту дополнительную ссылку в качестве дополнительного предлагаемого прочтения об использовании 74121 или 555 в качестве однократного таймер для устранения помех переключателей.
Теперь перейдем к наблюдению с помощью микроконтроллера.
Я обычно использую конечный автомат для обработки разбора. Это почти всегда вызывается обычным таймером "пульса", который я установил на8РС, где возможно. (Обычно я НЕ использую события прерывания, инициируемые фронтом, по нескольким причинам.)
Конечный автомат выглядит так:
смоделировать эту схему - схема, созданная с использованием CircuitLab
Значение DEBOUNCED для коммутатора может принимать значения «неактивно», «активно» и «неизвестно». Таким образом, вы можете убедиться, что ваше программное обеспечение ожидает, пока значение инициализации не установится после инициализации. Но обычно я не беспокоюсь об этом. Я заменяю «неизвестное» значение некоторым значением по умолчанию и просто использую систему двоичных значений.
Конечный автомат вводится, сначала устанавливая дебазированное значение по умолчанию, а затем переходя в состояние «ИЗМЕНЕНИЕ» конечного автомата. На каждом временном интервале (обычно8РСесли мне это удастся), я прочитаю текущее значение переключателя и выполню обновление текущего состояния и, возможно, отклоненного значения. Тогда я просто ухожу. Код высокого уровня затем получает доступ только к отклоненному состоянию.
Если это имеет значение для меня, я также могу сохранить ранее обсужденное состояние. В этих случаях при обновлении самого дебазированного состояния я сначала скопирую это состояние в «ранее дебазированное состояние». Затем я могу использовать пару значений, чтобы определить, произошел ли отклоненный переход. Иногда меня не волнуют переходы. Иногда я делаю. Так что это зависит. Но во всех случаях я хочу знать только о переходах, которые были обсуждены. Меня никогда не волнуют грубые переходы. Код высокого уровня никогда не использует внутреннее состояние, которое конечный автомат использует для своей работы.
Одна из приятных особенностей этого метода заключается в том, что я могу сразу отменить весь порт коммутаторов. И я могу сделать это без единой ветви в коде прерывания тоже. Это означает очень быстрый и короткий отладочный код для ширины порта микроконтроллера (обычно шириной 8 бит). Пример из Atmel AT90 показывает, как это достигается с помощью события прерывания Timer0:
.equ SWPORTPINS = PINB
.def SwRawCurr = r4
.def SwRawPrev = r5
.def SwState = r6
.def SwDebCurr = r7
.def SwDebPrev = r8
; Debounce the input switches.
mov SwRawPrev, SwRawCurr
in SwRawCurr, SWPORTPINS
mov Timer0Tmp1, SwRawCurr
eor Timer0Tmp1, SwRawPrev
mov Timer0Tmp0, Timer0Tmp1
or Timer0Tmp1, SwState
mov SwState, Timer0Tmp0
mov Timer0Tmp0, Timer0Tmp1
com Timer0Tmp0
and Timer0Tmp1, SwDebCurr
and Timer0Tmp0, SwRawCurr
or Timer0Tmp1, Timer0Tmp0
mov SwDebPrev, SwDebCurr
mov SwDebCurr, Timer0Tmp1
Теперь этот пример показывает полную сделку, включая предыдущие и текущие дебутированные значения переключателя. И он выполняет все необходимые переходы состояний, а также. Я не показываю инициализацию этого кода. Но вышеизложенное дает представление о том, как легко работает конечный автомат и как мало кода требуется для этого. Это довольно быстро и просто и не требует ветвления (что иногда включает в себя дополнительные циклы, а также дополнительное пространство кода).
Я предпочитаю использовать 8РСвремя, потому что долгое, долгое тестирование с различными людьми, использующими оборудование, над которым я работал в прошлом, привело меня туда. Я пробовал более длительные периоды, и когда я делаю это, я начинаю заставлять людей говорить мне, что «отзывчивость» недостаточно «оживленная». (В наши дни, когда дети растут, работая в режиме реального времени в играх «стреляй», я мог бы даже сократить их еще больше. Они будут горько жаловаться на даже небольшие задержки, вызванные современными цифровыми телевизорами при настройке и отображении кадра.)
Некоторые люди будут иметь очень четкие представления о том, насколько четкой и отзывчивой должна быть система. Свежий и отзывчивый означает выборку чаще, а не меньше. Но лично я нахожу20РССроки наблюдения приемлемы. ( Хотя я не нахожу более продолжительные времена достаточно хорошими даже для меня.)
Обратите внимание, что упомянутый мной конечный автомат должен сначала войти в состояние SETTLED, а затем остаться там еще на один раз, прежде чем значение DEBOUNCED будет обновлено. Поэтому нажатие кнопки и ее удержание даже в самых лучших обстоятельствах потребует следующих действий:
- изменить с УСТАНОВЛЕНО на ИЗМЕНЕНИЕ
- изменить с ИЗМЕНЕНИЯ на УСТАНОВЛЕННЫЙ
- остаться в заселенном состоянии, обновление отстает
Таким образом, новое состояние требует противодребезговой защиты как минимум 3-х выборок периодов времени для достижения.
Нажатие кнопки потребует не менее 6 раз для перехода из неактивного состояния в активное и затем обратно в неактивное состояние.
Я упомянул вышеупомянутые детали, так что совершенно ясно, что время выборки 8РС означает, что это где-то между 16мс <t≤24РСперейти от неактивного к признанному активному обсуждаемому результату. И это займет другое24РСпрежде чем государство может вернуться в неактивное состояние. Это минимум40мс <t≤48РС пройти весь цикл нажатия кнопки.
Использование более длительного времени выборки будет иметь соответственно более длительные периоды. С использованием20РС Я упомянул как «приемлемый» для меня уже тогда означает где-то вокруг 100мс <t≤120РСдля всего цикла кнопки. И это становится прямо вверх в область , где люди действительно склонны замечать. Мне, конечно, не нравится «чувствовать», если оно длится дольше.
Если вы идете по этому пути, не будьте осторожны с использованием более длительного времени выборки. Если вы должны, то я думаю, что вы также должны сделать много испытаний с пользователями / потребителями.
А если вы разрабатываете код для клавиатуры для набора текста, используйте более короткие сроки. Рекорд для машинистки был установлен десятилетия назад на 217 оборотах в минуту. Это приводит к примерно одному ключу каждый45РС, Такие машинистки нажимают несколько клавиш в контролируемом порядке. Чтобы получить хорошую производительность для очень быстрых машинисток, использующих ртутно-смачиваемую герконовую систему переключения, я обнаружил, что2РС работал хорошо.