Библиотека "GyverButton.h" и одновременное нажатие 2-х кнопок

dim3740

✩✩✩✩✩✩✩
17 Июн 2020
16
0
упрощенный код:
  //
#include "GyverButton.h"
GButton  b1(4);
GButton  b2(5);

void loop()
{
  if ((digitalRead(b1) == 0) && (digitalRead(b2) == 0))
  {
    if (fPr == 0)
    {
      fPr = 1;
      lcd.print("Обе нажаты ");
      delay(300);  // для меня это приемлимо! Хоть 5 минут могу ждать:)))

      // тут нужно вставить "очистку" некого флага, что прежде все же нажалась только одна из кнопок.
       // Иначе после делея она все же отработает.
    }
  }
  else
  {
    b1.tick();
    b2.tick(); // там сбросится fPr
  }
}
Прошу совета.
 

bort707

★★★★★★✩
21 Сен 2020
3,067
915
Если вы работаете с библиотекой, вы не должны читать кнопку через digitalRead(). Пользуйтесь методами библиотеки для проверки кнопок
 

dim3740

✩✩✩✩✩✩✩
17 Июн 2020
16
0
Спасибо. Я и читаю если нужны обработчики, которые есть в библе. Но там нет "одновременного нажатия 2- кнопок". Приходится искать обходные пути. Я думаю, что в библе должен быть параметр, отвечающий за статус события нажатия. Надо научить меня его очищать.

Пример. Допустим на кнопку назначен press & release. Нажали, ушли на обработчик по библе, ждем / проверяем нажатие второй кнопки. Нажали и ее. Отлично, зафиксировали. Но при отпускании первой кнопки все равно отработается release. А этого не нужно.

В библиотеке есть функции, возвращающие состояние кнопок. Как это может помочь? По идее, значит и переменную состояния можно модифицировать программно.
 
Изменено:

bort707

★★★★★★✩
21 Сен 2020
3,067
915
Если есть функции, проверящие состояние кнопок - то все, что вам нужно сделать - это дождаться, чтобы эти функции для обоих кнопок вернули состояние " нажато".
 

dim3740

✩✩✩✩✩✩✩
17 Июн 2020
16
0
C++:
if (butt1.isPress()) Serial.println("Press");         // нажатие на кнопку (+ дебаунс)
if (butt1.isRelease()) Serial.println("Release");     // отпускание кнопки (+ дебаунс)
На кнопку назначено 2 функции. На другую также две. По нажатию первой отработается первая строчка. Аналогично по второй кнопке.

Вопрос: как исключить выполнение второй строки, поскольку это иное событие - "2 кнопки одновременно" .
 

bort707

★★★★★★✩
21 Сен 2020
3,067
915
Вы так пишете, будто эти функции кто-то назначает за вас и вы не можете их менять. Но ведь вы же сами их и назначаете. А значит можете прописать в событие по отпусканию проверку, не было ли перед ним нажатия двух кнопок - и если было, игнорировать его.
 

Boroda22

★✩✩✩✩✩✩
23 Фев 2022
251
42
А в одно условие нельзя завернуть проверку двух кнопок?
 

dim3740

✩✩✩✩✩✩✩
17 Июн 2020
16
0
Я вопрос так и не решил. Думаю, что желаемое, одновременно с необходимостью ВСЕХ вариантов нажатий кнопок, просто нереализуемо. Ибо, "press" (т.е. отработка кнопки прямо в момент нажатия) всегда будет приоритетнее, чем любые алгоритмы определения совместного нажатия кнопок. Частичное решение можно получить, если все же как я и предполагал, это предварительная обработка 2-х кнопок ВНЕ библиотеки, а уже затем, если это не выполнено, передача на команду tick в loop, который и передаст управление в функцию, где будут описаны различные варианты нажатий.
 

Старик Похабыч

★★★★★★★
14 Авг 2019
4,272
1,303
Москва
Ну если так подумать.
Что есть одновременное нажатие кнопок ? Такого событие бывает очень редко. всегда одна из кнопок будет нажата чуть раньше.
Значит "одновременное" нажатие уже не такое одновременное, а просто нажатие 2х кнопок с небольшой (какой ? ) разницей по времени.
Тогда такой алгоритм.
При нажатии одной из 2-х кнопок запоминается время нажатия. При нажатии другой кнопки сравнивается разница времен с каким то эталоном и если разница меньше эталона, то считается что нажатие "одновременное" и выставляется соотв. флаг.
Библиотека Гайвера не работает с 2-мя кнопками как с массивом кнопок. Поэтому и нет у нее такой функции.

Для примера накидал простенький алгоритм обработки парного нажатия (именно нажатия!)
На остальные клики и пр не тестировал.
C++:
#include <GyverButton.h>

#define Btn_ok_Pin 3   
#define Btn_left_Pin 5

GButton btn_ok(Btn_ok_Pin);  
GButton btn_left(Btn_left_Pin);
void setup() {
  Serial.begin(115200);
  Serial.println("Start");

}

void loop() {
  btn_ok.tick();
  btn_left.tick();
  if (btn_ok.isPress())
    if (isDoublePress(1))Serial.println("Double");
  if (btn_left.isPress())
    if (isDoublePress(2))Serial.println("Double");

}

bool isDoublePress(uint8_t n)
{
  static bool f1 = false;
  static bool f2 = false;
  static uint32_t tmr = 0;
  if (n == 1)
  {
    if (f2)
    {
      f2 = false;
      return (millis() - tmr < 50);
    }
    else
    {
      f1 = true;
      tmr = millis();
    }
  }

  if (n == 2)
  {
    if (f1)
    {
      f1 = false;
      return (millis() - tmr < 50);
    }
    else
    {
      f2 = true;
      tmr = millis();
    }
  }
  return false;
}
 
  • Лойс +1
Реакции: Sergo_ST

poty

★★★★★★✩
19 Фев 2020
3,261
948
@dim3740, мне кажется, стоит ознакомиться с принципами библиотеки. "Обработка нажатия" может производиться как и когда угодно. Всё это превращается в статус, возвращаемый разными методами библиотеки. "Приоритет" обработки определяется Вами, а не библиотекой. Не нужно использовать библиотеку, если Вы считаете, что Вам нужно добраться до внутренних переменных.
Подсказка: нужно чётко регламентировать какие действия с кнопками Вы отрабатываете, с какими таймингами и приоритетом. И тогда станет всё кристально ясно.
 

dim3740

✩✩✩✩✩✩✩
17 Июн 2020
16
0
Прочитал. Итак, есть скажем 2 кнопки. На каждую назначены обработчики в терминологии библы: Click, Long, Press, Release. Итого можно получить 8 различных возвратов. Задача: добавить 9. Для этого можно: 1) одновременное нажатие двух (нет в библе) 2) двойной (тройной) клик - есть в библе. Пробуем вар2 на 1 кнопку. Наблюдаем, что прежде отработается Press 1 кнопки, и затем функция 9. Не устраивает. При варианте 1 - тоже самое. Понятно, что проблема в нулевом тайминге функции Press, и это неизбежно. Я, увы, не могу НЕ обрабатывать /исключить Press(((

Решение: ЛЮБАЯ функция библиотеки запускается с задержкой (50-100 мс меня устроит). Прежде в течение 50-100 мс неким алгоритмом анализируется одн.наж.двух.кнопок. Если его нет - то запускается библа, как tick. Если так, то помогите написать код.

Вышеописанный код будет работать, но, после отработки совместного нажатия, программа все равно выдаст функцию
if (btn_ok.isPress()), т.к. она, по моему мнению, "запоминается" в библе и отрабатывается ПОСЛЕ других событий все равно. Как ее "обнулять" я не знаю.
 
Изменено:

dim3740

✩✩✩✩✩✩✩
17 Июн 2020
16
0
Ох... если это так- то ура! чуть попозже поищу. В примерах я не встретил ее.

Спасибо. Строка 16 кода первого моего поста и воспрашала это.

Странно, что мы так далеко ушли от решения(((( Надо было джина ждать:).
 

bort707

★★★★★★✩
21 Сен 2020
3,067
915
Странно, что мы так далеко ушли от решения(((( Надо было джина ждать:).
потому что путь через обнуление статуса - это кривой костыль. К сожалению, вам несколько раз пытались обьяснить, как обойтись без него - но вы настаиваете именно на этом варианте...
 

Kir

★✩✩✩✩✩✩
28 Мар 2020
69
16
@dim3740, в данном классе вызов метода проверки состояния сразу сбрасывает внутренний флаг, поэтому на следующей итерации, если кнопка была не отпущена, вернется уже false, что, по моему скромному мнению, логически не верно. Т.е. if (b1.isPress() && b2.isPress()) будет работать крайне плохо, так как в реальности кнопки так быстро, как выполняется проверка, не нажимаются, плюс ко всему, время дребезга тоже никто не отменял. Как вариант - это выполнять подобную проверку с достаточно большим прореживанием по времени. Вероятность попасть проверкой в момент нажатия будет тем меньше, чем больше период проверки. Другой вариант - создать свою обработку, для этого придется ввести флаг нажатия для каждой кнопки, и выставлять его когда isPress() вернет true, а сбрасывать, когда isRelease() вернет true, что, по-хорошему, должен делать класс обработки кнопки. В основном коде уже проверять, когда эти 2 флага вернут true. Честно говоря, проще реализовать самому свое решение, так как из плюсов использования класса GButton в данном случае - это встроенный антидребезг, но для кнопок есть более простой, но не менее эффективный метод, но при этом позволяющий экономить ресурс процессора, что довольно приятно всегда.
 

poty

★★★★★★✩
19 Фев 2020
3,261
948
@Kir, есть метод состояния isHold, например, есть тайминги длительности нажатий и интервалов между нажатиями. Просто когда вообще человек не понимает, что на 50мс отличить "однократное нажатие" от "двухкратного" с учётом дебаунсинга и возможностей человека невозможно, то он и говорит, что press возникает всегда.
 

Boroda22

★✩✩✩✩✩✩
23 Фев 2022
251
42
Другой вариант - создать свою обработку, для этого придется ввести флаг нажатия для каждой кнопки, и выставлять его когда isPress() вернет true, а сбрасывать, когда isRelease() вернет true, что, по-хорошему, должен делать класс обработки кнопки
Извиняюсь, но хотелось бы поинтересоваться, а событиями можно такое реализовать? Я имею ввиду в классе, чтобы подписчиков уведомлять о событии?
 

Kir

★✩✩✩✩✩✩
28 Мар 2020
69
16
@Boroda22, можно, есть даже паттерн наблюдатель, который используют для решения подобных задач. Но количество строчек кода, которые потребуется написать, а их будет не то чтобы много, но вполне вероятно больше ожидаемого, очень часто (почти всегда) многих отталкивает.
 

Boroda22

★✩✩✩✩✩✩
23 Фев 2022
251
42
@Kir,почему тогда не пользуются благами ооп? Хотя, наверное, понятно, память...
 

bort707

★★★★★★✩
21 Сен 2020
3,067
915
Почему не пользуются? Очень даже пользуются. Половина, если не две трети кода ардуино и библиотек - это ООП