Как стабилизировать кнопку по прерыванию?
- Войдите на сайт для отправки комментариев
Чт, 28/02/2013 - 21:45
В своем скетче мне очень нужно использовать кнопку по прерыванию. Так как есть очень длинный и долгий цикл который нужно обрывать в любой момент по нажатию кнопки и запускать другую обработку. Как раз для этого идеально подходит прерывание, которое обрабатывает кнопку не зависимо от основной программы. Есть стандартный код обработки кнопки по прерыванию, но он работает с дребезгом.
// // светодиод, подключённый к digital pin 13 будет изменять своё // состояние при изменении напряжения на digital pin 2 // int pin = 13; volatile int state = LOW; void setup() { pinMode(pin, OUTPUT); // порт как выход attachInterrupt(0, blink, CHANGE); // привязываем 0-е прерывание к функции blink(). } void loop() { digitalWrite(pin, state); // выводим state } void blink() { state = !state; // меняем значение на противоположное }
Я знаю что можно внести в схему инвертирующий триггер шмидта, который будет стабилизировать сигнал получаемый с кнопки, но охота не услажнять схему дополнительными деталями. Может есть вариант сделать это програмно?
В обработчике прерываний запретить прерывания в начале и разрешить в конце.
Установить глобальный счетик в обработчике прерываний выполняющий полный код обработчика на 5-тый 10-тый или 20-тый вызов прерывания
Лучше всего читать в обработчике "системное" время ( millis() ) и проверять разницу. По достижении заданного интервала делать полную обработку и записывать актуальное время для последующего сравнения. Учесть преход счётчика millis() через ноль, если включаться будет дольше чем на 50 дней
А можно пример пожалуйста, а то у меня в голове каша после прочтенного.
Все решил проблему! А все очень просто. Добавил обычный керамический конденсатор на 1мф мжду контактами кнопки. И вуаля абсолютно никакого дребезга. Кнопку с большой частотой нажимал на сколько мог. Дребезга нет, удивительно)
"Все решил проблему! А все очень просто. Добавил обычный керамический конденсатор на 1мф мжду контактами кнопки. И вуаля абсолютно никакого дребезга. Кнопку с большой частотой нажимал на сколько мог. Дребезга нет, удивительно)" - Вы просто ещё не попали в ситуацию когда дребезг даст о себе знать снова. Да, конденсатор значительно сглаживает сигнал дребезга, но не устраняет полностью.
Все таки добавить две строки куда проще чем впаивать конденсатор.
отличное решение! А я пошел по другому пути. Установил глубину фильтра - от 8 до 16 единиц. И в том-же обработчике прерывания от кнопки просто считаю сколько подряд проскочило 1 или 0, смотря по какому уровню настроено прерывание. Когда необходимое количество 1 или 0 пришло, выставляю флаг что нажата кнопка.
Таким образом получается избавиться даже от очень сильного дребезга
при объявлении переменная millis_prev инициализируется в ноль или ей просто выделяется неочищенная область памяти ?
-------
Таким образом получается избавиться даже от очень сильного дребезга
В обработчике прерываний запретить прерывания в начале и разрешить в конце.
Пустые заботы. Прерывания автоматически запрещаются на время выполнения кода обработчика прерываний
Я полагаю в техническом форуме не место для персональных оскорблений.
Если Вы хотите критиковать, критикуйте по существу, если не можете , ведите себя достойно
Оскорблений никаких не было.
А по существу пожалуйста:
Абсолютно никак не помогает от дребезга. По какой причине в коде выше стоит LOW уже не помню, с таким же успехом будет работать и RISING и FALLING.
#4
http://arduino.ru/forum/programmirovanie/vopros-po-preryvaniyam#comment-34127
Что зависит? Длительность дребезга? Без разницы какой длины дребезг, если он есть.
из этой душераздирающей ветки нужно сделать вывод, что если в проекте всё так критично с дребезгом - плюньте на дребезг, пусть он будет, но не влияет ни на что...
две кнопки или тумблер - одна кнопка(положение тумблера) что-то включает, вторая - выключает.
и никакого дребезга!
Я полагаю в техническом форуме не место для персональных оскорблений.
Я вас правильно понял?
Потому как прочитав ваш пост у меня сложилось впечатление что вы решили мол - "да хрен ли вы тут все чушь какую то несете, вот как надо делать, вот как должно быть", отсюда и была такая жесткая реакция с моей стороны на ваш пост.
мой вариант борьбы с дребезгом при использовании прерываний такой:
- на кнопку настраиваем прерывание (одно из INT0/INT1 или PCINT). Только для INT0/INT1 можно установить то на какое событие мы будем срабатывать (any, zero, high, rasing, faling), для PCINT можно выбрать только вариант any, но это не страшно - прочитав первой строчкой кода прерывания статус кнопки в порту мы сразу поймем из-за чего произошло прерывание и можем его проигнорировать, если оно нам не интересно.
- делаем прерывание на тамер. частоты срабатывания должна быть от десятых долей секунды и чаще. точное значение милисеунд не нужно, нужно просто иметь возможность отсчитывать короткие (в десять и более раз меньшие чем секунда) интервалы.
- объявляем две volatile переменные одна для работы таймера кнопки, вторая для фиксации факта успешного (уже после обработки дребезга) нажатия кнопки. По второй переменной мы будет делать что нам нужно в loop() и после обработки будет сбрасывать в ноль значение этой переменной. Для многих случаев полезно игнорировать новые нажатия кнопки до тех пор, пока предыдущее нажатие не обработано.
- первую переменную выставляем в прерывании от нажатия кнопки (не забываем проверять состояние порта для обработки PCINT). Выставляем ее в количество циклов срабатывания таймера которые мы считаем надежным нажатием. Подбирается экспериментально. Из моей практики время до истечения таймера должно быть между 400 и 100 мсек. Делим это время на период срабатывания обработчика таймера и полученно число после округдения записываем в нашу первую переменную
- как только значение первой переменной стало больше нуля мы начинаем считать и как только досчитаем до нуля снова смотрим состояние порта и если кнопка все еще нажата - ставим единицу во вторую переменную
все. пример есть в моем коде здесь http://arduino.ru/forum/proekty/igrushechnyi-svetofor
А что если в обработчике прерываний первой строкой вписать запрет обработки прерывания? А в конце, если надо, разрешить.
Отлично работает! Перепробовал разные варианты, похоже этот пока самый простой и стабильный.
как по мне самый простой вариант, можно еще тригер поставить для большей надежности, тот же шмитта. Ставил DS, то тоже норм сбивает дребезг
Все таки добавить две строки куда проще чем впаивать конденсатор.
Ваше программное решение не защищает от брезга при отпускании кнопки. Пользователь может нажать, подержать, а потом отпустить. И вот тут-то при дребезге будет лишнее срабатывание.
А обычно хочется отрабатывать именно нажатие на кнопку, а не отпускание. В том числе, продолжительное.
Все решил проблему! А все очень просто. Добавил обычный керамический конденсатор на 1мф мжду контактами кнопки. И вуаля абсолютно никакого дребезга. Кнопку с большой частотой нажимал на сколько мог. Дребезга нет, удивительно)
... и потеряли энергоэффективность, надо полагать. Кондей можно поставить и поменьше.
Зачетного мракобеса к нам занесло! Это ж надо было раскопать тему и отвечать на сообщения пятилетней давности. Какая нах энергоэффективность нажатия кнопки ))) Какое длительное отпускание?! Почти усцался от смеха))
ПС. примеры годные, но деатач/атач в обработчике лишние. Кондей, тригер и пр. лабудень на кнопке - показатель неумения человека писать код. Еще важно чтобы один месный не заметил что паузу на 100мсек в коде, он свято верит что умеет нажать и отпустить кнопку быстрей и воспринимает такое как личное унижение ;)
Какая нах энергоэффективность нажатия кнопки ))) Какое длительное отпускание?! Почти усцался от смеха))
;)
не нажатия кнопки, а зарядки/разрядки кондея. Разумеется, программно множно и нужно. Но приведенный здесь пример далек от совершенства.
По поводу длительно нажатия:
Кнопки нажимаются не только для того чтобы тут же отпустить. По-моему, это очевидно.
ПС. Написал в древнюю тему, потому что искал готовое решение. Его, к сожалению, годного, пока не нашлось.
Еще важно чтобы один месный не заметил...
один местный уже три года ждёт обещанного одним балаболом кода обработчика сотни кнопок для человека с одним пальцем... но, пока балабол тратит время на комменты некропостеров.
алё. когда код будет, пустобрёх?
А один местный заказ уже оплатил?
ПС. Я знал что он обязательно клюнет! )))
пример далек от совершенства.
а совершенство - штука скорей хилосовская;)
Кнопки нажимаются не только для того чтобы тут же отпустить. По-моему, это очевидно.
А вот тут по разному бывает. Кнопка лифта, кнопка мышки, кнопка бояна - все сильно специфично.
искал готовое решение. Его, к сожалению, годного, пока не нашлось.
разумеется. Нет проблемы - нет решения.
А один местный заказ уже оплатил?
ПС. Я знал что он обязательно клюнет! )))
тред был не в рубрике "Ищу исполнителя", и ты обещал без условий оплаты, а что бы доказать, как нужно делать - б-а-л-а-б-о-л
*я знал, что Логик - пустобрёх.
Ничего подобного, я профи, пишу код за деньги. И если кому надо коду от меня - так не за так. И об этом изначально я те писал, влом только искать. Но учитывая чтот ты настырно клянчиш уже который месяц и беря во внимание, что недавно был день дурака, а заслуженого подарка на форуме ты так и нифига не получил, то дарю. Но не все ;) Интересные методы классов я позатираю, поля данных оставлю для подсчета. Так до поступления финансов на счет.
Ну и вывод при полном наличии иерархии классов
Ничего подобного, я профи, пишу код за деньги. И если кому надо коду от меня - так не за так. И об этом изначально я те писал, влом только искать.
ты не профи - у тебя долгосрочной памяти как у канарейки, ты не помнишь, что начал мне рассказывать, как нужно... и, когда я тебе предложил показать, как нужно - ты сказал, что выкатишь код и я буду посрамлён.
когда я тебе напомнил о твоих обещаниях - ты-сука слился.
давай код, прохфесианал!
Заметь, кстати непосредственно стробирование и опрос реализуется в пользовательском классе KBD, функции SetStrob и GetReturn. А это означает что? Правильно, ты ниче не понял... Это означает что клаву легко и не принужденно можна вынести в расширители портов. И ничего от этого не поменяется в базовых классах. Обем памяти сам посчитаеш, там просто, структурка в массиве. А я - спать. Пока. С прошедшим праздником ;)
Ничего подобного, я профи, пишу код за деньги. И если кому надо коду от меня - так не за так. И об этом изначально я те писал, влом только искать.
ты не профи - у тебя долгосрочной памяти как у канарейки, ты не помнишь, что начал мне рассказывать, как нужно... и, когда я тебе предложил показать, как нужно - ты сказал, что выкатишь код и я буду посрамлён.
когда я тебе напомнил о твоих обещаниях - ты-сука слился.
давай код, прохфесианал!
Прикольно получилось))) А код то - вон он, выше! Но самое вкусное - за бабло. Увы это жизнь такая. Не злись. Думаю в коде ты всеравно нихера не поймеш.
ПС. еще раз тя с прошедшим праздником.
ты бы ещё ссылку на блинк без делая дал, а отсальное - за бабло попросил, клоун.
это не раздел Ищу исполнителя - публикация цитат из секретного кода здесь считается тупым балабольством.
в референс, Гаммон и другие умные дядьки говорят не использовать милис,сериал и прочее внутри ISR. а) почему вы всетаки использовались милис именно внутри ?
б) почему оно работает если умные дядьки говорят что внутри ISR это не будет работать ?
Надо понимать, что такое "не работает". В ISR millis() не изменяет своего значения, выдавая все время одно и то же. Но, при двух разнесенных во времени вызовах обработчика, величина millis() в нем будет отличаться. Данный факт применен в этом коде "антидребезга".
понял спасиб
Господа, ок а можно же просто отключить прерывание? (вопрос в целях самооброзования а не подвоха который почемуто все тут ждут)
Так отключайте, никто не запрешает (пока).
я спрашиваю так тоже будет правильным ? не с точки зрения валидности кода а с точки зрения логики, "хорошего" кода
Правильно "отключать" прерывания путем их запрещения. Не всех скопом, а конкретное.
так detach как раз и отключает конкретное а не все скопом...
(не осуждаю умения и навыки maksim, он знает что делает) но новичков хотел бы предостиречь от использования millis(), Serial внутри ISR (обработчика прерываний) во избежания непонятных глюков
delay (100);
Serial.println ("ISR entered");
)подробнее тут http://www.gammon.com.au/interrupts, http://arduino.ru/forum/programmirovanie/vopros-po-preryvaniyam#comment-34127, http://arduino.ru/forum/programmirovanie/vnutrennie-preryvaniya?page=1#comment-446383
В моём случае этот код нормально отрабатывает только с LOW. Видимо поэтому он и был здесь указан! ))
По непонятным причинам с RISING или FALLING прерывание часто срабатывает и на нажатие, и на отпускание кнопки. Т.е. 2 раза, а не один раз, как ожидается.
Причем с RISING "левых" сработок около 90%, а с FALLING - около 50%. И, к сожалению, не прослеживается никакой логики по срабатыванию четко на смену сигнала с LOW на HIGH либо наоборот.
С вариантом LOW все как часы. Нажал - получил.
мой вариант борьбы с дребезгом при использовании прерываний такой:
Дык это некропост ! Тьфу ты :)