Вспомнил молодость и… решил написать про обычную кнопку (выключатель) в микропроцессорной системе. Есть про кнопку статья, однако про так назывемый дребезг (буду без кавычек далее писать) — тут ни слова (наверно, где-то все же про это написано, но…).
Есть у электрических контактов в коммутационных изделиях очень «вредное» свойство под названием дребезг. Проявляется свойство в том, что контакт замыкается (размыкается) не «сразу на вечно», а как бы нехотя: вроде бы контакт появился, потом исчез и так много-много раз… и, лишь через некоторое время (обычно до нескольких десятков милисекунд), контакт устойчиво фиксируется. Этот эффект напрямую связан с упругостью материалов контактов кнопки и ее конструкцией: упругая металлическая пластина контакта после сопркосновения с другой, отскакивает от нее и начинает вибрировать, по ходу дела касаясь второго контакта.
Приведенный в упоменутой статье пример скетча не отлавливает дребезг, т.к. его влияние на результат визуально отсутствует (мы не видим «помаргиваний» светодиода в момент замыкания). Более интересный вариант того же скетча позволяет оценить (хоть и весьма поверхностно) работу «дребезжащей конструкции».
// задаем константы const int buttonPin = 7; // номер входа, подключенный к кнопке const int ledPin = 13; // номер выхода светодиода // переменные int buttonState = 0; // перем. для хранения состояния кнопки int buttonState2 = 0; // перем. для хранения состояния кнопки unsigned long time_end; //для определения времени стабилизации int i_h, i_l; //тут считаем число замыканий/размыканий void setup() { Serial.begin(9600); Serial.println("Start..."); pinMode(ledPin, OUTPUT); // светод.пин, как выход pinMode(buttonPin, INPUT); //пин кнопки, как вход digitalWrite(buttonPin, HIGH); // вкл.подтягивающий резистор } void loop(){ i_l = 0; //число смены состояний i_h = 0; //тут чисо совпадений (для общей оценки) time_end = millis()+50; //даем 50мс на "успокоение" контактов while (millis() < time_end) { buttonState = digitalRead(buttonPin); buttonState2 = digitalRead(buttonPin); if (buttonState == buttonState2) { i_h++; //оцениваем общее число считываний кнопки } else { i_l++; //фиксируем изменение состояния кнопки (дребезг) } } Serial.print("Equal = "); Serial.print(i_h); Serial.print(" Counter = "); Serial.println(i_l); // проверяем нажата ли кнопка // если нажата, то buttonState будет LOW: if (buttonState == HIGH) { digitalWrite(ledPin, HIGH); // включаем светодиод } else { digitalWrite(ledPin, LOW); // выключаем светодиод } while (digitalRead(buttonPin) == buttonState) { //ожидаем изменения состояния кнопки (смотрим на экран!) } }
Отличия дополненного скетча от исходного в следующем:
- включаем внутренний подтягивающий резистор микроконтроллера к контакту кнопки, второй контакт кнопки — «на землю». Тем самым сокращая число элементов в схеме.
- после определения изменения состояния кнопки даем ей 50мс на то чтобы «успокоиться», при этом подсчитываем число изменений состояния кнопки за это время (как раз это и есть проявление дребезга)
- выводим на экран подсчитанные значения для созерцания и размышлений…
Схема макета у нас несколько упростилась из-за отсутствия лишнего резистора.
(на «лишние» детали можно не смотреть — нам нужна только кнопка и два провода)
Смотрим на экран — что же у нас происходит в момент нажатия и отпускания кнопки:
Видно «полнейший разброд и шатания» — т.е. даже с нашим «примитивным» программным решением видно, что дребезг ЕСТЬ! и он не предсказуем. За 50 мс после нажатия на кнопку мы проводим примерно 4400 парных считывания состояния входа и из них до 10 раз эти считывания не совпадают!
Конечно, не во всех программах так уж важно избавляться от этого нежелательного явления. Но, например, если мы по числу нажатий кнопки определяем режим работы или проводим установку какого-либо параметра — это важно.
Из методов борьбы с дребезгом наиболее надежен аппаратный — например, RS-триггер в паре с кнопкой на переключение. Из программных методов, обычно, используется приведенный в примере способ задания паузы после первой смены состояния кнопки или подсчитывают число последовательных повторений одного состояния (например, 10 раз).
ИТОГ: Помните о дребезге! (В молодости, я дня два сидел — не мог понять, почему схема работает не так, как задумано… 🙂 )
В процессе изучения столкнулся с двумя проблемами:
1) Не понимал что такое подтягивающий резистор. Провел ликбез и более менее разобрался.
2) Все схемы где был описан принцип действия такого резистора непосредственно его включали как элемент, а тут на «сокращенной» схеме, так и не нашел его… боялся замыкания). Но в листинге заметил строку
digitalWrite(buttonPin, HIGH); // вкл.подтягивающий резистор
Оказалось дело именно в ней.
До этого момента не встречал таких примеров) Теперь знаю как можно подключить внутренний подтягивающий резистор. Спасибо
Приятно 🙂
Надо отметить, что внутренний резистор довольно велик по номиналу (50-100К), что может привести к ложным срабатываниям от наводок. Поэтому обычно ставят внешний резистор 1-10К. Внутренний резистор также можно включить функцией: pinMode(pin, INPUT_PULLUP).
Практически все механические кнопки, контакторы и переключатели в той или иной степени подвержены дребезгу.