Привет Хабр! Сегодня хочу поделиться опытом разработки небольшого модуля электронного циферблата на базе семисегментных дисплеев. Помимо этого, также рассмотрим способ устранения «дребезга контактов» механической кнопки, который я подсмотрел в одной известной книге и опробовал самостоятельно.

Вечная проблема

Думаю, каждый, кто работал со встраиваемыми системами, сталкивался с этой проблемой: когда проект требует подключения механической кнопки для самых разных задач, но всегда возникает одна и та же трудность — несовершенство механизма замыкания. То есть, вы нажимаете кнопку один раз, но контроллер воспринимает это как многократное нажатие. А в системах, где логика работы строится на количественном подсчёте нажатий, это может привести к серьёзным сбоям.

Паразитный дребезг
Паразитный дребезг

Даже подключение кнопки к пину с прерыванием не избавляет от проблемы: прерывание просто срабатывает несколько раз подряд. Конечно, вместо механической кнопки можно использовать сенсорную — она лишена этого недостатка. Однако это не всегда уместно, и внедрить её можно не во все системы. К тому же сенсорная кнопка может срабатывать произвольно — при случайном касании.

Программный метод борьбы

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

Суть заключалась в следующем: после срабатывания первого прерывания по смене логического уровня с высокого на низкий (при нажатии кнопки) запускался аппаратный таймер, настроенный на определённый период — как правило, это 50 мс. После срабатывания таймера прерывание вызывало событие обработки нажатия: увеличение счётчика, смена положения стрелки в меню и т.д.

Плата stm32f103c8t6
Плата stm32f103c8t6

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

Аппаратный метод

Решение, взятое мною является аппаратным, построенным на простой RC-цепи и инвертирующем триггере Шмитта. Преимущество в том, что схема полностью снимает нагрузку с микроконтроллера. Решение я подсмотрел в книге Джереми Блума "Изучаем Arduino".

Вот основные компоненты:

  • Резистор 220 Ом (по книге — 100 Ом),

  • Конденсатор 10 мкФ,

  • Подтягивающий резистор 10 кОм,

  • Инвертирующий триггер Шмитта (например, 74HC14).

Первая часть схемы работает на RC-цепи, формирующей задержку по смене фронта, длительность которой определяется по формуле: t = RC. Подставим значения в формулу и получим 1 мс. Общий график сигнала RC-цепи представлен ниже.

Затем полученный сигнал поступает на инвертирующий триггер Шмитта — устройство, приводящее аналоговый сигнал к стабильным логическим значениям. В зависимости от модели и производителя, триггер Шмитта обладает порогами срабатывания по напряжению: 2,5 В для восходящего и 1,6 В для нисходящего фронта при амплитуде 5 В. Так как мы используем инвертирующий триггер Шмитта, он работает по обратному принципу: когда сигнал преодолевает верхний порог срабатывания, на выходе образуется логический ноль, а когда — нижний порог, логическая единица. Общая схема представлена ниже.

Схема с подключённым виртуальным осциллографом
Схема с подключённым виртуальным осциллографом

Я собрал данную схему в программе для моделирования электрических схем — Multisim, чтобы на программном осциллографе продемонстрировать работу схемы. Единственное, что я заменил — резистор 100 Ом на 220 Ом. Красным отмечен сигнал после RC-цепи, жёлтым — готовый сигнал, поступающий на пин прерывания после преодоления триггера Шмитта. На осциллограмме видны импульсы, происходящие в моменты нажатия кнопки. Для начала, за счёт RC-цепи происходит нисходящий фронт, и из-за этого на выходе триггера устанавливается логическая единица. Затем происходит плавное нарастание фронта, и, когда он проходит определённую грань, на выходе получается логический ноль. В этом и заключается работа всей схемы.

Осциллограмма
Осциллограмма

Пример практического применения: модуль индикации

Модуль представляет собой электронный циферблат на четырёх семисегментных индикаторах и двух светодиодах диаметром 3 мм (используются для индикации секунд, как на цифровых часах).

Архитектура:

  • Индикация организована через два сдвиговых регистра 74HC595.

    • Первый регистр управляет сегментами (A–G и DP),

    • Второй — выбором активного индикатора (общего анода или катода).

  • Управление регистрами осуществляется через три линии:

    • SER (DIO) — данные,

    • SRCLK (SCLK) — тактирование,

    • RCLK (LATCH) — защёлка.

  • Дополнительно используется пин ~OE (Output Enable), на который подаётся ШИМ-сигнал для регулировки яркости дисплея.

  • Перемычка Jumper1 позволяет выбрать: управлять двумя светодиодами с одного пина, либо независимо с двух.

Схема модуля
Схема модуля

Ключевым блоком данной схемы является управление механическими кнопками, подключёнными по схеме, разобранной ранее. Выходы с триггера Шмитта выведены на отдельные коннекторы. Индикация циферблата осуществляется с помощью STM32, данные на сегменты поступают по интерфейсу SPI, а управление осуществляется через четыре механические кнопки.

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

Внизу можно наблюдать 3D-модель платы, созданную в программе EasyEDA.

Спасибо за прочтение! Если есть что добавить или подправить — пишите, будет любопытно почитать!

3D модель
3D модель

Комментарии (66)


  1. Paulus_Engeneer
    01.07.2025 20:20

    Можно добавить к программному методу еще один:

    Скрытый текст
    1. создаем программный счетчик, который инкриминируется, если кнопка нажата и декриментируется если кнопка отжата (без переполнения);

    2. создаем флаг, который принимает свое значение в зависимости от пересечения верхнего или нижнего установленного порога (обеспечит гистерезис положения нажато/отжато);

    3. добавляем опрос кнопки в бесконечном цикле.

    Это позволит сэкономить аппаратный счетчик и деньги на рассыпухе и площади платы


    1. mmMike
      01.07.2025 20:20

      Ну ну..
      Ключевая концептуальная ошибка: "опрос"+"счетчик".

      который инкриминируется, если кнопка нажата и декриментируется если кнопка отжата

      Получите неопределенное значение. Потому что, момент опроса и момент переходных процессов при нажатии (дребезг) вообще могут не совпасть.

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


      1. nUser123
        01.07.2025 20:20

        Но ведь неопределенное значение станет определенным в следующий или чуть более поздние опросы. Да, для энкодера не годится, но для кнопки вроде норм, если принять, что основой цикл всегда выполняется за одинаковое время. Для опроса через +/- равные промежутки времени использовал системный таймер.


        1. mmMike
          01.07.2025 20:20

          тогда зачем фраза

          программный счетчик, который инкриминируется, если кнопка нажата и декриментируется если кнопка отжата

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

          Я так, понимаю, что автор рассматирвал вопрос сложности определения момента "нажатия" на кнопку как фиксации события "нажата". А не просто определения факта "нажата/не нажата"


          1. nUser123
            01.07.2025 20:20

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


            1. mmMike
              01.07.2025 20:20

              первая строка значение на входе контроллера (*)
              вторая строка - считываение в период опроса.
              третья строка - типа счетчик
              000001010101010101010100111101000101111111111100111011111111111..0100100001110000000
              0____1____0____1____1____1____0____1____0____0____1..0____1____1____0____
              __ -1____0____-1____0____1____2____1____2___-1____-2___-1__.. 345__346__347__346___

              Ну и что конретно даст значение счетчика для анализа по предложенному...

              программный счетчик, который инкриминируется, если кнопка нажата и декриментируется если кнопка отжата.

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

              (*) - условно. значени если бы опрашивали порт в данный момент. Тема для превращения в 0/1, фактически аналогового сигнала дребезка, не проста. Но можно не вдаваться и считать 0/1.


              1. Genoik
                01.07.2025 20:20

                А не могли бы пояснить, где на вашей картинке переходный процесс ?

                По-моему, там просто случайные 0 и 1, приходящие на порт МК.


                1. mmMike
                  01.07.2025 20:20

                  Если снять осцилограмму с кнопки в момент ее нажатия/отпускания (хорошим осцилографом с малой емкостю и большим входным сопростивлением). То будет видна характерная картина. Собствено это и есть "дребез контакта".
                  наберите "дребез контакта осциллограмма" в поиске. Там будут картинки примера дребезка на осцилографе.

                  В зависимости от физического исполнения "кнопки", емкости на входa, входного сопротивления входа и пр. может быть разной формы.. разной длитетельности (может до 5-10ms).

                  По-моему, там просто случайные 0 и 1, приходящие на порт МК.

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

                  4-й курс (времена динозавов правда).. схемотехника.. лаба посвященная этому. "Что бы запомнили".
                  Для меня электроника и схемотехника - хоби. Но запомнил жжж..


                  1. Genoik
                    01.07.2025 20:20

                    Вы не поняли вопрос.

                    Я попросил отметить, ГДЕ именно на вашей картинке переходный процесс, который должен с течением времени закончится. Он потому и называется переходный.

                    То есть, картинка должны быть типа такой: 0110101010101011111111111.

                    И вот этих вот 111111, на вашей картинке не видно, то есть ваша условная кнопка выдает дребезг ВСЕГДА. Что не является правдой, если кнопка исправна.


              1. nUser123
                01.07.2025 20:20

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


                1. ahabreader
                  01.07.2025 20:20

                  Он про алиасинг говорит. Контакты дребезжат с частотой до f, а выборку делаем с частотой явно ниже 2*f и Котельников нам напоминает, что мы рискуем увидеть ошибочную картину.

                  Ух какой шустрый мух
                  Ух какой шустрый мух

                  Но этот риск можно счесть приемлемым.

                  А можно иначе рассудить - если кнопка будет до ~100 мс дребезжать, то зачем вообще её повторно опрашивать в это время? Чтобы собирать статистику по длительности дребезга и реализовывать антидребезг, адаптирующийся к старению кнопок? Ну-ну. В одной статье упоминают возможный "short glitch" в нажатом состоянии - это, видимо, про полунажатое состояние в случае с мягкими мембранами как в пультах или компьютерных клавиатурах.


                  1. nUser123
                    01.07.2025 20:20

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


                    1. ahabreader
                      01.07.2025 20:20

                      Этот счётчик должен испытать экзистенциальный кризис. Если решение принимается по такому числу отсчётов, которое в сумме дольше возможного дребезга, то что полезного он считает? Если мы только фильтруем дребезг, то ничего полезного - антидребезг с мгновенной реакцией + dead time будет лучше.

                      Чья-то реализация: https://www.eevblog.com/forum/beginners/keyboard-switch-matrix-hw-debounce-multiplexer/msg3926876/#msg3926876

                      Если мгновенная реакция не нужна, то решение сводится к редкому опросу с периодом, совпадающим с выбранным dead time (как в комментах ниже про 0,5 секунды и 200 мс).


              1. Antares1991
                01.07.2025 20:20

                А давайте не будем натягивать сову на глобус и всё-таки примем 1 условие: размер программного счётчика и частота опроса GPIO должны быть подобраны так, чтобы при максимальной частоте полезного сигнала счётчик успевал пройти весь цикл. В таком случае: 1-я строка - данные от GPIO, 2-я значение счётчика, 3 - отфильтрованное состояние кнопки, которое предоставляется остальным программным модулям вместо данных напрямую из GPIO.
                0000010101101111111111010110010000000
                0000010101212345555555454554343210000
                0000000000000001111111111111111110000
                Такой алгоритм работает у меня и моих коллег в тысячах устройств по всему миру, и доказал свою состоятельность. И с энкодерами тоже всё хорошо работает, просто частоту опроса GPIO надо приподнять, и обработчику энкодера фильтрованные данные давать, а не с GPIO напрямую. Если надо нервно на один из фронтов реагировать - тоже пожалуйста, с минимальными правками всё делается:
                0000010101101111111111010110010000000
                0000054545545555555555454554343210000
                0000011111111111111111111111111110000
                А если речь идёт о "точная координата оси станка после часа его работы", то, по-хорошему, надо энкодер соответствующий использовать, а не лепить из того есть под рукой. Хотя, если с умом подойти, то и из подножного корма можно конфетку собрать, но тут уже изощряться надо, решение "в лоб" обычно порождает много "но".


                1. mmMike
                  01.07.2025 20:20

                  У вас в примере магическим образом частотад дребезка это константа, совпадающая с
                  частотой опроса.
                  А проблемы алиасинга так же магически "частоту опроса GPIO надо приподнять".

                  Мне больше нечего сказать на это..


      1. LinkToOS
        01.07.2025 20:20

        Очень типичная ошибка "опросом" + "счетчик".

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

        Например, так же нельзя опросом энкодер считывать.

        Квадратурный энкодер обрабатывается как две кнопки.

        Если конечно интересует не "качественные" показатели (типа крутилка громкости), а накомительное значение (ось станка и пр.).

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


        1. mmMike
          01.07.2025 20:20

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

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

          Квадратурный энкодер обрабатывается как две кнопки.

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

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

          Для "крутилки громкости", зачастую достаточно в фоновом процессе (прерывание по таймера раз в 50ms) тупо считывать состояние и риск возникновения дребезга в момент считывания не учитывать.. кнопки/энкодеры типа "крутилки громкости" - интерактивны. Щелчком больше/меньше значения не имеет вообще.


    1. Ig_B
      01.07.2025 20:20

      >Можно добавить к программному методу еще один:

      В дополнение имеем возможность определять длинное нажатие.

      И для этого метода есть "вертикальные" счетчики.


    1. Antares1991
      01.07.2025 20:20

      А ещё можно специализированные микросхемы использовать, например HT16K33 со встроенным подавлением дребезга (не идеальным, но лучше, чем ничего). Есть ещё TM1638, но не знаю, есть ли у неё встроенное подавление дребезна.


  1. Flammmable
    01.07.2025 20:20

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

    По этой причине, а также чтобы не городить кучу RC-цепочек с непонятным разбросом параметров, в реальности, когда требуется избавить от дребезга сразу несколько кнопок, применяют специальные микросхемы подавления дребезга вроде MC14490. Которые после первого фронта на входе, отсчитывают N тактов и лишь затем выдают значение на выходе.

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


    1. tklim
      01.07.2025 20:20

      У вас, неактуальная или нерелевантная информация. Как раз наоборот, микроконтроллеры (а тут упомянут stm32) обычно итак имеют на входе триггер Шмитта.

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

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


      1. Flammmable
        01.07.2025 20:20

        У вас, неактуальная или нерелевантная информация. Как раз наоборот, микроконтроллеры (а тут упомянут stm32) обычно итак имеют на входе триггер Шмитта.

        У триггера Шмитта та же базовая проблема. Да, он не переключится в лог.1, если вы не доведёте уровень напряжения от лог.0 до напряжения переключения. Но у него также в большинстве случаев есть такое входное напряжение, при котором приоткрывается и верх и низ.

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

        Сейчас попробую предложить DeepSeek "написать статью на Хабр про дребезг контактов и способ борьбы с ним".


        1. LinkToOS
          01.07.2025 20:20

          У триггера Шмитта та же базовая проблема. Да, он не переключится в лог.1, если вы не доведёте уровень напряжения от лог.0 до напряжения переключения. Но у него также в большинстве случаев есть такое входное напряжение, при котором приоткрывается и верх и низ.

          Не должно быть такого эффекта.


          1. Flammmable
            01.07.2025 20:20

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


      1. Flammmable
        01.07.2025 20:20

        Чёёёрт! ))))) Реально по промту "Напиши статью характерным для Хабра языком о том как я справился с дребезгом контактов от кнопки." DeepSeek написал заметно более интересную и живую статью!


        1. Antares1991
          01.07.2025 20:20

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


  1. juramehanik
    01.07.2025 20:20

    Емкость 10мкф крайне перебор. 10нф-100нф на практике достаточно. ну можно просто не вешать обработку кропки на прерывание там где это возможно, столько проблем сразу уйдет.


    1. Danchkin_Sab Автор
      01.07.2025 20:20

      Касательно ёмкости конденсатора могу сказать что путём эксперимента были проверены разные значения, в том числе и 100нф и в конце было выявлено что 10 мкФ оптимальнее всего, а что же касается прерывания бывают моменты когда их использование корректнее всего


      1. juramehanik
        01.07.2025 20:20

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


  1. LaoWai2000
    01.07.2025 20:20

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

    Но в принципе, если вы реализуете динамическую индикацию, оч легко организовать цифровую фильтрацию кнопки. Каждый раз во время регенерации просто сдвигаете состояние пина кнопки в переменную, например uint8_t, то если она будет 0xff, то нужно перебросить бит кнопки в одно состояние, а если 0, то в другое. Не хватит восьмого инта, есть 16 или 32)))


    1. LinkToOS
      01.07.2025 20:20

      Десяточка мкФ конденсатора фильтра может вытечь через защитные диоды на входе триггера Шмитта на шину питания, это может привести к выходу из строя мсх триггеров Шмитта.

      Ток через защитные диоды потечет при отключении питания. Если по линии питания установлена маленькая емкость, то ток через диоды будет максимальным, и будет зависеть от тока потребления устройства.
      У защитных диодов максимальный допустимый ток 20мА. В схеме 4 цепочки. Значит при потреблении до 80 мА должно обойтись без последствий. В грубом приближении.


      1. LaoWai2000
        01.07.2025 20:20

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

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


  1. REPISOT
    01.07.2025 20:20

    Даже подключение кнопки к пину с прерыванием не избавляет от проблемы

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


  1. technomancer
    01.07.2025 20:20

    Согласен с уже высказавшимися. Есть давно устоявшиеся алгоритмы обработки дребезга контактов. Можно обойтись и без дополнительного таймера, и без прерываний вообще. Вы молодец. Сделали красиво. Но дорого. И чем больше кнопок, тем дороже. А программная обработка сколько-то будет стоить только в тех редких случаях, когда ресурсы чипа уже забиты под завязку , что бывает крайне редко: обычно стараются брать с хотя бы небольшим запасом. И всё равно переход на следующий в каталоге микроконтроллер окажется дешевле дополнительных деталей, дополнительного места, дополнительных операций по монтажу.

    Но технически - да - работает здорово.

    P.S. У микроконтроллера, кстати, вход точно так же определяет логическую единицу по "больше порогового напряжения/меньше порогового напряжения", так что дополнительный триггер можно было и не ставить.


  1. SlFed
    01.07.2025 20:20

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


    1. LinkToOS
      01.07.2025 20:20

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

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


      1. SlFed
        01.07.2025 20:20

        Ну если так говорить, то у меня на схеме двухэлементный повторитель с положительной обратной связью и ёмкостной развязкой :)))))

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

        Установка одновибратора для устранения дребезга контактов - это стандартный прием применяющийся с 70-х годов (во всяком случае меня в институте так учили).


        1. LinkToOS
          01.07.2025 20:20

          и ёмкостной развязкой

          Это не емкостная развязка, а дифференцирующая цепь.

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

          У автора не одновибратор.


  1. Bagatur
    01.07.2025 20:20

    • Собственно, из аппаратного можно использовать одновибратор. Для себя такое реализовывал на копеешной ne555, предусматривающей соответствующую схему включения. Но у меня задача была достаточно тривиальная - дополнительная кнопка к магнитоле, там частота нажатий пальцем не более 2 раз в секунду, задержка на одновибраторе выставлялась достаточно большая.


  1. longtolik
    01.07.2025 20:20

    Плата, которую Вы привели на фото - Blue Pill - может выдавать дребезг даже при работе с хорошим датчиком. Схемы этих плат различаются как количеством элементов, так и схемой получения 3.3 V.

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

    Для них нужно применять фильтрацию как по питанию, так и по цепям датчиков.


  1. Prohard
    01.07.2025 20:20

    А зачем механика. Как минимум есть ТТР223.


  1. MinimumLaw
    01.07.2025 20:20

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

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


    1. Ivanii
      01.07.2025 20:20

      RC цепочка все равно нужна для подавления наводок и выбросов при замыкании кнопки.

      Резистор ставится максимально близко к кнопке последовательно кнопке, конденсатор около МК. Подтяжка и софтовые методы про вкусу.


    1. Antares1991
      01.07.2025 20:20

      Ну, раз говорим про самый надёжный, то тогда надо триггер на каждую кнопку лепить, и кнопки с переключающим контактом использовать. А что за схема с супервизором? Хотелось бы расширить кругозор...


      1. MinimumLaw
        01.07.2025 20:20

        Например MAX6817 или ей подобные. Не сказать что их много, но и совсем не экзотика.


  1. Dark_Purple
    01.07.2025 20:20

    Замыкать 10uF кнопкой, даже через 100 Ом, такое себе.


    1. Antares1991
      01.07.2025 20:20

      50мА в пике, в чём проблема? Другое дело, что постоянная времени очень большая, быстрые нажатия будут игнорироваться. Я обычно использую 10к, 100нФ - проблем не знаю.


      1. Dark_Purple
        01.07.2025 20:20

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


  1. Mishootk
    01.07.2025 20:20

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


  1. LeonidPr
    01.07.2025 20:20

    Самый простой софтовый вариант имхо:

    Заводим счетчик и переменную, куда сохраняем текущее состояние кнопки.

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

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


    1. LinkToOS
      01.07.2025 20:20

      Самый простой софтовый вариант, это таймер блокирующий опрос. Зафиксировали нажатие, установили счетчик. По прерыванию уменьшаем счетчик. Пока счетчик не обнулился, кнопку игнорируем. Таймер на 0,5 секунды разрешит два нажатия в секунду. Легко сделать автоповтор при нажатой кнопке.
      Дубовый метод. Не подходит для игровых мышей.


      1. LeonidPr
        01.07.2025 20:20

        У этого способа есть один минус. Если идут помехи, или просто возможно кратковременное случайное нажатие, то можем его (или ее - помеху) зарегистрировать как нажатие на кнопку и пока блокирующий таймер активен, мы считаем, что кнопка нажата.

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

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

        Но с точки зрения простоты, согласен, ваш способ проще.


  1. ahabreader
    01.07.2025 20:20

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

    Причину придумать можно - борьба с какими-то злостными помехами, но тогда бы недоверие к первому отсчёту (это не контакт замкнулся, это молния рядом ударила) проговаривалось явно и перечислялось вместе с другими необходимыми мерами защиты от электромагнитных помех, а так это просто ошибка.


    1. Antares1991
      01.07.2025 20:20

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


      1. ahabreader
        01.07.2025 20:20

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

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


  1. AVKinc
    01.07.2025 20:20

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


  1. kenomimi
    01.07.2025 20:20

    Делал так: в программе на любое количество кнопок 1 счетчик. Если он 0, то прилетевшее прерывание добавляет 1 к счетчику и выполняет основной код, если нет - происходит сброс таймера и выход из прерывания. Дальше таймер сбрасывает счетчик по факту прерывания на переполнении. То есть какое-бы не было время дребезга и сколько бы фронтов не прилетело, валидным будет только первый фронт.


  1. iShrimp
    01.07.2025 20:20

    А пробовал ли кто-нибудь извлекать из этого переходного процесса полезную информацию - например, о скорости или силе нажатия на кнопку?

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


    1. Danchkin_Sab Автор
      01.07.2025 20:20

      Хорошая мысль, спасибо!!


    1. Danchkin_Sab Автор
      01.07.2025 20:20

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


    1. Megavolt75
      01.07.2025 20:20

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


  1. jingobo
    01.07.2025 20:20

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


  1. slog2
    01.07.2025 20:20

    Вечная проблема

    Это проблема для цифровых схем на рассыпухе. Если кнопка подключена ко входу процессора то никакой проблемы нет.


  1. randomsimplenumber
    01.07.2025 20:20

    Если просто перечислить все способы, которыми эта проблема успешно решалась - будет статья с таким же объемом, а то и больше.


  1. bvaleri
    01.07.2025 20:20

    По сигналу с пина кнопки запоминаем текущий счетчик тиков и через 50 мсек проверяем состояние пина. Если то же, то обрабатываем нажатие кнопки. Или второй способ -- сглаживание: state = state * 0.99 + new_state * 0.01. if state < 0.1 pressed(); if state > 0.9 released().


    1. randomsimplenumber
      01.07.2025 20:20

      через 50 мсек

      Время срабатывания есть в даташите на кнопку. Можно умножить на 2.

      А можно просто после первого сигнала игнорировать следующие в течение этого времени. Если это датчик на валу, например.