Причины дребезга контактов
На самом деле, данное явление встречается достаточно часто и является крайне пугающим и неприятным для начинающих ардуинщиков, которые всё ещё не знают, как с ним бороться, и что это вообще такое. С этим «багом» система может работать вполне исправно, вырубаясь лишь на короткие промежутки времени, но именно эти отключения и являются основной причиной недоумения новичков и множества проблем, поэтому справиться с проблемой стараются как можно быстрее.
Чаще всего с дребезгом сталкиваются при подключении кнопки, но почему так происходит? Вот пример при котором это будет:
void loop() {
if (digitalRead(PIN_BUTTON)) {
Serial.println(«1»);
} else {
Serial.println(«0»);
}
}
Кнопка – это один из видов дополнительных модулей под Ардуино, служащих для ввода информации. В основе работы такого механизма лежит простой алгоритм работы – вы надавливаете на механический переключатель, он смыкает контакты, лежащие под оболочкой, и запускается какой-нибудь скрипт. Таким образом, при помощи давления, которое формируется при нажатии, происходит схождение или расхождение металлических пластин, которые и выступают наиболее популярными триггерами.
Программисту остается лишь написать код, который будет как-то засекать данное событие и выполнять определённые действия.
Пример программного решения проблемы:
int currentValue, prevValue;
void loop() {
currentValue = digitalRead(PIN_BUTTON);
if (currentValue != prevValue) {
// Что-то изменилось, здесь возможна зона неопределенности
// Делаем задержку
delay(10);
// А вот теперь спокойно считываем значение, считая, что нестабильность исчезла
currentValue = digitalRead(PIN_BUTTON);
}
prevValue = currentValue;
Serial.println(currentValue);
}
Алгоритм работы казался бы простым, но всегда стоит помнить, что идеализированные системы не применимы на практике, и на той же практике вам приходится сталкиваться с различными их недочетами, как серьезными, так и мелкими, например, отсутствием гладких поверхностей, неровностями на контактах и, для более продвинутых, паразитной емкостью.
Соответственно, в реальности контакты соприкасаются не моментально, из-за недочетов конструкции и на короткий промежуток времени на границах пластин меняется сопротивление, вместе с взаимной емкостью.
Всё это приводит к разнообразным изменениям уровня тока и напряжения, и вместо идеальной диаграммы в виде равнобедренной прямоугольной трапеции, мы получаем промежуток из максимумов и минимумов, прежде, чем система уравновесится. Все эти процессы называются в электротехнике переходными, и, зачастую, просто незаметны для обывателя. Простейшим примером будет включение света в комнате, ведь лампа накаливания разогревается и меняет свою яркость не моментально. Но наш мозг не способен зарегистрировать всё это сам по себе.
Однако, когда мы сталкиваемся с системами, способными фиксировать состояние объектов вплоть до миллисекунды, все эти процессы становятся заметными и крайне проблемными. А всё дело в том, что каждая строчка кода, которую вы прописываете при программировании системы, каким-то образом должна учитывать и обрабатывать все сигналы, в том числе и тот самый пресловутый «дребезг контактов».
Сделать это не так легко, а неприспособленный код, хоть и скомпилируется, но будет вести себя непредсказуемо, что станет кошмаром для любого инженера. Мы разобрались в причинах, но какие же ошибки нам стоит ожидать из-за дребезга?
Способы устранения и подавления дребезга
Без конструктивного изменения контактной системы устранить либо подавить дребезг принципиально невозможно. Примером таких конструктивных изменения можно наблюдать в узлах галетных переключателей или в кнопках типа П2К. В упомянутых конструкциях дребезг практически отсутствует. Нет его и у механического переключателя ползункового типа.
Аппаратный способ
С целью подавления дребезга в системах слаботочных электромеханических ключей прибегают к смачиванию ртутью контактов, которые помещают в изолирующие колбы. Жидкое состояние ртути частично гасит упругие силы, вызывающие дребезг, а также образует токопроводящие перемычки, не позволяющие разрывать электрическую цепь при соприкосновении контактов.
Для снижения уровня коммутационного износа в различных реле и силовых выключателях применяют искрогасящие цепочки:
- шунтирующие RC-цепи;
- варисторы, препятствующие скачкообразному изменению напряжения;
- обратные диоды, подавляющие напряжения самоиндукции;
- стабилитроны;
- комбинированные схемы (варистор +RC-цепь).
Эти цепочки помогают устранить дребезг путём выравнивания скачкообразных характеристик тока. Их подключают параллельно нагрузке либо к контактам реле. Существуют также схемы, в которых искрогасящие цепи подключаются одновременно и к нагрузке и к реле.
Схемы цепей изображены на рис. 3.
Рисунок 3. Схемы искрогасящих цепей
У каждого способа есть свои преимущества и недостатки. В зависимости от того какого результата необходимо достигнуть, применяют ту или иную схему.
Управление приборами чувствительными к дребезгу осуществляется через ФНЧ (например, через RC-цепочку). Обладая электрической емкостью, конденсатор забирает часть энергии в момент касания контактов. После разрыва цепи вследствие дребезга накопленная энергия возвращается. Таким образом, происходит сглаживание амплитуды колебаний.
Установки триггеров
Ещё один способ борьбы с дребезгом состоит в использовании специальных электронных схем, включающих rs-триггеры.
Роль триггеров заключается в преобразовании входного аналогового сигнала в цифровой и инверсии (переворачивания) логических уровней. Наглядно инверсию объясняет схема на рисунке 4.
Рис. 4. Наглядная схема инверсии сигнала
Устройство учитывает только части сигналов, превосходящие заданные пороговые значения, выдавая логические нули и единицы на выходе. Каждый раз восходящий или нисходящий сигнал переключает триггер, когда он проходит верхнее или нижнее пороговое значение. Проще говоря, провалы напряжения компенсируются инвертированными импульсами триггеров.
Простая схема с триггером показана на рисунке 5.
Рис. 5. Наглядная схема подключения rs-триггеров
Промежутки между пороговыми значениями называются гистерезисом. Форма таких импульсов используется для шумоподавления во время переключения логических сигналов. Сигнал от контакта поступает на схему, имеющую передаточную статическую характеристику в виде петли гистерезиса (триггер Шмидта). Только после этого сигнал с выходов триггера подаётся на вход цифрового устройства для тактирования.
Использование герконов
Выше упоминалось, что наличие ртути на контактах подавляет дребезг. Но общеизвестно, что пары этого жидкого металла очень ядовиты. Использовать их в открытых конструкциях, например в тактовых кнопках, небезопасно. Но контакты можно поместить в герметическую колбу, что позволяет применять ртуть. Такие конструкции называются герконами.
Управление контактами герконов осуществляется внешним магнитным полем. Для этого можно использовать постоянные магниты или электромагнитную индукцию. Устройства могут использоваться в маломощных цепях. Они имеют длительный срок службы, так как контакты в них не изнашиваются.
Настройка оборудования
Все коммутаторы будут подключены одинаково (это важно, если мы собираемся сравнивать результаты). Сначала мы увидим, как коммутаторы ведут себя без обработки. Основой нашей схемы будет HCF4017BE. Это десятичный счетчик/делитель, производимый STMicroelectronics. Они больше не производят эту микросхему, так как этот тип устарел. Тем не менее, есть много других производителей, которые всё еще выпускают эту маленькую микросхему, и они часто совместимы по контактам.
Микросхема получает тактовый импульс на вывод 14, после чего загорается светодиод, подключенный к Q1. Когда принимается следующий тактовый импульс, микросхема отключает Q1 и зажигает Q2, и так далее. Когда счетчик достигает Q8 (вывод 9), он подает импульс на вывод 15, который является выводом сброса. Это означает запуск отсчета, начиная с Q0.
Наша основная схема:
Схема тестового макета (описание выше)
Сначала мы попробуем не обрабатывать дребезг совсем. Схемы подачи тактового сигнала показаны ниже:
Тактовый вывод удерживается на уровне лог. 0,
импульс – лог. 1
Тактовый вывод удерживается на уровне лог. 1,
импульс – лог. 0
На видео мы используем схему справа. Тактовый вывод удерживается на уровне логической единицы, импульс соответствует уровню логического нуля.
Видео:
Теперь давайте посмотрим некоторые скриншоты осциллографа. Здесь мы использовали левый вариант схемы подачи импульсов: тактовый вывод удерживается на уровне логического нуля, импульс соответствует уровню логической единицы.
Для коммутатора A:
Дребезг контактов коммутатора A
Для коммутатора B:
Дребезг контактов коммутатора B
Для коммутатора C:
Дребезг контактов коммутатора C
Для коммутатора D:
Дребезг контактов коммутатора D
И один скриншот я снял для коммутатора C при использовании правой схемы подачи импульсов: тактовый вывод удерживается на уровне логической единицы, импульс соответствует уровню логического нуля.
Дребезг контактов коммутатора C (импульс соответствует логическому нулю)
Как вы можете видеть, микросхеме кажется, что было несколько нажатий на коммутатор. Хотя это и не так, поскольку на коммутатор было выполнено только одно нажатие.
Добавим керамический конденсатор:
Тактовый вывод удерживается на уровне лог. 0,
импульс – лог. 1
Тактовый вывод удерживается на уровне лог. 1,
импульс – лог. 0
При добавлении конденсатора мы создаем RC-цепь. RC-цепи здесь не обсуждаются.
Новые скриншоты осциллографа сильно отличаются от полученных ранее. Это показывает, что RC-цепь отфильтровывает дребезг.
Данное видео показывает, как работает схема с керамическим конденсатором 0,1 мкФ:
Для коммутатора A:
Сигнал с коммутатора A после добавления конденсатора
Для коммутатора B:
Сигнал с коммутатора B после добавления конденсатора
Для коммутатора C:
Сигнал с коммутатора C после добавления конденсатора
Для коммутатора D:
Сигнал с коммутатора D после добавления конденсатора
Для коммутатора C (импульс соответствует логическому нулю):
Сигнал с коммутатора C после добавления конденсатора (импульс соответствует логическому нулю)
Эти скриншоты говорят нам о том, что дребезг устранен, и что микросхема «видит» только одно нажатие или переключение. Это то, чего мы и хотели.
Программная борьба с влиянием дребезга контактов кнопок
Сразу отказываемся от подключения RC-цепей и триггеров
и решать проблему будет программно. Суть алгоритма в многократном подтверждении состояния, такого рода алгоритм для подавления влияния дребезга контактов кнопок вида для ПЛИС уже был описан, кроме этого цифровой фильтр использовался при подключении энкодера к STM32 (но он был аппаратным).
С частотой около (50-100) Гц, то есть с периодом (20-10 мс) будет происходить опрос в прерывании от таймер, что уже хорошо, т.к. не мешаем основной программе
.
Итак, вот произошло прерывание, в его обработчике считывается текущий логический уровень на нужном выводе (к нему и подключена кнопка) и если она нажата (низкий уровень, т.к. используется схема слева) — то
увеличиваем (инкрементируем) значение счетчика на единицу, теперь проверяем достиг ли счетчик нужного числа, например 4, что будет означать, что лог. уровень не изменялся на протяжении 4*10 мс = 40 мс (если прерывание с периодом 10 мс), то есть нужно выбирать такой промежуток, который будет явно больше ожидаемого дребезга (например, выше он составлял 26 мс), если же не нажата (высокий уровень) — обнуляем, таким образом если во время проверки из-за дребезга будет высокий уровень, счетчик
Дребезжание реле
Кроме дребезга кнопок в цифровых электронных схемах также доставляет проблемы дребезг контактов в схемах управления реле. К таким схемам можно отнести сумеречное реле или различные датчики протока, а также регуляторы температуры. Когда датчик выдаёт сигнал на пороге срабатывания устройства, получается неопределенное состояние и логика схемы то включает, то отключает его. И при срабатывании реле не всегда наблюдается устойчивое удержание контактов, оно начинает как бы вибрировать, включаясь и отключаясь. На эпюре ниже наглядно изображена эта проблема на примере регулятора температуры:
Решением этой проблемы также является установка порогового элемента петлей гистерезиса в его передаточных статических характеристиках, то есть триггера Шмидта или Компаратора на операционном усилителе. На схеме ниже изображен исходный вариант с рассмотренной на графике проблемой:
А так выглядит схема с дополнением в виде задержки включения на логических элементах 2И-НЕ отечественной микросхемы К561ЛА7:
Иногда с этой же проблемой справляются с помощью установки стабилитрона в сигнальные цепи.
Аналогично дребезгу кнопок при включении реле, его контакты могут повторно несколько раз перекоммутироваться. Явление опасно тем, что в этот момент происходит зажигание и гашение дуги, что значительно снижает срок службы аппарата. Особенно часто это происходит при срабатывании реле на переменном токе.
Всё это связано с механической структурой герконов, реле и других коммутаторов. Их контакты замыкаются не моментально, а в течении долей, единиц или десятков миллисекунд. Чтобы продлить срок службы реле, ознакомьтесь со способами, которые мы описывали в статье о том, почему искрят контакты.
Также рекомендуем посмотреть хорошее видео на эту тему:
Теперь вы знаете, что такое дребезг контактов реле и какие способы борьбы с ним наиболее эффективны. Если возникли вопросы, задавайте и в комментариях под статьей!
Аппаратный способ подавления дребезга кнопки
Подавление дребезга кнопки с помощью задержек в скетче – способ очень распространенный и не требующий изменения самой схемы. Но далеко не всегда его можно использовать – ведь 10 миллисекунд – это целая вечность для многих процессов в электроном мире. Также программный способ невозможно применять при использовании прерываний – дребезг приведет к многократному вызову функций и повлиять на этот процесс в скетче мы не сможем.
Более правильный (и более сложный) способ борьбы с дребезгом – использование аппаратного решения, сглаживающего импульсы, посылаемые с кнопки. Для этого, правда, придется внести изменения в схему.
Аппаратный способ устранения дребезга основан на использовании сглаживающих фильтров. Сглаживающий фильтр, как следует из названия, занимается сглаживанием всплесков сигналов за счет добавления в схему элементов, имеющих своеобразную “инерцию” по отношению к таким электрическим параметрам как ток или напряжение. Самым распространенным примером таких “инерционных” электронных компонентов является конденсатор. Он может “поглощать” все резкие пики, медленно накапливая и отдавая энергию, точно так же, как это делает пружина в амортизаторах.
За счет инерции устройство как утюгом походит по “мятому” сигналу с большим количеством пиков и впадин, создавая пусть и не идеальную, но вполне гладкую кривую, у которой легче определить уровень срабатывания.
Пример простого фильтра на базе RC-цепочки
Схема подключение фильтра для устранения дребезга:
Пример подключения к плате ардуино
Форма сигнала после использования фильтра:
Как видим, “лес” дребезга сменился достаточно плавной линией, с которой уже можно работать дальше.
Что такое дребезг контактов и как его устранить?
В этой статье мы рассмотрим такое распространенное и вредное явление как дребезг контактов. Ознакомимся с основными причинами возникновения дребезга. Изучим основные методы аппаратного и программного устранения данного явления.
Определение и суть проблемы в электронике
Дребезг контактов возникает при нажатии на кнопку и переключатель, он возникает из-за реальных вибраций контактной пластины при её перемещении. Любой переключатель устроен так, что у него есть подвижный и неподвижный контакт. Как видно из названия, подвижным называется тот, что соединен с толкателем или рычагом, на который уже нажимает человек или механизм при работе устройства.
Так как кнопки имеют механическое устройство, то от их качества зависит то, как точно они отрабатывают нажатия. При этом в любом случае полностью устранить явление дребезга нельзя. К чему он приводит?
Если клавиша управляет каким-то электронным устройством с цифровым входом, например, микроконтроллера, логического элемента и пр., то его вход распознает столько нажатий, сколько было импульсов послано в результате возникновения дребезга.
Пример осциллограммы дребезга контактов изображен на рисунке ниже:
Ошибки дребезга кнопки
Проще всего заметить основные проблемы, которые доставляет дребезг контактов на Аrduino, на непосредственном проекте, в котором прописан код для обработки события нажатия кнопки.
Если вы уже работали с подобной задачей, то должны помнить, что для этого используется специальный цикл, дабы постоянно проверять состояние рычага и в нужный момент преобразить систему под необходимые условия, например, подав напряжение на выход. 1 такой цикл проходит за промежуток времени, зависящий от мощности процессора, но, зачастую, не превышающий нескольких миллисекунд.
Этого времени вполне достаточно, чтобы код успел отреагировать на «шумы» при нажатии кнопки. А теперь представьте себе ситуацию – в вашей программе прописано запускать процесс, как только кнопка нажимается, и выключать, как только её отпускают. Для регистрации обоих событий применяется перепад напряжения. В результате цикл будет несколько раз запускать и закрывать функции, пока происходит дребезг контактов. Если всё это происходит ещё и в многопоточном режиме, то нагрузку в стеке микроконтроллера не сложно вообразить.
Проверка
Настроил на две кнопки. Работает замечательно, переключается состояние СИД и счетчик-переменная инкрементируется:
Дребезг контактов, и как с ним бороться
В данной статье мы рассмотрим, что такое дребезг контактов и способы борьбы с ним. Сначала я рассмотрю теорию, а позже покажу вам некоторые способы обработки дребезга и аппаратно, и программно.
Теория
Что такое дребезг контактов? Когда вы нажимаете на кнопку или на микропереключатель или изменяете положение тумблера, два металлических контакта замыкаются. Для пользователя может показаться, что контакт наступил мгновенно. Это не совсем правильно. Внутри коммутатора есть движущиеся части.
Когда вы нажимаете на коммутатор, он вначале создает контакт между металлическими частями, но только в кратком разрезе микросекунды. Затем он делает контакт немного дольше, а затем еще немного дольше. В конце коммутатор полностью замыкается. Коммутатор скачет (дребезжит) между состояниями наличия и отсутствия контакта.
«Когда коммутатор замыкается, два контакта фактически разъединяются и снова соединяются обычно от 10 до 100 раз за время, примерно равное 1 мс» («Искусство схемотехники», Хоровиц и Хилл, второе издание). Обычно оборудование работает быстрее, чем дребезг, что приводит к тому, что оборудование думает, что вы нажали на кнопку несколько раз.
Оборудование часто является интегральной микросхемой. Следующие скриншоты иллюстрируют типовой дребезг контактов без какой-либо обработки:
Осциллограмма дребезга контактов
Каждый коммутатор обладает своими собственными характеристиками относительно дребезга. Если вы сравните два одинаковых коммутатора, есть большая вероятность того, что они будут «дребезжать» по-разному.
Я покажу вам дребезг четырех разных коммутаторов. Я меня есть две микрокнопки, 1 кнопка и 1 тумблер:
Исследуемые коммутаторы
Настройка оборудования
Все коммутаторы будут подключены одинаково (это важно, если мы собираемся сравнивать результаты). Сначала мы увидим, как коммутаторы ведут себя без обработки. Основой нашей схемы будет HCF4017BE.
Это десятичный счетчик/делитель, производимый STMicroelectronics. Они больше не производят эту микросхему, так как этот тип устарел.
Тем не менее, есть много других производителей, которые всё еще выпускают эту маленькую микросхему, и они часто совместимы по контактам.
Микросхема получает тактовый импульс на вывод 14, после чего загорается светодиод, подключенный к Q1. Когда принимается следующий тактовый импульс, микросхема отключает Q1 и зажигает Q2, и так далее. Когда счетчик достигает Q8 (вывод 9), он подает импульс на вывод 15, который является выводом сброса. Это означает запуск отсчета, начиная с Q0.
Наша основная схема:
Схема тестового макета (описание выше)
Сначала мы попробуем не обрабатывать дребезг совсем. Схемы подачи тактового сигнала показаны ниже:
Тактовый вывод удерживается на уровне лог. 0, импульс – лог. 1
Тактовый вывод удерживается на уровне лог. 1, импульс – лог. 0
На видео мы используем схему справа. Тактовый вывод удерживается на уровне логической единицы, импульс соответствует уровню логического нуля.
Видео:
Теперь давайте посмотрим некоторые скриншоты осциллографа. Здесь мы использовали левый вариант схемы подачи импульсов: тактовый вывод удерживается на уровне логического нуля, импульс соответствует уровню логической единицы.
Для коммутатора A:
Дребезг контактов коммутатора A
Для коммутатора B:
Дребезг контактов коммутатора B
Для коммутатора C:
Дребезг контактов коммутатора C
Для коммутатора D:
Дребезг контактов коммутатора D
И один скриншот я снял для коммутатора C при использовании правой схемы подачи импульсов: тактовый вывод удерживается на уровне логической единицы, импульс соответствует уровню логического нуля.
Дребезг контактов коммутатора C (импульс соответствует логическому нулю)
Как вы можете видеть, микросхеме кажется, что было несколько нажатий на коммутатор. Хотя это и не так, поскольку на коммутатор было выполнено только одно нажатие.
Добавим керамический конденсатор:
Тактовый вывод удерживается на уровне лог. 0, импульс – лог. 1Тактовый вывод удерживается на уровне лог. 1, импульс – лог. 0
При добавлении конденсатора мы создаем RC-цепь. RC-цепи здесь не обсуждаются.
Новые скриншоты осциллографа сильно отличаются от полученных ранее. Это показывает, что RC-цепь отфильтровывает дребезг.
- Данное видео показывает, как работает схема с керамическим конденсатором 0,1 мкФ:
- Для коммутатора A:
Сигнал с коммутатора A после добавления конденсатора
Для коммутатора B:
Сигнал с коммутатора B после добавления конденсатора
Для коммутатора C:
Сигнал с коммутатора C после добавления конденсатора
Для коммутатора D:
Сигнал с коммутатора D после добавления конденсатора
Для коммутатора C (импульс соответствует логическому нулю):
Сигнал с коммутатора C после добавления конденсатора (импульс соответствует логическому нулю)
Эти скриншоты говорят нам о том, что дребезг устранен, и что микросхема «видит» только одно нажатие или переключение. Это то, чего мы и хотели.
Борьба с дребезгом кнопки с помощью библиотеки Ардуино
Мы поняли, что проблема чисто аппаратная, но, как ни парадоксально, со стороны «железа» её сложно исправить. Вы же не можете лично под микроскопом отполировать контакты, да ещё и просить пользователя нажимать на кнопку лишь с одной силой и на постоянной основе.
Поэтому нам придется хитрить со стороны кода и пытаться каким-то образом вписать в обработчик событий этот непростой процесс. А так как мы уже знаем природу этого явления, то примерно представляем, как его обойти или хотя бы постараться минимизировать нагрузку на систему в этот момент.
А всё на самом деле просто, ведь перед нами стоит такой перечень условий:
- На срок до 10-100 мС, система пребывает в нестабильном состоянии и может выдавать ошибки.
- Далее идет срок от 1 до 2-ух секунд, что в 10 раз больше от предыдущего, пока кнопку нажимают.
- И вновь, под конец, 10-100 мС, длится дребезг.
Все, кто работал с многопоточностью на Си, уже заприметили очевидные триггеры, от которых мы и будем отталкиваться. Дело в том, что для предотвращения проблем по программной части нам достаточно выдержать тишину на каком-то промежутке времени, пока дребезг не пройдет, то есть достаточно воспользоваться уже готовой функцией delay().
Программирование
Код реализующий подобный принцип может быть разным, вот один из возможных, он «прокачан» за счет сравнения текущего значения с предыдущим (так отслеживается нажатие и отпускание кнопки) [взят из:
Software debouncing of buttons snigelen February 5, 2015, и чутка переделан под STM32].
Используется целых
три глобальных переменных для каждой кнопки:
/********** PV **********/
/* PA0 */
uint8_t pres_pa0;
uint8_t prev_pa0;
uint8_t cnt_pa0;
/* PA7 */
uint8_t pres_pa7;
uint8_t prev_pa7;
uint8_t cnt_pa7;
/* Other */
uint8_t counter;
/************************/
А вот и сама функция с кучей аргументов (перегружена, зато удобная):
/**
* @brief Debounce function for button
* @note Perform it every 10-20ms (e.g. in timer’s interrupt)
* In main loop check first variable ((*pres_px), if (it > 0) nullify it and execute required code
* @param Three global variables, IDR register, Bit for check (e.g. &pres_pa0, &cnt_pa0, &prev_pa0, GPIOA->IDR, GPIO_IDR_ID0)
* @retval no
*/
void Debounce(uint8_t *pres_px, uint8_t *cnt_px, uint8_t *prev_px, uint32_t GPIOx_IDR, uint32_t GPIO_IDR_IDx)
{
/* Read current state */
uint8_t cur_px = (~GPIOx_IDR & GPIO_IDR_IDx) != 0;
/* If level has changed */
if (cur_px != *prev_px) {
/* Increase counter */
(*cnt_px)++;
/* If consecutive 4*10 = 40ms approved */
if (*cnt_px >= 4) {
/* The button have not bounced for four checks, change state */
*prev_px = cur_px;
/* If the button was pressed (not released), tell main so */
if (cur_px != 0)
{
*pres_px = 1;
}
(*cnt_px) = 0;
}
}
else {
/* Reset counter */
*cnt_px = 0;
}
}
Взял крутую заряженную отладочную плату
MiniF4 (МК: STM32F411CEU6). Ну, а теперь нужно настроить вывод(ы) на вход (к нему подключена кнопка) и один на выход (к нему подключен светодиод):
/* GPIOC 13 OUT PP */
/* Clock GPIOC */
RCC->AHB1ENR |= RCC_AHB1ENR_GPIOCEN;
/* 01: General-purpose output */
GPIOC->MODER |= GPIO_MODER_MODE13_0;
GPIOC->MODER &= ~GPIO_MODER_MODE13_1;
/* 0: Output push-pull */
GPIOC->OTYPER &= ~GPIO_OTYPER_OT13;
/* 00: Low speed */
GPIOC->OSPEEDR &= ~GPIO_OSPEEDER_OSPEEDR13;
/* 00: Np pull-pull up, pull-down */
GPIOC->PUPDR &= ~GPIO_PUPDR_PUPD13;
/**********************/
/* GPIOA 0 IN PU */
/* Clock GPIOA */
RCC->AHB1ENR |= RCC_AHB1ENR_GPIOAEN;
/* 00: Input (reset state) */
GPIOA->MODER &= ~GPIO_MODER_MODE0_0;
GPIOA->MODER &= ~GPIO_MODER_MODE0_1;
/* 01: Pull-up */
GPIOA->PUPDR |= GPIO_PUPDR_PUPD0_0;
GPIOA->PUPDR &= ~GPIO_PUPDR_PUPD0_1;
Также прерывание от
Таймера 11, частота 100 Гц (при APB2 = 16000000 Гц):
/* Clock Tim11 */
RCC->APB2ENR |= RCC_APB2ENR_TIM11EN;
/* T=10ms */
TIM11->PSC = 160-1;
TIM11->ARR = 1000-1;
/* Update Interrupt Enable */
TIM11->DIER |= TIM_DIER_UIE;
/* Counter enable */
TIM11->CR1 |= TIM_CR1_CEN;
/* Tim11 Interrupt enable */
NVIC_EnableIRQ(TIM1_TRG_COM_TIM11_IRQn);
В прерывании выполняем функцию:
void TIM1_TRG_COM_TIM11_IRQHandler(void){
if(TIM11->SR & TIM_SR_UIF){
/* GPIOA-0 KEY */
Debounce(&pres_pa0, &cnt_pa0, &prev_pa0, GPIOA->IDR, GPIO_IDR_ID0);
Debounce(&pres_pa7, &cnt_pa7, &prev_pa7, GPIOA->IDR, GPIO_IDR_ID7);
TIM11->SR &= ~TIM_SR_UIF;
}
}
И в главном цикле при каждом нажатии будет изменятся состояние свечения СИД и инкрементироваться значение переменной (чисто для примера):
while(1){
if(pres_pa0){
pres_pa0 = 0;
GPIOC->ODR ^= GPIO_ODR_OD13;
counter++;
}
}
Полный код:
Файл main.c
#include «main.h»
/****** Prototypes ******/
void Cnf_GPIO(void);
void Cnf_TIM11(void);
void Debounce(uint8_t *pres_px, uint8_t *cnt_px, uint8_t *but_px, uint32_t GPIOx_IDR, uint32_t GPIO_IDR_IDx);
/************************/
/********** PV **********/
/* PA0 */
uint8_t pres_pa0;
uint8_t prev_pa0;
uint8_t cnt_pa0;
/* PA7 */
uint8_t pres_pa7;
uint8_t prev_pa7;
uint8_t cnt_pa7;
/* Other */
uint32_t counter;
/************************/
int main(void)
{
/* Configuration */
Cnf_GPIO();
Cnf_TIM11();
while(1){
if(pres_pa0){
pres_pa0 = 0;
GPIOC->BSRR |= GPIO_BSRR_BR13;
counter++;
}
if(pres_pa7){
pres_pa7 = 0;
GPIOC->BSRR |= GPIO_BSRR_BS13;
counter—;
}
}
}
/*****************************************************/
void Cnf_GPIO(void){
/* GPIOC 13 OUT PP */
/* Clock GPIOC */
RCC->AHB1ENR |= RCC_AHB1ENR_GPIOCEN;
/* 01: General-purpose output */
GPIOC->MODER |= GPIO_MODER_MODE13_0;
GPIOC->MODER &= ~GPIO_MODER_MODE13_1;
/* 0: Output push-pull */
GPIOC->OTYPER &= ~GPIO_OTYPER_OT13;
/* 00: Low speed */
GPIOC->OSPEEDR &= ~GPIO_OSPEEDER_OSPEEDR13;
/* 00: Np pull-pull up, pull-down */
GPIOC->PUPDR &= ~GPIO_PUPDR_PUPD13;
/**********************/
/* GPIOA 0 IN PU */
/* Clock GPIOA */
RCC->AHB1ENR |= RCC_AHB1ENR_GPIOAEN;
/* 00: Input (reset state) */
GPIOA->MODER &= ~GPIO_MODER_MODE0_0;
GPIOA->MODER &= ~GPIO_MODER_MODE0_1;
/* 01: Pull-up */
GPIOA->PUPDR |= GPIO_PUPDR_PUPD0_0;
GPIOA->PUPDR &= ~GPIO_PUPDR_PUPD0_1;
/* GPIOA 7 IN PU */
/* Clock GPIOA */
RCC->AHB1ENR |= RCC_AHB1ENR_GPIOAEN;
/* 00: Input (reset state) */
GPIOA->MODER &= ~GPIO_MODER_MODE7_0;
GPIOA->MODER &= ~GPIO_MODER_MODE7_1;
/* 01: Pull-up */
GPIOA->PUPDR |= GPIO_PUPDR_PUPD7_0;
GPIOA->PUPDR &= ~GPIO_PUPDR_PUPD7_1;
}
void Cnf_TIM11(void){
/* Clock TIM11 */
RCC->APB2ENR |= RCC_APB2ENR_TIM11EN;
/* T=10ms f=100Hz */
TIM11->PSC = 160-1;
TIM11->ARR = 1000-1;
/* Update Interrupt Enable */
TIM11->DIER |= TIM_DIER_UIE;
/* Counter enable */
TIM11->CR1 |= TIM_CR1_CEN;
/* TIM11 Interrupt enable */
NVIC_EnableIRQ(TIM1_TRG_COM_TIM11_IRQn);
}
void TIM1_TRG_COM_TIM11_IRQHandler(void){
if(TIM11->SR & TIM_SR_UIF){
/* GPIOA-0 KEY */
Debounce(&pres_pa0, &cnt_pa0, &prev_pa0, GPIOA->IDR, GPIO_IDR_ID0);
Debounce(&pres_pa7, &cnt_pa7, &prev_pa7, GPIOA->IDR, GPIO_IDR_ID7);
TIM11->SR &= ~TIM_SR_UIF;
}
}
/**
* @brief Debounce function for button
* @note Perform it every 10-20ms (e.g. in timer’s interrupt)
* In main loop check first variable ((*pres_px), if (it > 0) nullify it and execute required code
* @param Three global variables, IDR register, Bit for check (e.g. &pres_pa0, &cnt_pa0, &prev_pa0, GPIOA->IDR, GPIO_IDR_ID0)
* @retval no
*/
void Debounce(uint8_t *pres_px, uint8_t *cnt_px, uint8_t *prev_px, uint32_t GPIOx_IDR, uint32_t GPIO_IDR_IDx)
{
/* Read current state */
uint8_t cur_px = (~GPIOx_IDR & GPIO_IDR_IDx) != 0;
/* If level has changed */
if (cur_px != *prev_px) {
/* Increase counter */
(*cnt_px)++;
/* If consecutive 4*10 = 40ms approved */
if (*cnt_px >= 4) {
/* The button have not bounced for four checks, change state */
*prev_px = cur_px;
/* If the button was pressed (not released), tell main so */
if (cur_px != 0)
{
*pres_px = 1;
}
(*cnt_px) = 0;
}
}
else {
/* Reset counter */
*cnt_px = 0;
}
}
Программный способ устранения дребезга кнопок
Самым простым способом справиться с проблемой дребезга кнопки является выдерживание паузы. Мы просто останавливаемся и ждем, пока переходный процесс не завершится. Для этого можно использовать функцию delay()или millis() (за подробной информации можете обратиться к статье про использование функций delay() и millis() в ардуино). 10-50 миллисекунд – вполне нормальное значение паузы для большинства случаев.
int currentValue, prevValue;
void loop() {
currentValue = digitalRead(PIN_BUTTON);
if (currentValue != prevValue) {
// Что-то изменилось, здесь возможна зона неопределенности
// Делаем задержку
delay(10);
// А вот теперь спокойно считываем значение, считая, что нестабильность исчезла
currentValue = digitalRead(PIN_BUTTON);
}
prevValue = currentValue;
Serial.println(currentValue);
}
В данном примере мы использовали задержку в программе, чтобы не реагировать на случайные всплески и определить реальную смену сигнала.
Борьба с дребезгом кнопки с помощью библиотеки ардуино
Проблема с дребезгом настолько популярна, что есть специальные библиотеки, в которых вам не надо организовывать ожидание и паузы вручную – это все делается внутри специального класса. Пример популярной библиотеки для борьбы с дребезгом кнопок – библиотека Bounce.
Пример использования библиотеки:
#include
Борьба с дребезгом библиотекой «bounce»
Как вариант борьбы с дребезгом в Ардуино — библиотека Bounce, которую можно скачать на Github.
Методы библиотеки:
Bounce() | инициализация объекта «Bounce»; |
void interval (мсек) | устанавливает время задержки в миллисекундах; |
void attach (номерПина) | задаёт вывод, к которому подключена кнопка; |
int update() | обновляет объект и возвращает true, если состояние пина изменилось, и false в противном случае; |
int read() | считывает новое состояние пина. |
Сам код.
#include
Подробнее в видосе
Устранение эффекта
Чтобы устранить дребезг контактов, возможно использовать аппаратное или программное решение. К аппаратным решениям относится:
- Установка конденсаторов параллельно входу. Тогда может снижаться быстродействие реакции на нажатие при слишком большой ёмкости и неполного устранения дребезга при слишком маленькой.
- Введение триггеров Шмидта во входную цепь устройства. Более сложное решение, которое затруднительно для реализации в ходе доработки уже готового изделия, но и более технологичное и совершенное.
Если рассмотреть это явление на примере сдвигового регистра, то в этом видео наглядно показано его воздействие. После каждого нажатия кнопки должен загораться следующий светодиод.
Схема включения регистра и светодиодов на рисунке ниже:
Кнопка подключена так, как показано на схеме:
Пример осциллограммы сигнала с выраженным дребезгом:
Установив конденсатор на 1 мкФ параллельно кнопке для его подавления, получаем стабильное и точное срабатывание:
Схема подавления:
А фронт сигнала переключения, как вы можете убедиться, действительно завален, зато без лишних всплесков.
Альтернативой такому решению защиты от этого эффекта, без заваливания фронта и с большим быстродействием является использование триггера Шмидта. Типовая его схема изображена ниже:
На следующем рисунке изображены другие варианты схем на логических элементах для борьбы с дребезгом контактов:
Кроме аппаратного устранения, как было сказано, есть и программный способ решения данной проблемы. Он заключается в написании кода, смысл которого в считывании изменения сигнала, выдержки определенного времени и повторного его считывания.
Пример программного подавления дребезга контактов в Arduino IDE вы можете скачать, перейдя по ссылке: код для подавления дребезга.