Ошибка счетчика нажатий кнопки на прерываниях.

croan
Offline
Зарегистрирован: 21.02.2018
volatile int counter = 0;  // переменная-счётчик
void setup() {
  Serial.begin(9600); // открыли порт для связи
  // подключили кнопку на D2 и GND
  pinMode(2, INPUT_PULLUP); \
  // D2 это прерывание 0
  // обработчик - функция buttonTick
  // FALLING - при нажатии на кнопку будет сигнал 0, его и ловим
  attachInterrupt(0, buttonTick, FALLING);
}
void buttonTick() {
  counter++;  // + нажатие
}
void loop() {
  Serial.println(counter);  // выводим
  delay(1000);              // ждём
}

Здравствуйте. Не могу понять почему некорректно считает нажатия на кнопку. кнопку пустил в разрыв между минусом и 2 пином. в мониторе порта происходит какая-то фигня - нажатие прибавляет 1 или 2, иногда 3... 

что за ерунда и как это лечится?

xDriver
xDriver аватар
Offline
Зарегистрирован: 14.08.2015

дребезг.

croan
Offline
Зарегистрирован: 21.02.2018

причину понял - дребезг кнопки.

нашел способ - использование задержки для сравнения положений кнопки. ситуация не изменилась((

volatile int counter = 0;  // переменная-счётчик
int currentValue, prevValue;
void setup() {
  Serial.begin(9600); // открыли порт для связи
  // подключили кнопку на D2 и GND
  pinMode(2, INPUT_PULLUP); \
  // D2 это прерывание 0
  // обработчик - функция buttonTick
  // FALLING - при нажатии на кнопку будет сигнал 0, его и ловим
  attachInterrupt(0, buttonTick, CHANGE);
}
void buttonTick() {
  currentValue = digitalRead(2); 
  if (currentValue != prevValue) {
    
    delay(10);
  counter++;  // + нажатие
    currentValue = digitalRead(3);
     
  }
 
}
void loop() {
  
 Serial.println(counter);  // выводим
  delay(1000);              // ждём
}

 

BOOM
BOOM аватар
Offline
Зарегистрирован: 14.11.2018

Поставь параллельно кнопке конденсатор на 1мкФ и увеличь время до 60...150мс.  Или используй триггер Шмидта. 

sadman41
Offline
Зарегистрирован: 19.10.2016

delay() в обработчике прерывания не работает. Если хочется придержать считывание - принимайте delayMicroseconds() сразу после входа в ISR. А потом уже вход чекайте.

croan
Offline
Зарегистрирован: 21.02.2018

BOOM пишет:

Поставь параллельно кнопке конденсатор на 1мкФ и увеличь время до 60...150мс.  Или используй триггер Шмидта. 

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

тут вопрос в другом - когда используются несколько кнопок для управления менюшкой на дисплее придется на каждую лепить кондер с триггером, если программно не получится решить проблему ? и почему-таки программно без кондера результата нет - может в коде ошибка какая ?

croan
Offline
Зарегистрирован: 21.02.2018

спасибо, где-то проскакивала инфа что такие задержки не работают - упустил из виду) сейчас поковыряю ваш вариант решения.

croan
Offline
Зарегистрирован: 21.02.2018

sadman41 пишет:

delay() в обработчике прерывания не работает. Если хочется придержать считывание - принимайте delayMicroseconds() сразу после входа в ISR. А потом уже вход чекайте.

попробовал разные варианты расположения задержки - результата практически нет((

volatile int counter = 0;  // переменная-счётчик
int currentValue, prevValue;
void setup() {
  Serial.begin(9600); // открыли порт для связи
  // подключили кнопку на D2 и GND
  pinMode(2, INPUT_PULLUP); \
  // D2 это прерывание 0
  // обработчик - функция buttonTick
  // FALLING - при нажатии на кнопку будет сигнал 0, его и ловим
  attachInterrupt(0, buttonTick, CHANGE);
}
void buttonTick() {
  //delayMicroseconds(1650);
  currentValue = digitalRead(2); 
  if (currentValue != prevValue) {
    

  counter++;  // + нажатие
    currentValue = digitalRead(3);
     
  }
 delayMicroseconds(1650);
}
void loop() {
  
 Serial.println(counter);  // выводим
  delay(1000);              // ждём
}

 

sadman41
Offline
Зарегистрирован: 19.10.2016
volatile int counter = 0;  // переменная-счётчик

void buttonTick() {
  delayMicroseconds(2*1000UL); // 2ms
  if (LOW == digitalRead(2)) {
      counter++;  // + нажатие    
  }
}

void setup() {
  Serial.begin(9600); // открыли порт для связи
  pinMode(2, INPUT_PULLUP);
  attachInterrupt(0, buttonTick, FALLING);
}

void loop() {  
  Serial.println(counter);  // выводим
  delay(1000);              // ждём
}

Но навигацию по менюшке лепить на прерываниях - это оверкилл. Достаточно библиотеки дебаунсера.

croan
Offline
Зарегистрирован: 21.02.2018

нашел проблему - оказывается задержка delayMicroseconds() в микросекундах и то, что у меня 1650 равнозначно 1.65 милисекунд ))) увеличил до 10650 - и всё заработало как часы.

огромное спасибо!!!

croan
Offline
Зарегистрирован: 21.02.2018

сейчас библиотеку поизучаю, спасибо)

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

две миллисекунды маловато видимо будет, тут осциллограмку кто-то выкладывал,там три всплеска на обычной кнопке, найти бы, там и временные отрезки видны

croan
Offline
Зарегистрирован: 21.02.2018

sadman41 пишет:

volatile int counter = 0;  // переменная-счётчик

void buttonTick() {
  delayMicroseconds(2*1000UL); // 2ms
  if (LOW == digitalRead(2)) {
      counter++;  // + нажатие    
  }
}

void setup() {
  Serial.begin(9600); // открыли порт для связи
  pinMode(2, INPUT_PULLUP);
  attachInterrupt(0, buttonTick, FALLING);
}

void loop() {  
  Serial.println(counter);  // выводим
  delay(1000);              // ждём
}

Но навигацию по менюшке лепить на прерываниях - это оверкилл. Достаточно библиотеки дебаунсера.

не пойму что за библиотека дебаунсера ?

croan
Offline
Зарегистрирован: 21.02.2018

ua6em пишет:

две миллисекунды маловато видимо будет, тут осциллограмку кто-то выкладывал,там три всплеска на обычной кнопке, найти бы, там и временные отрезки видны

10650 микросекунд уже работают) для тестирования устранения дребезга - долее чем достаточно) буду ковырять дальше...

sadman41
Offline
Зарегистрирован: 19.10.2016

ua6em пишет:

две миллисекунды маловато видимо будет, тут осциллограмку кто-то выкладывал,там три всплеска на обычной кнопке, найти бы, там и временные отрезки видны

От раздолбанности кнопки зависит, безусловно. Пример я написал, двоечку менять на что-то другое - наверное хватит соображалки. 

Вообще - 5-8 мс дебаунса покрывали все мои старые тактовые кнопки. Конечно, в прерываниях я задержки не ставил, не для того они.

P.S. 

Картинка из интернета:

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

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

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Поставьте на входе интегрирующую цепочку на 10-16 мс и забудьте о перхоти дребезге от слова совсем (ну, если кнопка не совсем вдрызг убитая). В программе тогда вообще ничего делать не надо.

Или можно взять SPDT кнопку и сделать как здесь. С таким подходом дребезг невозможен в принципе независимо от степени убитости кнопки. И опять же в программе ничего делать не надо.

asam
asam аватар
Offline
Зарегистрирован: 12.12.2018

croan пишет:

10650 микросекунд уже работают) для тестирования устранения дребезга - долее чем достаточно) буду ковырять дальше...

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

- В прерывании считываем кнопку раз 5 подряд (для отсекания "иголок"). Если все пять раз кнопка "нажата", то ставим флаг, что кнопка нажата (и увеличиваем счетчик нажатий, если так надо) и  и игнорируем прерывания от пина миллисекунд на 10.  Лучше их вообще запретить, что бы проц дребезгом не грузить. Но тогда потребуется использовать прерывания от таймера, что бы прерывания от кнопки опять разрешить. Ну или их можно опять разрешить в Loop() если он у вас крутится быстрее чем за 10мс.

Потом проверям прямым чтением пина - если кнопка все еще нажата, то аналогичным образом ловим отпускание и тогда симаем флаг "нажато".

BOOM
BOOM аватар
Offline
Зарегистрирован: 14.11.2018

Вот такие триггеры (https://ru.aliexpress.com/item/32844342674.html?spm=a2g0s.9042311.0.0.7fa133edAqthaZ) копейки стоят и сразу 4шт в одном корпусе. Есть smd исполнение. Дёшево и работает )))

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

BOOM пишет:

Вот такие триггеры (https://ru.aliexpress.com/item/32844342674.html?spm=a2g0s.9042311.0.0.7fa133edAqthaZ) копейки стоят и сразу 4шт в одном корпусе. Есть smd исполнение. Дёшево и работает )))

Тока их там шесть в одном корпусе

dimax
dimax аватар
Offline
Зарегистрирован: 25.12.2013

BOOM, триггер шмитта уже есть в МК на каждом входе, подключать ещё и внешний в целях формирования  логических уровней не имеет смысла. Действительно работающие варианты аппаратного дребезгоподавления это   MC14490, MAX6816

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

DetSimen пишет:

BOOM пишет:

Вот такие триггеры (https://ru.aliexpress.com/item/32844342674.html?spm=a2g0s.9042311.0.0.7fa133edAqthaZ) копейки стоят и сразу 4шт в одном корпусе. Есть smd исполнение. Дёшево и работает )))

Тока их там шесть в одном корпусе

и не копейки а три рубля за корпус )))

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

dimax пишет:

BOOM, триггер шмитта уже есть в МК на каждом входе, подключать ещё и внешний в целях формирования  логических уровней не имеет смысла. Действительно работающие варианты аппаратного дребезгоподавления это   MC14490, MAX6816

хорошие девайсы, первые аж на 6 каналов, за то вторые с защитой по входу от наводок до 15 киловольт, а принцип действия одинаковый, возьму на заметку )))

dimax
dimax аватар
Offline
Зарегистрирован: 25.12.2013

ua6em, mc14490 я уже как-то обозревал с картинками :)

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

dimax пишет:

ua6em, mc14490 я уже как-то обозревал с картинками :)

я тогда даже слова такого - ардуино - не слышал )))