Найти тему
Разумный мир

Работаем с кнопками. Или о дребезге контактов и не только о нем

Оглавление
фрагмент изображения с сайта HardNews24.ru
фрагмент изображения с сайта HardNews24.ru

На эту тему написано много, в разных источниках и многими авторами. Казалось бы, все давно известно, а решения проверены временем. С одной стороны, это действительно так. А с другой, этот вопрос возникает постоянно у новичков, да и не только у них.

Поэтому я решил уделить дребезгу контактов, не силовых, а сигнальных, небольшое внимание. Но рассмотрю вопрос с разных сторон, а не так, как в большинстве публикаций "вот вам кнопка, вот так давим дребезг". Реальные ситуации бывают разными, и подход к подавлению дребезга тоже будет разным.

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

Потребности бывают разные

В большинстве случаев нужно не просто реагировать на нажатия и отпускания кнопки однозначным и устойчивым образом. Да и сами кнопки бывают разные. Часто требуется:

  • Отрабатывать короткое и, возможно, длинное нажатие кнопки. При этом не требуется четко отслеживать моменты нажатия и отпускания. Это самый простой случай.
  • Четко отслеживать моменты нажатия и отпускания кнопки, при этом длительность нажатого и отпущенного состояний может быть быть разная. В данном случае, кнопка не обязательно кнопка, это может быть, например, концевой переключатель фиксирующий достижение некоторым объектом крайнего положения.
  • Обработка коротких и, возможно, длительных нажатий, при этом моментом наступления события является отпускание кнопки.
  • Обработка одиночного короткого нажатия, двойного короткого нажатия, длительного нажатия.
  • Обработка короткого одиночного, короткого и последующего длительного нажатия.

Как видно, вопрос обработки кнопок далеко не ограничивается гашением дребезга.

Что такое кнопка?

По большому счету, вопрос не корректен. Кнопка это механический переключатель, точнее, лишь одна из его разновидностей. Поэтому правильнее говорить о работе с механическими переключателями используемыми для взаимодействия с оператором (человеком) или в качестве механических датчиков различных систем автоматики. Однако, для краткости, я буду говорить именно "кнопка". Некоторые, далеко не все, примеры таких "кнопок" приведены ниже.

-2

Может возникнуть вопрос, а переключатель то как сюда попал? Переключатель может быть подключен к контроллеру и управлять, например, режимами работы. В такой ситуации он эквивалентен кнопке с переключающим контактом, но с "памятью состояния", то есть, его не надо держать нажатым.

Что такое дребезг и откуда он берется?

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

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

-3

Здесь Sw это кнопка. Хорошо видно, что дребезг контактов появляется и при замыкании, и при размыкании контактов кнопки. Более того, переходное сопротивление контактов может изменяться в зависимости от силы нажатия.

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

-4

Аналогичные функции имеет выпуклая пластинка в тактовых (на самом деле, тактильных) кнопках. Однако, как я уже сказал, подобные решения позволяют уменьшить дребезг, но не устраняют его полностью. При этом, в процессе эксплуатации кнопки "стареют". Контакты изнашиваются и загрязняются, а дребезг и переходное сопротивление возрастают.

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

Аппаратные (схемотехнические) методы борьбы с дребезгом

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

Прежде, чем перейти к описанию конкретных методов, должен отметить, что описывать их буду без учета особенностей различных серий и технологий цифровых микросхем. Другими словами, я не буду учитывать разницу между КМОП и ТТЛ микросхемами, например. А отличия могут быть весьма значимыми. Из наиболее важного могу отметить вытекающий входной ток у ТТЛ и недопустимость длинных фронтов на входе дискретной логики с мощными буферными каскадами на выходе (если это не триггеры Шмитта).

Использование RS триггера

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

-5

Эта схема гарантированно подавляет дребезг. Но она требует использования кнопки с переключающим контактом. Не буду подробно описывать работу этой схемы, она широко известна. Но уточню один момент, который часто упускают из рассмотрения. Конструкция кнопки с переключающим контактом такова, что дребезг сразу двух половин контактной группы исключен. Именно это исключает многократное опрокидывание триггера при нажатии и отпускании кнопки.

Отмечу некоторые особенности этой схемы, которые тоже редко упоминаются. Эта схема не фиксирует момент размыкания верхнего контакта, она фиксирует момент первого замыкания нижнего контакта. Точно так же, она не фиксирует момент размыкания нижнего контакта, но фиксирует момент замыкания верхнего. Учет этой особенности иногда может быть важным, когда кнопка используется для отслеживания положения объекта, а не нажимается человеком.

Конденсатор параллельно кнопке

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

-6

Кривая напряжения для случая "с конденсатором" показана мной очень условно. Схема работает очень просто. Когда кнопка не нажата конденсатор заряжен, поэтому ток в цепи не протекает и не создает падения напряжения на резисторе. На входе схемы низкий уровень напряжения. Нажатие кнопки разряжает конденсатор (можно считать, что мгновенно). При этом на входе схемы появляется напряжение высокого уровня, через контакты кнопки. Короткие периоды разомкнутого состояния контактов во время дребезга позволяют конденсатору немного зарядиться через резистор, при этом протекающий через резистор тока заряда конденсатора создает на нем падение напряжения, а это поддерживает на входе схемы напряжение высокого уровня, но плавно спадающее.

Если постоянная времени RC цепи выбрана правильно, конденсатор не успевает заметно зарядиться за время дребезга, что позволяет избежать ошибочной работы схемы, к которой кнопка подключена. Обычно, в качестве порогового элемента, на входе схемы при таком подключении кнопки используется триггер Шмитта. Или используется вход микроконтроллера с триггером Шмитта. Но давайте внимательно посмотрим, как такой сигнал с кнопки воспринимается схемой

-7

Я показал пороговые уровни логического нуля (th 0) и логической единицы (th 1). Хорошо видно, что этот метод гашения дребезга позволяет точно отследить момент замыкания кнопки, но момент размыкания отслеживается с задержкой. А это может быть критично. Кроме того, быстрое отпускание и повторное нажатие кнопки может быть воспринято как единичное длительное нажатие, так как конденсатор не успеет зарядиться до уровня, когда будет зафиксирован логический 0. И это гораздо более важный момент, который просто необходимо учитывать. Вы думаете, что человек не может очень часто и быстро нажимать на кнопку? Но кнопкой может быть, например, энкодер. Или контакт может быть механическим датчиком скорости вращения.

Если эту схему перевернуть, то есть, резистор подключить к источнику питания, а конденсатор и кнопку к общему проводу, то поведение схемы не изменится. Она по прежнему позволит фиксировать момент нажатия, но отпускание будет фиксироваться с задержкой. Только при отпущенной кнопке на выходе будет высокий уровень напряжения, а при нажатой низкий.

Использование одновибратора (ждущего мультивибратора)

Этот метод тоже встречается, хотя и реже двух ранее описанных

-8

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

Одновибратор может быть и специализированной микросхемой, и реализован, например, на D-триггере. Подобных схем можно найти множество.

Однако, данный метод гашения дребезга имеет один, но существенный, недостаток. Если длительность нажатия кнопки больше длительности формируемого импульса, то возможны ложные срабатывания дребезга при отпускании кнопки. Кроме того, можно отследить только момент нажатия кнопки, но не момент отпускания.

Схему можно усложнить, что позволит устранить некоторые недостатки. Можно использовать несколько одновибраторов, что позволит сформировать отдельный сигнал длинного нажатия, а это невозможно с приведенными выше методами. Однако, в настоящее время такие решения применяются довольно редко.

Другие схемотехнические решения

Есть и другие варианты схем гашения дребезга, но они, так или иначе, реализуют продемонстрированные выше принципы. Я приведу их без описания работы

-9

Если посмотреть внимательнее, то видно, что эти схемы можно считать разновидностью использования одновибраторов.

Еще раз обращаю внимание, что здесь применены микросхемы старых серий, для которых были допустимы затянутые фронты входных сигналов. Для современных серий это может вызывать большие проблемы. Я затрагивал этот вопрос в статье Почему "глючит" цифровая электроника.

Специализированные решения

Если необходимо обрабатывать большое количество кнопок, например, клавиатуру 4х4, то имеет смысл использовать специализированные микросхемы. Они бывают и отдельными, и совмещенными с контроллерами динамической индикации. Рассмотрение подобных микросхем выходит за рамки статьи, я упомянул их только для полноты картины.

Программные способы обработки кнопок и гашения дребезга

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

-10

Я буду рассматривать именно такой простейший вариант подключения кнопки к порту микроконтроллера. При этом возможно поменять местами резистор и кнопку, это не повлияет на суть изложения.

Но сначала важное примечание. Дзен не позволяет как либо удобоваримо форматировать текст, что приводит к невозможности приводить фрагменты программ в текстовом виде, они становятся нечитаемыми. По этой причине все фрагменты программ я буду приводить в виде картинок. Увы, иного способа просто нет.

Фрагменты программ написаны на некоем диалекте языка С, что бы избежать привязки к конкретному компилятору и микроконтроллеру.

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

Есть три основных способа программной обработки кнопок и гашения дребезга

  • использование задержек
  • использование счетчиков
  • измерение длительности импульсов

Я буду рассматривать только два первых способа, как более простые и часто используемые.

Использование циклического опроса и счетчиков

Это самый простой и очевидный способ обработки кнопки. Приведенный ниже фрагмент программы может располагаться как в теле основной программы, если она выполняется циклически и это позволяет считывать состояние кнопки с разумными интервалами, примерно, каждые 0.5 мс - 5 мс. Так же, он может располагаться в процедуре обработки прерываний таймера, которые происходят с той же частотой.

В фрагменте программы будут использоваться следующие переменные и их начальные значения.

-11

Состояния кнопки это внутренние переменные "драйвера" кнопки. Они не должны использоваться остальной частью программы. Исключение составляет KeyPressed, которая использоваться с некоторыми ограничениями.

События кнопки это события обрабатываемые основной программой. В данном случае событий лишь два, короткое и длинное нажатия.

Пороги состояний, с точки зрения программы, являются константами определяемыми на этапе отладки. Press_th задает длительность дребезга контактов кнопки в периодах ее сканирования. Другими словами, это пороговое значение счетчика, после которого считается, что кнопка нажата. Кнопка будет считаться отпущенной, когда счетчик обнулится. В данном случае я не учитываю, что длительность дребезга при нажатии и при отпускании может быть разной. Вы можете учитывать это, если потребуется, в своих программах. Long_th это количество циклов опроса, после фиксации нажатого состояния кнопки, когда считается, что нажатие было долгим.

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

Основу этого метода составляет счетчик связанный с циклом опроса кнопки. В начальном состоянии он равен 0. Если в очередном цикле опроса кнопки на выводе порта высокий уровень, а значение счетчика еще не достигло порогового значения, счетчик инкрементируется. Если в очередном цикле опроса кнопки на выводе порта низкий уровень, а счетчик не равен 0, то он декрементируется.

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

Счетчик LongCounter считает циклы опроса, в течении которых кнопка считается нажатой. Это нужно для фиксации длительного нажатия кнопки.

Событие ShrotPress - короткое нажатие кнопки, фиксируется при отпускании кнопки и только в том случае, если не зафиксировано длинного нажатия кнопки. Это событие существует только до следующего цикла опроса.

Событие LongPress - длинное нажатие кнопки, фиксируется если кнопка нажата в течении последних Long_th циклов опроса. Это событие существует до тех пор, пока кнопка не будет отпущена. При длинном нажатии событие ShortPress при отпускании кнопки не возникает.

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

-12

Обратите внимание, нажатие и отпускание кнопки фиксируются с задержкой на время гашения дребезга.

Использование прерываний по изменению состояния вывода порта

Это более сложный способ обработки кнопки. К тому же, не в каждом микроконтроллере есть прерывания вообще, и по изменению состояния порта, в частности. Зато этот метод позволяет сразу фиксировать моменты нажатия и отпускания. Кроме того, программе на нужно тратить время на сканирование кнопки.

Собственно говоря, это одна из реализаций способа с использованием задержек.

Я опишу, как этот метод работает, но не буду приводить текст программы. Дело в том, что обработка прерываний очень сильно зависит от использованного микроконтроллера.

Кратко опишу, что такое прерывания по изменению состояния вывода порта, для тех, кто с этим никогда не сталкивался. Микроконтроллер запоминает состояние, 0 или 1, для заданного вывода порта. Когда состояние меняется, не важно, из 0 в 1, или из 1 в 0, микроконтроллер генерирует прерывание. В некоторых случаях можно задавать какое изменение (0-1 или 1-0) генерирует прерывание. Дополнительно может потребоваться выполнять чтение порта, для обновления сохраненной информации о состоянии вывода. То есть, как я и говорил, все сильно зависит от выбранного микроконтроллера.

В начальный момент времени считается, что кнопка не нажата. При этом прерывания по изменению состояния вывода порта разрешены.

Как только состояние вывода изменится, микроконтроллер сгенерирует прерывание. Если состояние вывода изменилось из 0 в 1, мы фиксируем нажатие кнопки. Если состояние изменилось из 1 в 0, мы фиксируем отпускание кнопки.

При этом прерывания по изменению состояния вывода порта нужно заблокировать на время гашения дребезга контактов. Это исключает влияние дребезга на состояние кнопки в программе.

По истечении заданного времени гашения дребезга мы снова разрешаем прерывания по изменению состояния вывода порта.

Далее, обработка кнопки будет проходить так же, как и в начальный момент времени. С той лишь разницей, что теперь у нас не предопределенное (отпущена), а фактическое состояние кнопки.

Обратите внимание, программа будет отвлекаться на обработку кнопки только в моменты ее нажатия и отпускания, а так же, для разрешения прерываний от кнопки (для это нужен таймер, но можно использовать циклы основной программы).

Я не стал усложнять описание формированием состояний короткого и длинного нажатий. Вы легко сможете сделать это сами, если потребуется, использовав тот же подход, как в примере с опросом и счетчиками. Но теперь потребуется дополнительно использовать таймер (но можно обойтись и циклами основной программы).

Заключение

Я довольно кратко описал гашение дребезга контактов при подключении кнопок к цифровым схемам и микроконтроллерам. Но постарался заострить внимание на особенностях, которые не редко опускают. И более подробно описал программную реализацию. При этом избегал привязки к конкретным моделям микроконтроллеров, что бы показать сам принцип, а не увязать в деталях.