Очередной вопрос по нажатию кнопки

Алексей Н
Offline
Зарегистрирован: 02.01.2016

Добрый день, участникам форума!

Прошу помочь разобраться с вопросом, который у меня возник при изготовлении поделки на ардуино. Проект - автоматические шторы. Идея такая: нажал одну кнопку - шторы закрылись, нажал другую кнопку - шторы открылись. Если шторы находятся в процессе открытия/закрытия, то нажатие на любую кнопку приводит к остановке штор. Вроде простая задача. Поскольку программист я так себе, то пишу программу добавляя по несколько строк  и смотрю на результат работы. Сначала написал кусок программы, который открывает и закрывает шторы, путем включения соответствующих реле на заданное время.  Все работает. Дребезг контактов подавляю с помощью библиотеки Bounce2. Добавляю кусок кода, который устанавливает флаг движения штор и отключает реле, если кнопка нажата во время движения. Строки 58-62 и 70-74. И тут появилась проблема. По идее, если при нажатии кнопки взведен флаг движения, то сигнал на реле перестает подаваться и флаг движения устанавливается в ноль. Все вроде просто. Но снова появился дребезг. Пробовал увеличивать время задержки в  debouncer.interval. Пробовал устанавливать задержку после взведения флага. Дребезг все равно остается. Думаю, что проблема в коде, но не могу сам найти ошибку. Не могли бы уважаемые участники форума посмотреть код и сказать, в чем моя ошибка?

// Include the Bounce2 library found here :
// https://github.com/thomasfredericks/Bounce2
#include <Bounce2.h>

#define BUTTON_PIN_1 2
#define BUTTON_PIN_2 3

#define PIN_OPEN 14
#define PIN_CLOSE 15

// Флаг движения штор
int action_flag = 0;

// Переменная для хранения точки отсчета
unsigned long timing;

// Instantiate a Bounce object
Bounce debouncer1 = Bounce();

// Instantiate another Bounce object
Bounce debouncer2 = Bounce();

void setup() {

   pinMode(BUTTON_PIN_1, INPUT_PULLUP);
  // After setting up the button, setup the Bounce instance :
  debouncer1.attach(BUTTON_PIN_1);
  debouncer1.interval(10); // interval in ms

  // Setup the second button with an internal pull-up :
  pinMode(BUTTON_PIN_2, INPUT_PULLUP);
  // After setting up the button, setup the Bounce instance :
  debouncer2.attach(BUTTON_PIN_2);
  debouncer2.interval(10); // interval in ms

  pinMode(PIN_OPEN, OUTPUT);
  pinMode(PIN_CLOSE, OUTPUT);


}

void loop() {
  // Update the Bounce instances :
  debouncer1.update();
  debouncer2.update();

  // Get the updated value :
  int value1 = debouncer1.read();
  int value2 = debouncer2.read();

  // Отслеживаем состояние кнопок
  if ( value1 == LOW ) {
    if ( action_flag == 0 ) { // Если нажата кнопка "открыть" и движения нет
      digitalWrite( PIN_OPEN, HIGH );
      timing = millis();
      action_flag = 1;
    }
    else {                   // Если нажата кнопка "открыть" и движение есть
      digitalWrite( PIN_OPEN, LOW ); //Остановить движение
      digitalWrite( PIN_CLOSE, LOW );
      action_flag = 0;
    }
  }
  if ( value2 == LOW ) {
    if ( action_flag == 0 ) { // Если нажата кнопка "закрыть" и движения нет
      digitalWrite( PIN_CLOSE, HIGH );
      timing = millis();
      action_flag = 1;
    }
    else {                   // Если нажата кнопка "закрыть" и движение есть
      digitalWrite( PIN_OPEN, LOW ); //Остановить движение
      digitalWrite( PIN_CLOSE, LOW );
      action_flag = 0;
    }
  }


  if (  action_flag == 1 ) {
    if (millis() - timing > 10000) { // Вместо 10000 подставьте нужное вам значение паузы
      digitalWrite( PIN_OPEN, LOW );
      digitalWrite( PIN_CLOSE, LOW );
      action_flag = 0;
    }
  }
}

 

MaksVV
Offline
Зарегистрирован: 06.08.2015

юзайте титановый велосипед, местный продукт

v258
v258 аватар
Offline
Зарегистрирован: 25.05.2020

Это не дребезг. Скорее всего это реакция на длительное нажатие на кнопку. Т.е. вы ее просто не успеваете отпустить, как она срабатывает снова

Алексей Н
Offline
Зарегистрирован: 02.01.2016

v258 пишет:

Это не дребезг. Скорее всего это реакция на длительное нажатие на кнопку. Т.е. вы ее просто не успеваете отпустить, как она срабатывает снова

 

Похоже на то. Я думал, что это можно победить, установив задержку после обнаружения нажатия кнопки. Но не помогло. Думаю, что порождение злого гения (класс титановый велосипед) не поможет по той же причине. Хотя скачал, попробую разобраться.

bwn
Offline
Зарегистрирован: 25.08.2014

До какого значения увеличивали интервал? ИМХО, здесь обычной задержки должно хватать через край, без каких-либо библиотек.

Алексей Н
Offline
Зарегистрирован: 02.01.2016

bwn пишет:

До какого значения увеличивали интервал? ИМХО, здесь обычной задержки должно хватать через край, без каких-либо библиотек.

debouncer.interval делал 10, 50, 100, 300, 1000. Чем больше, тем непонятнее поведение программы. Еще глюк. По логике программы (как вижу ее я), если нажата кнопка 1 и запущено реле 1, то нажатие кнопки 2 должно выключать реле 1. Вместо этого включается реле 2.

v258
v258 аватар
Offline
Зарегистрирован: 25.05.2020

Алексей Н пишет:

Думаю, что порождение злого гения (класс титановый велосипед) не поможет по той же причине. Хотя скачал, попробую разобраться.

Во-первых поможет, потому что там есть работа с состоянием кнопки. Во-вторых можно и ваш код довести до ума, а для этого нужно вести учет не только нажатию, но и отжатию кнопки. Т.е. завести еще один флаг (для каждой кнопки), который будет устанавливаться в true при нажатии и в false при отпускании кнопки, а все нынешние действия с кнопками допускать только при условии, что этот флаг еще false. Так вы исключите множественные срабатывания кнопки за одно нажатие.

Ну и в-третьих - не уверен, т.к. не пользовался библиотекой Bounce2, но, возможно, и в ней есть возможность обработки состояния кнопки (а не только считывания, как вы делаете сейчас)

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

В bounce2 есть и fell() и rose()

bwn
Offline
Зарегистрирован: 25.08.2014

v258 пишет:

Во-первых поможет, потому что там есть работа с состоянием кнопки. Во-вторых можно и ваш код довести до ума, а для этого нужно вести учет не только нажатию, но и отжатию кнопки. Т.е. завести еще один флаг (для каждой кнопки), который будет устанавливаться в true при нажатии и в false при отпускании кнопки, а все нынешние действия с кнопками допускать только при условии, что этот флаг еще false. Так вы исключите множественные срабатывания кнопки за одно нажатие.

Не знаю, по мне, так:
Считали кнопки 1,2
если нажата одна, проверили - выполняется любое(закрытие-открытие) действие - стоп 
                                                не выполняется - старт действия от кнопки.

delay(200);

И не надо долго тычить пальчик. Тот случай, когда делей вполне в тему, а вся задача в тиньку со свистом поместится. ИМХО.

То ТС, это имеет право на жизнь, если не лезет помеха от реле, что весьма возможно и приделать концевики на шторы или пытаться как то запомнить их положение в момент остановки, концевики надежней.

v258
v258 аватар
Offline
Зарегистрирован: 25.05.2020

bwn пишет:

И не надо долго тычить пальчик.


А как же защита от дурака?)))

Клапауций 9999
Offline
Зарегистрирован: 27.11.2020

MaksVV пишет:

юзайте титановый велосипед, местный продукт

та, да - пордукт... местный.

сцуко, до слёз.

!Здрасте, всем.

 

Клапауций 9999
Offline
Зарегистрирован: 27.11.2020

вот это точно небезопасная архитектура:

36   pinMode(PIN_OPEN, OUTPUT);
37   pinMode(PIN_CLOSE, OUTPUT);

достаточно чуть намутить в коде и рискуешь врубить открывание и закрывание одновременно.

безопасно: одно реле на переключение режима "открывать/закрывать штору", второе реле - режим "старт/стоп открывания/закрывания".

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

ну, и аппаратные концевики - обязательно.

Алексей Н
Offline
Зарегистрирован: 02.01.2016

bwn пишет:

Считали кнопки 1,2
если нажата одна, проверили - выполняется любое(закрытие-открытие) действие - стоп 
                                                не выполняется - старт действия от кнопки.

Так мой код именно это и делает. Но с глюками :). delay пробовал вставлять после ого как обнаружено нажатие кнопки, но не работает. Все равно по симптомам похоже на то, что я очень медленно нажимаю на кнопку и за это время код успевает выполниться несколько раз.

Основную идею я уловил. Надо отслеживать не нажатие кнопки а изменение ее состояния. В библиотеке bounce2, действительно есть функция отслеживания изменения состояния. Причем можно установить какое изменение (в HIGH или в LOW) считать нажатием. Переделал код. Сейчас вроде работает четко. Есть идея отказаться от библиотеки и прописать все в коде. Там вроде несложно должно быть. Еще я хочу подавление дребезга кнопок сделать аппаратное, чтобы код упростить до минимума. И пока идут с Китая mc14490, я делаю предварительные наброски программы.

Концевики предусмотрены.

Алексей Н
Offline
Зарегистрирован: 02.01.2016

Спустя некоторое время чуть переписал код. Теперь код отслеживает изменение состояния кнопок и без библиотек. Вопрос такой возник. Поскольку отслеживается изменения состояния кнопки, то дребезг кнопок не влияет на работу кода. Но возможность поставить MC14490P для подавления дребезга у меня есть. Вопрос стоит ли добавлять аппаратное подавление дребезга к данному коду?

  // инициализируем последовательную передачу данных:
  Serial.begin(9600);
}


void loop() {
  // считываем данные с входного «кнопочного» контакта:
  button1State = digitalRead(BUTTON_PIN_1);
  button2State = digitalRead(BUTTON_PIN_2);

  // сравниваем текущее состояние (button1State) с предыдущим:
  if (button1State != lastButton1State) {
    // если состояние изменилось, увеличиваем значение счетчика:
    if (button1State == LOW) {
      // Если нажата кнопка "открыть" и движения нет
      if ( action_flag == 0 ) {
        Serial.println("on");
        digitalWrite(PIN_OPEN, HIGH); // WRITE THE NEW ledState
        timing = millis();
        action_flag = 1;
      }
      // Если нажата кнопка "открыть" и движение есть
      else {
        //Остановить движение
        digitalWrite( PIN_OPEN, LOW );
        digitalWrite( PIN_CLOSE, LOW );
        action_flag = 0;
      }
    }
    delay (200);
  }

  // сравниваем текущее состояние (button2State) с предыдущим:
  if (button2State != lastButton2State) {
    // Если нажата кнопка "закрыть" и движения нет
    if (button2State == LOW) {
      if ( action_flag == 0 ) {
        Serial.println("on");
        digitalWrite(PIN_CLOSE, HIGH); // WRITE THE NEW ledState
        timing = millis();
        action_flag = 1;
      }
      // Если нажата кнопка "закрыть" и движение есть
      else {
        //Остановить движение
        digitalWrite( PIN_OPEN, LOW );
        digitalWrite( PIN_CLOSE, LOW );
        action_flag = 0;
      }
    }
    delay (200);
  }

  // для прогона через следующий цикл
  // делаем текущее состояние предыдущим
  lastButton1State = button1State;
  lastButton2State = button2State;

// Если флаг движения установлен,отсчитываем время до отключения реле
  if (  action_flag == 1 ) {
    if (millis() - timing > 10000) { // Вместо 10000 подставьте нужное вам значение паузы
      digitalWrite( PIN_OPEN, LOW );
      digitalWrite( PIN_CLOSE, LOW );
      action_flag = 0;
    }
  }
}

 

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

При delay(200) ваще пофигу должен быть дребезг при переключении.

MaksVV
Offline
Зарегистрирован: 06.08.2015
#include <Button.h>
Button test;

#define BUT_OPEN_PIN   2   // пин ардуино, к которому подключена кнопка
#define BUT_CLOSED_PIN 3   // пин ардуино, к которому подключена кнопка

#define BUTTON_OPEN   0       // программный номер кнопки
#define BUTTON_CLOSED 1       // программный номер кнопки

#define PIN_OPEN_ACTUATOR  14
#define PIN_CLOSE_ACTUATOR 15

#define OPEN    0
#define CLOSED  1

const byte timeout = 10;  // время движения штор , сек

uint32_t timing = 0;
bool action_flag = 0 ; 

void start (const bool &Direction) 
{
action_flag = 1;
timing = millis();
digitalWrite(PIN_OPEN_ACTUATOR,  !Direction);
digitalWrite(PIN_CLOSE_ACTUATOR,  Direction);
}

void Stop () 
{
action_flag = 0;
digitalWrite(PIN_OPEN_ACTUATOR,  LOW);
digitalWrite(PIN_CLOSE_ACTUATOR, LOW);
}

void setup() 
{
test.NO(); // N.O. Normal Open
test.pullUp();
test.duration_bounce       (  50);  // время антидребезга 
test.duration_click_Db     ( 250);  // скорость дабл клика
test.duration_inactivity_Up(5000);  // время бездейтсвия отпущенной кнопки 
test.duration_inactivity_Dn(1000);  // время бездейтсвия нажатой кнопки 
test.duration_press        ( 500);  // время длинного клика
test.button(BUT_OPEN_PIN, BUT_CLOSED_PIN);   // arduino pins connected to button

pinMode(PIN_OPEN_ACTUATOR,  OUTPUT);
pinMode(PIN_CLOSE_ACTUATOR, OUTPUT);
}

void loop() 
{
  test.read(); // опрос кнопок

  if (action_flag) // если движение есть и нажата любая кнопка, остановим 
   {
    if (test.event_click_Dn (BUTTON_OPEN)==1||test.event_click_Dn (BUTTON_CLOSED)==1) 
      {
        Stop();
      }
   
   if (millis() - timing > (uint32_t)timeout * 1000ul) {Stop();}
   }

  else {  // если движения нет и нажата кнопка делаем соответствующее движение
              if (test.event_click_Dn (BUTTON_OPEN)  ==1) {start(OPEN)  ; }
         else if (test.event_click_Dn (BUTTON_CLOSED)==1) {start(CLOSED); }
       }

}

 

Клапауций 9999
Offline
Зарегистрирован: 27.11.2020

Клапауций 9999 пишет:

вот это точно небезопасная архитектура:

36   pinMode(PIN_OPEN, OUTPUT);
37   pinMode(PIN_CLOSE, OUTPUT);

достаточно чуть намутить в коде и рискуешь врубить открывание и закрывание одновременно.

безопасно: одно реле на переключение режима "открывать/закрывать штору", второе реле - режим "старт/стоп открывания/закрывания".

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

ну, и аппаратные концевики - обязательно.

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

может нужно так сделать:

25 pinMode(PIN_OPEN_CLOSE,  OUTPUT);
26 pinMode(PIN_START_STOP,  OUTPUT);

и, затем уже и титановый велосипед цеплять.

Алексей Н
Offline
Зарегистрирован: 02.01.2016

Клапауций 9999 пишет:

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

может нужно так сделать:

25 pinMode(PIN_OPEN_CLOSE,  OUTPUT);
26 pinMode(PIN_START_STOP,  OUTPUT);

и, затем уже и титановый велосипед цеплять.

Я обдумал Ваше предложение еще в первый раз. Оно также не исключает возможности "генериться случайным сигналам на управляющих пинах". Хотя и с меньшей вероятностью.

А еще я хочу использовать твердотельные реле. Они только на вкл/выкл работают (те, которые у меня). Поэтому для переключения направления не подходят.

Клапауций 9999
Offline
Зарегистрирован: 27.11.2020

Алексей Н пишет:

Я обдумал Ваше предложение еще в первый раз.

обдумал, но на прямой вопрос, заданный два раза отвечать не буду...(с)

ок. попытка номер три - опубликуйте сюда схему силовой части шторы.

 

 

Алексей Н
Offline
Зарегистрирован: 02.01.2016

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

"Схему" прикладываю. Надеюсь Вас не покоробит от картинки из Fritzing. Вроде никаких подводных камней? два реле управляются двумя пинами ардуино. Провода от ардуино до реле максимально короткие и толстые.

Клапауций 9999
Offline
Зарегистрирован: 27.11.2020

я спрашивал, сгорит ли ваш дом после включения шторы на закрытие и открытие одномоментно?

если "да", то нужно воспользоваться моим советом.

SLKH
Offline
Зарегистрирован: 17.08.2015

Алексей Н пишет:

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

"Схему" прикладываю. Надеюсь Вас не покоробит от картинки из Fritzing. Вроде никаких подводных камней? два реле управляются двумя пинами ардуино. Провода от ардуино до реле максимально короткие и толстые.

для себя я сделал бы по #11.

С некоторой модификацией: одно реле твердотельное, второе эл.магнитное с перекидным контактом; контакты не будут срабатывать под напряжением, так что проблемы искрения, помех и т.п. неактуальны.

==============

и логика может быть такой (борьба с дребезгом не нужна):

при нажатии кнопки "против движения"

мотор стоп;

делэй;

если кнопка еще не отпущена, включаем мотор, куда надо;

Клапауций 9999
Offline
Зарегистрирован: 27.11.2020

какой вообще в этом всём смысл, если управление шторой ручное?

один тумблер на три положения и два концевика достаточны для комфортной эксплуатации шторы.

О_о

SLKH
Offline
Зарегистрирован: 17.08.2015

Клапауций 9999 пишет:
какой вообще в этом всём смысл, если управление шторой ручное? один тумблер на три положения и два концевика достаточны для комфортной эксплуатации шторы. О_о
И то верно...

Алексей Н
Offline
Зарегистрирован: 02.01.2016

Клапауций 9999 пишет:
какой вообще в этом всём смысл, если управление шторой ручное? один тумблер на три положения и два концевика достаточны для комфортной эксплуатации шторы. О_о

Как учат нас основатели дзена, смысла вообще нигде ни в чем нет.

А вообще, Вы додумываете то, чего я нигде не писал. Даже на "недосхеме" выше указан модуль ttl-rs485. С помощью которого, модули будут объединяться в сеть и иметь возможность управляться еще и удаленно. Если я про них не спрашиваю, это не значит, что их нет. Модули едут, код пишется. Я задаю простые вопросы, ответы на которые смогу понять.

Вы сами додумали за меня, что я собираюсь сделать, и объявили это фигней :) Как так-то?

Про использование твердотельного и электромагнитного реле я подумаю.

vosara
vosara аватар
Offline
Зарегистрирован: 08.02.2014

Почитайте тему http://arduino.ru/forum/programmirovanie/proshu-pomoshchi-problema-s-odnovremennoi-rabotoi-shagovykh-dvigatelei

Может найдете не только ответы но и готовое решение

Клапауций 9999
Offline
Зарегистрирован: 27.11.2020

Алексей Н пишет:

Как учат нас основатели дзена, смысла вообще нигде ни в чем нет.

А вообще, Вы додумываете то, чего я нигде не писал. Даже на "недосхеме" выше указан модуль ttl-rs485. С помощью которого, модули будут объединяться в сеть и иметь возможность управляться еще и удаленно. Если я про них не спрашиваю, это не значит, что их нет. Модули едут, код пишется. Я задаю простые вопросы, ответы на которые смогу понять.

Вы сами додумали за меня, что я собираюсь сделать, и объявили это фигней :) Как так-то?

Про использование твердотельного и электромагнитного реле я подумаю.

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

я три раза повторил один и тот же вопрос в разных формулировках: что произойдёт, если будут включены одномоментно режимы открытия и закрытия шторы?

ответа я не получил, поэтому что бы ты не самоубился, начитавшись форума, предложил самый безопасный вариант.

 

Алексей Н
Offline
Зарегистрирован: 02.01.2016

Да ладно-ладно... вот с твердотельным и электромагнитным реле вроде нормальная идея.

Спасибо за советы.

Клапауций 9999
Offline
Зарегистрирован: 27.11.2020

Алексей Н пишет:

Да ладно-ладно... вот с твердотельным и электромагнитным реле вроде нормальная идея.

...повбивав бы. О_о

SLKH
Offline
Зарегистрирован: 17.08.2015

Алексей Н пишет:

Клапауций 9999 пишет:
какой вообще в этом всём смысл, если управление шторой ручное? один тумблер на три положения и два концевика достаточны для комфортной эксплуатации шторы. О_о

Как учат нас основатели дзена, смысла вообще нигде ни в чем нет.

А вообще, Вы додумываете то, чего я нигде не писал.

Ничего он не додумывал. Вы писали про две кнопки со всякими программами - это действительно с успехом заменяется на тумблер on-off-on.

Цитата:
Даже на "недосхеме" выше указан модуль ttl-ttl-rs485.
ни хрена там не указано  - на самом деле там изображена какая-то НЁХ без обозначений. естественно, никто её не разглядывал и не пытался угадать, что это и зачем.

Цитата:
С помощью которого, модули будут объединяться в сеть и иметь возможность управляться еще и удаленно. Если я про них не спрашиваю, это не значит, что их нет. Модули едут, код пишется. Я задаю простые вопросы, ответы на которые смогу понять.

Вы сами додумали за меня, что я собираюсь сделать, и объявили это фигней :) Как так-то?

наоборот. Мы не проинтуичили ваши планы создания глобальной сети и отвечали на заданный вопрос: управление шторой двумя кнопками.