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

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

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

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

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

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

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

Суть заключалась в следующем: после срабатывания первого прерывания по смене логического уровня с высокого на низкий (при нажатии кнопки) запускался аппаратный таймер, настроенный на определённый период — как правило, это 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 модель

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


  1. Paulus_Engeneer
    01.07.2025 20:20

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

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

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

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

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


  1. Flammmable
    01.07.2025 20:20

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

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

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


  1. juramehanik
    01.07.2025 20:20

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


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

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