Продолжительность дребезга кнопки

Тема в разделе "Схемотехника, компоненты, модули", создана пользователем DrProg, 25 янв 2016.

  1. Пушной звер

    Пушной звер Оракул Модератор

    главное чтобы мне недовольные клиенты на почту не писали с просьбами разобраться с проектами таких вот гуру инженерной мысли.
     
    Последнее редактирование: 26 янв 2016
  2. DrProg

    DrProg Вечный нерд

    Что, уже пишут? А ведь обещали не перебегать!
     
  3. Onkel

    Onkel Гуру

    тут половина жалоб - серва дрожит, и еще много просьб сделать что-то вроде "отключения через 120 секунд". Но вообще говоря таймер - первичен,
    при грамотной разводке все помехи много ниже уровня 0. При неграмотной - да, любой формы и длины и в любой момент.
     
  4. Unixon

    Unixon Оракул Модератор

    ISR(TIM0_OVF_vect) или ISR(TIMER0_OVF_vect), см. wiring.c
     
  5. Onkel

    Onkel Гуру

    Пасиб. Сейчас срочная работа - надо силовые диммеры подготовить, скоро сезон фонтанный. А как так сразу и попробую. Что не мешает некоторым докторам тоже попробовать. В субботу не забудете подъехать?
     
    DrProg нравится это.
  6. DrProg

    DrProg Вечный нерд

    Попробовать андидребезг на таймерах? Нет уж, такого намазывания хлеба на масло я не потяну. Беру подсказку зала. Пусть кто-нибудь расскажет алгоритм хотя бы на словах.
     
  7. DrProg

    DrProg Вечный нерд

    Хотя нет, одна идея есть. Интересно, совпадает ли с ответом? Как бы проверить?
     
  8. DrProg

    DrProg Вечный нерд

    Ладно, вот мой вариант программного антидребезга на примере таймера 1А МК Atmega8. Можете критиковать до посинения, но только он действительно работает. О плюсах и минусах ниже.

    Суть процесса: Запускаем таймер с прерыванием каждые несколько миллисекунд (на примере ниже - 20мс), в котором опрашивается состояние искомого пина. Запоминаем его. В следующий вызов вновь опрашиваем состояние пина и сравниваем его с запомненным в прошлый раз. Если они равны, значит считаем его состояние устоявшимся и заносим его в специальную глобальную переменную. То есть как бы дважды опрашиваем и сравниваем, что собственно делается и в классических вариантах программного подавления, только делаем это постоянно вне зависимости от того чем занят МК в этот момент. На выходе получаем стабильное, в заданный промежуток времени, значение пина.

    Пример. Берем традиционное задание призванное проиллюстрировать дребезг и борьбу с ним. Оставляем только вкл-выкл светодиода, который без дополнительной заботы, естественно, будет вкл-выкл непредсказуемо. Добавляем наш сабж и получаем примерно следующее:
    Код (C++):
    // Atmega8 8MHz-Int
    // E4
    // D9

    volatile bool button = 0;
    volatile bool button_old = 0;
    volatile bool button_press = 0;

    bool press_old = 0;
    bool light = 0;

    void setup() {
      pinMode(13, OUTPUT);
      pinMode(8, INPUT_PULLUP);

      TCCR1A = 0;     // настройка таймера 1А
      TCCR1B = 3;
      OCR1A = 0x09C3; // 20мс
      TIMSK = 0b00010000;
      sei();
    }

    void loop() {
      if (!button_press and press_old) {
        light = !light;
        digitalWrite(13, light);
      }
      press_old = button_press;
    }


    ISR(TIMER1_COMPA_vect)
    {
      button = PINB & 1; //digitalRead(8);
      if (button == button_old) button_press = button;
      button_old = button;
      TCNT1 = 0;
    }
    Булева переменная button_press и есть то что нам нужно.

    Для наглядности примера на этом видео я увеличил время антидребезга до 50мс, чтобы иметь возможность имитировать дребезг вручную. Минимальное время за которое я успевал нажать-отжать кнопку 30-35мс. На видео я то нажимаю кнопку медленно, что влечет переключение светодиода, то быстро (ударом), что успешно игнорируется системой как дребезг.



    Плюсы и минусы метода с тз моего ИМХО:
    + действительно работает и стабильно,
    ++ пользоваться "устаканенным" состоянием пина можно в любом месте программы без необходимости каждый раз копипастить код считыаания и подавления,
    ++ практически не тормозит программу,
    + можно использовать в качестве программной антипомехи,
    + при необходимости можно менять параметры налету в процессе работы,
    + прикольно выглядит.

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

    Итого: квест проходимый, задачка интересная.

    Теперь особенно хочется посмотреть на другие уже готовые решения для сравнения и извлечения выводов. Жду.
     
    Последнее редактирование: 27 янв 2016
  9. Максимус-Бог

    Максимус-Бог Убийца матрёшек

    Почему бы не использовать схему с тригером шмита (20ый эксперемент)
     
    Пушной звер нравится это.
  10. Onkel

    Onkel Гуру

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

    Onkel Гуру

    обычно так и делают, но я ни разу не слышал, чтобы прерывание по изменению состояния порта называли "извращением". Это что получается, если вы нажали кнопку на пульте (вызвав тем самым в мк пульта функцию обработки прерывания), вы соучастник извращения?
     
  12. Gurf

    Gurf Нуб

    По-моему так и сделано в готовом примере антидребезга, зашитого в Arduino Ide. Примеры - Digital - Debaunce. Любопытно, что этот упомянутый скетч был создан в 2006 г. потом его еще редактировали в 2011 и 2012 г. Видимо, проблема антидребезга полна нюансов...
     
  13. Onkel

    Onkel Гуру

    проблема антидребезга и всех ее нюансов решается конденсатором 0,1 uF и пятью операторами кода.
     
  14. DrProg

    DrProg Вечный нерд

    Почему бы вам не выложить свой код, мне вот на самое деле интересно посмотреть. Мне вот до конца не понятно как каждый раз запускать таймер при нажатии кнопки и как потом отлавливать его результат. Я решил, что проверка кнопки фоном постоянно не так уж нагрузит систему, но облегчит код.
     
    Последнее редактирование: 27 янв 2016
  15. DrProg

    DrProg Вечный нерд

    Про аппаратное решение тут не говорим. Иначе бы я снова давно повесил пример на 40мс без единой строки кода:
    [​IMG]
     
  16. Gurf

    Gurf Нуб

    Ну, в упомянутом мной образце код так выглядит. Я его кстати, проверял - работает нормально
    Код (C++):
    const int buttonPin = 2;    // the number of the pushbutton pin
    const int ledPin = 13;      // the number of the LED pin

    // Variables will change:
    int ledState = HIGH;         // the current state of the output pin
    int buttonState;             // the current reading from the input pin
    int lastButtonState = LOW;   // the previous reading from the input pin

    // the following variables are long's because the time, measured in miliseconds,
    // will quickly become a bigger number than can be stored in an int.
    long lastDebounceTime = 0;  // the last time the output pin was toggled
    long debounceDelay = 50;    // the debounce time; increase if the output flickers

    void setup() {
      pinMode(buttonPin, INPUT);
      pinMode(ledPin, OUTPUT);

      // set initial LED state
      digitalWrite(ledPin, ledState);
    }

    void loop() {
      // read the state of the switch into a local variable:
      int reading = digitalRead(buttonPin);

      // check to see if you just pressed the button
      // (i.e. the input went from LOW to HIGH),  and you've waited
      // long enough since the last press to ignore any noise:

      // If the switch changed, due to noise or pressing:
      if (reading != lastButtonState) {
        // reset the debouncing timer
        lastDebounceTime = millis();
      }

      if ((millis() - lastDebounceTime) > debounceDelay) {
        // whatever the reading is at, it's been there for longer
        // than the debounce delay, so take it as the actual current state:

        // if the button state has changed:
        if (reading != buttonState) {
          buttonState = reading;

          // only toggle the LED if the new button state is HIGH
          if (buttonState == HIGH) {
            ledState = !ledState;
          }
        }
      }

      // set the LED:
      digitalWrite(ledPin, ledState);

      // save the reading.  Next time through the loop,
      // it'll be the lastButtonState:
      lastButtonState = reading;
    }
     
    Или, пардон - Вы о запуске таймера с прерыванием говорили - я же о другом способе...
     
  17. DrProg

    DrProg Вечный нерд

    По сути мало чем отличается от варианта с delay(), правда можно напихать внутрь код при желании, но встроить его в готовый даже не представляю как. Или я что то не понял. В чем его преимущество?
     
  18. Gurf

    Gurf Нуб

    В чем преимущество? работает классно, а в отличие от delay - не "вешает" контроллер на время delay. Встроить тоже можно. Например, я вместо строки, идущей после коммента
    Код (C++):
    //set the LED:
    вставлял нужное мне количество сток моего кода... Думаю, не сложно его приколхозить для чего-то полезного... ну если не нужно с прерыванием работать...
     
  19. DrProg

    DrProg Вечный нерд

    Ну можно, наверное, надо вникнуть. Задача то, чаще всего такая: например МК динамически выводит на дисплей цифры и одновременно ждет нажатия кнопки, как простой вариант пуск/стоп. Так вот чтобы на время обработки антидребезга изображение не дергалось и не пропадало надо обойтись без delay().

    Хотя вот подумал, у меня вывод одного кадра выполняется вызовом функции, можно его и вставить в
    Код (C++):
    //set the LED:
    Как вариант интересно, да, надо попробовать.

    Но меня вот раздразнили способом через таймер. Я не поленился и сделал свой вариант, на мой взгляд интересный, но очень хочу посмотреть брежневский.
     
  20. Onkel

    Onkel Гуру

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