Несколько кнопок на одном прерывании, как устранить дребезг?

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

Моя цель состоит в том, чтобы одно прерывание обрабатывало все события (кнопки и другие цифровые входы). Я не хочу зависеть от loop(), я хочу иметь возможность часто использовать delay, а не прерывания по таймеру.
Большинство кнопок выполняют действие при нажатии, некоторые при нажатии.

Что у меня есть сейчас (пока только 2 кнопки):

схема

void setup() {
  pinMode(17, INPUT_PULLUP);
  pinMode(16, INPUT_PULLUP);
  pinMode(3, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(3), wotHappnd, CHANGE);
}

boolean isDebouncing(){
  unsigned int now = millis();
  if(now - time_lastPressed > time_debounceLockout){
    time_lastPressed = now;
    return false;
  }
  return true;
}

void wotHappnd(){
  boolean interruptFalling = digitalRead(3) == LOW;
  if(interruptFalling && isDebouncing()) return;
  // цифровое чтение пинов; делать вещи
}

Внутренние затяжки на всех используемых штифтах.

Моя проблема заключается в том, что часто (~4%) при прерывании контакт прерывания НИЗКИЙ, все контакты кнопок ВЫСОКИЙ ("не нажаты" - скорее всего, просто подпрыгивают). как я читал). Как это исправить?

Невозможно использовать задержку во время прерывания; delayMicroseconds для ожидания стабильных показаний по-прежнему кажется неуместным; задержка на основе колпачка на выводе прерывания вызывает период плавающего состояния. Предпочитают программные решения или не более 1 дополнительного компонента на вход.

[edit] здесь утверждается, что прерывания контакта уже выполняют некоторую фильтрацию , что, если оно истинно, может сделать некоторые решения ненадежными.

, 👍2

Обсуждение

Разве вы не можете поймать нажатие кнопки при следующем отскоке? Поскольку кнопка отскакивает несколько раз, должна быть одна, где она находится в НИЗКОМ состоянии достаточно долго, чтобы ее можно было поймать. Таким образом, в коде вам нужно будет проверить, нажата ли одна из кнопок, прежде чем вызывать функцию isDebouncing., @Gerben

@Gerben Это обычное устранение дребезга для всех кнопок. Достаточно для меня. Итак, вы предлагаете мне выполнять *digitalRead* в цикле, пока я где-нибудь не получу *LOW*?, @kaay

Нет. Сделайте два цифровых чтения для двух кнопок в ISR. Если оба высокие, ничего не делайте. В противном случае выполните код, который у вас теперь есть в ISR., @Gerben

Ой. Тем не менее, *уверенно* ли, что прыгающая кнопка вызовет поток прерываний? Я спрашиваю, потому что я где-то читал (Electrical Engineering StackExchange?), что уже есть некоторая гарантия стабильности сигнала, сделанная для прерываний в некоторых микроконтроллерах, чтобы предотвратить именно это. Кроме того, я понятия не имею, какое влияние здесь могут иметь диоды или другие подключенные контакты, если таковые имеются., @kaay

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

1) По какой причине вы не attachInterrupt(..., FALLING)? 2) MCU не фильтрует внешние прерывания., @Edgar Bonet

@EdgarBonet Я забыл термины для этого, поэтому написал: «Большинство кнопок выполняют действие при нажатии, некоторые при нажатии». Что касается последнего, я должен знать, когда они будут выпущены., @kaay


2 ответа


Лучший ответ:

1

В Isr прочитайте два вывода и сохраните их текущий статус (UN debounced) и сбросьте счетчик.

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

Или Google Kuhn разоблачен. Я написал об этом страницу в блоге. Если хотите, могу выложить позже. Основная идея та же.

,

Спасибо, что напомнили мне о разоблачении Куна. Жаль, что для этого нужен опрос в основном цикле, чего я не хочу делать. Опрос без задержки не даст такого же результата... может опрос по прерыванию таймера? Хм..., @kaay

Подход, который я предложил, по сути является отказом Куна от дребезга, без опроса кнопок. Вместо этого вы увеличиваете счетчик как способ обнаружения стабилизированных кнопок., @dannyf

Извините, я неправильно понял раньше. Тем не менее, что меня отталкивает, так это зависимость от того, что основной цикл не имеет длительных задержек. Кроме того, есть идеи о том, что находится в 4-м комментарии под вопросом? Не будет ли прерываний *CHANGE* меньше, чем изменений на контакте кнопки (без прерывания)?, @kaay

Не требуется, чтобы основной цикл имел какие-либо задержки, длинные или короткие., @dannyf

Любое решение, использующее *loop()*, требует, чтобы *loop()* НЕ имело длительных задержек. Кун повторяет 10 раз в секунду. Arduino — это платформа для прототипирования — совершенство оставлено на потом, а пока я настраиваю генерацию сигнала с помощью *delay*., @kaay

Принимая это, поскольку кажется, что для моего сценария не существует более удобного метода, чем блокировка, оставляя * цикл * и аппаратные решения. Спасибо., @kaay


2

Как всегда, я выступаю за несогласие: никогда не пишите программы для решения аппаратных проблем.

Для двойного переключателя классическим решением является защелка SR.

Одиночный бросок на самом деле сложнее. На первый взгляд, устранение дребезга — тривиальная задача, выполняемая с помощью конденсатора и подтягивающего (или подтягивающего) резистора. Это, безусловно, остановит плавающие и ложные срабатывания от наведенного тока от всплесков. Однако микропроцессоры переключаются довольно быстро и распознают края микросекундных колебаний напряжения переключения как изменения состояния переключателя. Чтобы предотвратить это, вам нужен гистерезис триггера Шмитта, такого как LM7414 (TTL) или LM7417 (подходит для 3V3).

Вот схема устранения дребезга, предложенная в Понимание триггеров Шмитта. К сожалению, он не работает корректно при любых условиях по причинам, описанным на странице Ganssle, ссылка на которую приведена ниже.

Почти, но плохо работает в нестандартных условиях

Решить проблему можно с помощью диода. Для ТТЛ R1 = 82 кОм, R2 = 18 кОм, C = 1 мкФ

надежный

Большие значения C будут поглощать более медленные отказы. В одном из моих проектов есть реле, которое прыгает так долго, что мне понадобилось 470µF.

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

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

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

Это не значит, что нет других способов решения проблемы.

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

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

void isr_change()
{
    if (listen)
    {
        unsigned long now = millis();
        int d2 = digitalRead(2);
        if (d2 == LOW || fall_time == 0)
        { // ПАДЕНИЕ
            fall_time = now;
        }
        if (d2 == HIGH)
        { // ПОДЪЕМ
            command_pending = now - fall_time > MIN_PULSE_MS;
        }
    }
}

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

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

Спасибо kaay в комментариях за ссылку на MC14490, который представляет собой DIP16 или SOIC16 с шестью устройствами защиты от дребезга, защищенными диодами. Каай считает, что это дорого, но примите во внимание затраты времени на кодирование и отладку устранения дребезга шести входных данных. Как насчет стоимости, когда программа не совсем подходит, и вам нужно переписать ее, чтобы уменьшить? А затем провести регрессионное тестирование всего. Вы бы заплатили кому-то 5 долларов за мгновенный гарантированный результат, который не усложняет и не раздувает ваше программное обеспечение? Экономика, конечно, меняется в зависимости от масштаба производства, но я думаю, что при очень малых тиражах это того стоит.

Я нашел MC14490 DIP16 за 5 долларов и SOIC за 9 австралийских долларов в Интернете. В местных магазинах его не было.

,

Один вверх и один вниз. Жаль, что голосующий против не удосужился сказать, почему он считает это плохим ответом., @Peter Wone

Я не против, но я вижу, что аппаратное обеспечение дороже, чем программное обеспечение, с точки зрения деталей, реального состояния платы, времени сборки..., @Edgar Bonet

@EdgarBonet Надеюсь, вы это видите, я подробно обсуждал это в предпоследнем абзаце., @Peter Wone

@EdgarBonet больше не предпоследний абзац, но это было, когда вы его читали. Я добавил некоторые материалы, чтобы помочь людям с узким зрением., @Peter Wone

+1 за усилия. Этот ответ собирает несколько хороших идей, и даже если он не соответствует требованиям вопроса, он полезен. Хотя, должен не согласиться с «(стоимость) не имеет значения для одноразового использования» - для большинства шлепок на Shmitt&TheRest будет стоить от 20 минут (в маловероятном случае, у них есть все под рукой) ПЛЮС тестирование, до нескольких часов. И это ОСОБЕННО обидно, если все, что вы получаете, это одна единица. Микросхемы Debouncer - у меня была точно такая же мысль! Насколько я понимаю, по такой цене MC14490 не существует., @kaay

@kaay, возможно, во многом это вопрос ценностей. Я подозреваю, что большинство проектов Arduino — это труды любви, где одним из результатов является удовлетворение как от того, что вы делаете это сами, так и от того, что проектируете его самостоятельно. Учитывая негативную реакцию, я могу ошибаться. Причина, по которой я думаю, что аппаратное устранение дребезга может быть дешевле, чем программное обеспечение для очень небольшого тиража, заключается в стоимости контроля качества программного обеспечения и стоимости обновления прошивки., @Peter Wone