Kakmyc_btn.h (удержание кнопки)

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

Есть кнопка на пине (пусть будет «не важно какой пин»), она использует библиотеку kakmyc_btn, отлично отрабатывает нажатия и долгое удержание. Но есть необходимость кроме кликов / мультикликов / и долгого удержания кнопки ещё и в в событии «нажали и держат». То есть мультиклик сработал но кнопку все ещё держат, не отпускают и такое может длиться овердохрена времени. Как правильно это реализовать?

Либу только ленивый и Andriano (hi!) не знает ))) Но ссылка имеется: https://github.com/kakmyc-github/kakmyc_btn

Не совсем понимаю (так как я не настоящий программист), что будет происходить и какие флаги при этом правильно расставлять.

Собственно это факультатив, сегодня пятница, так что я не против превратить тему в обычное пятничное «потрепаться». А если ещё и результат будет - вот де супер)))

ЗЫ: Ещё раз автору респект, постоянно пользую. 282 байта код, 16 байт озу (в среднем на кнопку).

Kakmyc
Offline
Зарегистрирован: 15.01.2018

Она не для этого писалась.
Но если что, иногда тоже бывает нужно и сам делаю так:

Внутри нужного цикла завожу статичную переменную флага, который поднимается при событии LONG_PRESS.
Опускается флаг при условии if(digitalRead(btnPin)==NOT_PRESSED)
Ну и уже работаю в этом цикле с этим флагом.

ЗЫ: в последней итерации там вроде 240 байт сама библиотека и 14 байт ОЗУ на каждый объект кнопки

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

Берешь пример из библиотеки, заливаешь и смотришь в сериале, что выдается при неотпускании кнопки )))

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

Kakmyc пишет:
if(digitalRead(btnPin)==NOT_PRESSED)

Стесняюсь спросить, а где там вообще описан такой флаг? ))

Kakmyc
Offline
Зарегистрирован: 15.01.2018

v258 пишет:

Берешь пример из библиотеки, заливаешь и смотришь в сериале, что выдается при неотпускании кнопки )))

Ничего не выдаётся.

Kakmyc
Offline
Зарегистрирован: 15.01.2018

v258 пишет:

Kakmyc пишет:
if(digitalRead(btnPin)==NOT_PRESSED)

Стесняюсь спросить, а где там вообще описан такой флаг? ))

Где там ?
Его нужно описывать, внутри программы.
Где захочешь, там и описывай.

Kakmyc
Offline
Зарегистрирован: 15.01.2018

Что то типа этого:

 

#include <kakmyc_btn.h>
#define btnPin 4
enum {NOT_PRESSED,SHORT_PRESS,DOUBLE_CLICK,TRIPLE_CLICK,LONG_PRESS=255};
kakmyc_btn btn1(btnPin,INPUT_PULLUP,2);

void setup(){
    Serial.begin(9600);
}

void loop(){
   static boolean pressFlag=0;
    if(btn1.read()==LONG_PRESS){
        pressFlag=1;
    }
    if(pressFlag)Serial.println("btn1 pressed");
 if(digitalRead(btnPin))pressFlag=0;
}

 

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

«Девочки не ссорьтесь» (шутка юмора :) )

Я понимаю, что она (библиотека) под это не «заточена», иначе бы вообще вопросов не было. 
Что Вы (kakmyc) описали я и так понимаю, но я не хотел бы терять событие долгого удержания, вот тут и весь «косяк». Как отличить «долгое удержание» от «зажали и не отпускают»?

Kakmyc
Offline
Зарегистрирован: 15.01.2018

BOOM пишет:
как отличить «долгое удержание» от «зажали и не отпускают»?

 

А в чем разница ?

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

Kakmyc пишет:

BOOM пишет:
как отличить «долгое удержание» от «зажали и не отпускают»?

А в чем разница ?

Вот и мне бы понять в чем программно разница. А фактически - долгое удержание 2-4 сек, зажали и не отпускают - гораздо дольше. Хотя может быть в этом и ответ, только как его красиво программно «обыграть»?

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

BOOM пишет:

Kakmyc пишет:

BOOM пишет:
как отличить «долгое удержание» от «зажали и не отпускают»?

А в чем разница ?

Вот и мне бы понять в чем программно разница. А фактически - долгое удержание 2-4 сек, зажали и не отпускают - гораздо дольше. Хотя может быть в этом и ответ, только как его красиво программно «обыграть»?

в смысле - зажал и удерживаешь всю ночь? )))

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

BOOM пишет:

«Девочки не ссорьтесь» (шутка юмора :) )

Как отличить «долгое удержание» от «зажали и не отпускают»?

Это вопрос философский )) Так-то и 4 секунды - это "зажали и не отпускают"

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

v258 пишет:

Это вопрос философский )) Так-то и 4 секунды - это "зажали и не отпускают"

Да, в этом и «загвоздка». (
В библиотеке описаны тайминги, а дальше как быть чтобы и «рыбку пожарить и слона отжарить»?

ЗЫ: Пятница, вечер. Ни деды, ни Евгения Петровича, ни Андриано, никого... Я что-то не знаю?))

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

Ну вроде ж автор подсказал, как делать.

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

Но при его варианте теряется событие «долгое удержание».

При событии «долгое удержание» взвести флаг «нажали долго», далее если кнопка пин ещё в высоком состоянии... Все, спасибо. Понял как мне это сделать. Нужно было просто спросить. Спасибо всем!

Надо проверить завтра.

Дим-мычъ
Offline
Зарегистрирован: 20.03.2021

BOOM пишет:

 Как отличить «долгое удержание» от «зажали и не отпускают»?

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

 

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

BOOM пишет:

Есть кнопка на пине (пусть будет «не важно какой пин»), она использует библиотеку kakmyc_btn, отлично отрабатывает нажатия и долгое удержание. Но есть необходимость кроме кликов / мультикликов / и долгого удержания кнопки ещё и в в событии «нажали и держат».

Это ошибка проектирования.

Не должно быть одновременно событий "долгое нажатие" и "нажали и держат".

Нет, теоретически можно, конечно, реализовать что-то вроде:

- нажали на 0.1 с - действие №1,

- нажали на 0.2 с - действие №2,

- нажали на 0.3 с - действие №3,

...

- нажали на 2.3 с - действие №23,

- нажали на 2.4 с - действие №24,

...

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

Вот и в ситуации с одновременными "долгое нажатие" и "нажали и держат" будет то же самое.

 

Дим-мычъ
Offline
Зарегистрирован: 20.03.2021

andriano пишет:

Нет, теоретически можно, конечно, реализовать что-то вроде:

- нажали на 0.1 с - действие №1,

- нажали на 0.2 с - действие №2,

- нажали на 0.3 с - действие №3,

...

-

А как отделить , не отпустив кнопки? Как знать, что действие  закончилось, не отпуская?

В то же время юзать кнопку в таком режиме неудобно и непривычно ИМХО.

P.S. Разве что, синхронизируя свои действия с дисплеем, и вовремя отдёргивая руку от кнопки))

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

Дим-мычъ пишет:

А как отделить , не отпустив кнопки? Как знать, что действие  закончилось, не отпуская?

Не отпуская кнопки можно определить единственный вариант: "кнопку нажали". Никаких других вариантов нет.

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

Дим-мычъ пишет:

andriano пишет:

Нет, теоретически можно, конечно, реализовать что-то вроде:

- нажали на 0.1 с - действие №1,

- нажали на 0.2 с - действие №2,

- нажали на 0.3 с - действие №3,

...

-

А как отделить , не отпустив кнопки? Как знать, что действие  закончилось, не отпуская?

В то же время юзать кнопку в таком режиме неудобно и непривычно ИМХО.

P.S. Разве что, синхронизируя свои действия с дисплеем, и вовремя отдёргивая руку от кнопки))

1. купить вторую кнопку. Или TP229. Или клавиатуру на 100+ клавиш.

2. Если п.1 не приемлем - запрограммировать единственную кнопку на распознавание морзянки, вызов 57  функций к вашим услугам.

nik182
Offline
Зарегистрирован: 04.05.2015

Ну у меня если кнопку нажали и держат, через таймаут идёт сброс события кнопка нажата и соответственно сразу идет новое событие нажатие кнопки. Соответственно получается пулемёт выдающий нажатую кнопку. Иногда надо.  

Дим-мычъ
Offline
Зарегистрирован: 20.03.2021

andriano пишет:
Не отпуская кнопки можно определить единственный вариант: "кнопку нажали". Никаких других вариантов нет.

nik182 пишет:
Ну у меня если кнопку нажали и держат, через таймаут идёт сброс события кнопка нажата и соответственно сразу идет новое событие нажатие кнопки. Соответственно получается пулемёт выдающий нажатую кнопку. Иногда надо.

Я про то, что привычное для нас "долгое удержание" работает так:

Нажали> держим>держим>что-то произошло>уже потом отпустили, причём можно не спешить отпускать, событие уже произошло.

А если ждать, определённое время, потом отпустить, и смотреть, вовремя ли ты отпустил? произошло ли событие? - Это уже совсем не то...

SLKH пишет:
1. купить вторую кнопку

Здесь скорее самое то будет

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

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

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

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

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

NikShel
Offline
Зарегистрирован: 21.01.2018

Подписаться

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

v258 пишет:
В принципе, одной кнопкой можно выполнять овердохрена действий, главное - хорошенько продумать )))
Сэмюэл Морзе уже продумал.

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

andriano пишет:

v258 пишет:
В принципе, одной кнопкой можно выполнять овердохрена действий, главное - хорошенько продумать )))
Сэмюэл Морзе уже продумал.

еще и Q коды придумали для овердохрена сообщений )))

Kakmyc
Offline
Зарегистрирован: 15.01.2018

v258 пишет:
В принципе, одной кнопкой можно выполнять овердохрена действий, главное - хорошенько продумать )))

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

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

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

Поливалка для цветов. Несколько каналов. Одна кнопка, несколько адресных светодиодов и пищалка

Манипуляции с кнопкой для управления модулем:
  - режимы настроек
3 коротких клика – настройка времени работы помпы
4 коротких клика – настройка порога влажности (четыре уровня, 400 – 500 – 600 – 700)
5 коротких кликов – настройка минимального интервала (дней)
6 коротких кликов – настройка максимального интервала (дней)
7 коротких кликов – включение/отключение датчика влажности для канала
8 коротких кликов – включение/отключение канала целиком
3 коротких + 1 длинный - включение/отключение датчика света и пищалки об ошибках
  - режимы неавтоматического полива
1 короткий + 1 длинный - выборочный полив каналов с автоматическим дозированием воды
2 коротких + 1 длинный - полностью ручной полив без автоматического дозирования воды
*/

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

Kakmyc
Offline
Зарегистрирован: 15.01.2018

v258 пишет:

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

Поливалка для цветов. Несколько каналов. Одна кнопка, несколько адресных светодиодов и пищалка

Манипуляции с кнопкой для управления модулем:
  - режимы настроек
3 коротких клика – настройка времени работы помпы
4 коротких клика – настройка порога влажности (четыре уровня, 400 – 500 – 600 – 700)
5 коротких кликов – настройка минимального интервала (дней)
6 коротких кликов – настройка максимального интервала (дней)
7 коротких кликов – включение/отключение датчика влажности для канала
8 коротких кликов – включение/отключение канала целиком
3 коротких + 1 длинный - включение/отключение датчика света и пищалки об ошибках
  - режимы неавтоматического полива
1 короткий + 1 длинный - выборочный полив каналов с автоматическим дозированием воды
2 коротких + 1 длинный - полностью ручной полив без автоматического дозирования воды
*/

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

Это изврат

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

Знаю. Но я таки это сделал )))) Экран цеплять было некуда, не хотелось делать большую коробку

ЗЫ: там еще один режим пропущен - 4 коротких + 1 длинный ))

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

«Четыре длинных, два коротких - так в мужской бане господин Морзе изобрёл свою азбуку!» )))))) (Городок)

SAB
Offline
Зарегистрирован: 27.12.2016

v258 пишет:

- 4 коротких + 1 длинный ))

Это четыре в морзе ))))

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

SAB пишет:

v258 пишет:

- 4 коротких + 1 длинный ))

Это четыре в морзе ))))

Блин, а ведь точно ))

ЗЫ: в армии, кстати, как раз радиотелеграфистом был )))

Дим-мычъ
Offline
Зарегистрирован: 20.03.2021

Дим-мычъ пишет:
P.S. Разве что, синхронизируя свои действия с дисплеем, и вовремя отдёргивая руку от кнопки))

Ради "поиграться" сделал простейшее меню, как раз такого типа. Индикация - минимальна. Удержание кнопки - автопрокрутка позиций меню, отпускание - выбор. Можно сделать столько пунктов, сколько палец сможешь держать))

А в них ещё подпункты...))

 



#define ACTIV 0

const byte kn = 13;
const byte on = 14;
const byte pin[6] = {8, 9, 10, 11, 12, 15};
unsigned long last0_millis = 0;
int press_time = 0;
byte level = 0;
byte level_on = 0;
byte drebezg = 0;
byte btn_status;

bool button_read();
bool RDBTN = false;
bool BTN_ON = false;


void setup() {
  pinMode(kn, INPUT_PULLUP);
  pinMode(on, OUTPUT);
  for (byte i = 0; i < 6; i++)
    pinMode(pin[i], OUTPUT);
}


void loop() {

  if ((millis() - last0_millis) >= 4)  {
    last0_millis = millis();

    if (button_read()) {
      if (!BTN_ON)
        digitalWrite(pin[level_on], LOW);
      BTN_ON = true;
      press_time++;
      if (press_time >= 200) {
        press_time = 0;
        level++;
        if (level > 6)
          level = 1;
        level_on = level - 1;
      }
      switch (level) {
        case 1:
          digitalWrite(pin[sizeof(pin) - 1], LOW);
          digitalWrite(pin[level_on], HIGH);
          break;
        case 2:
          digitalWrite(pin[level_on - 1], LOW);
          digitalWrite(pin[level_on], HIGH);
          break;
        case 3:
          digitalWrite(pin[level_on - 1], LOW);
          digitalWrite(pin[level_on], HIGH);
          break;
        case 4:
          digitalWrite(pin[level_on - 1], LOW);
          digitalWrite(pin[level_on], HIGH);
          break;
        case 5:
          digitalWrite(pin[level_on - 1], LOW);
          digitalWrite(pin[level_on], HIGH);
          break;
        case 6:
          digitalWrite(pin[level_on - 1], LOW);
          digitalWrite(pin[level_on], HIGH);
          break;
      }
    }
    else {
      if (BTN_ON) {
        if (!level_on) {
          digitalWrite(on, LOW);
        }
        else {
          digitalWrite(on, HIGH);
        }
        BTN_ON = false;
        press_time = 0;
        level = 0;
      }
    }
  }
}


bool button_read() {
  if ((digitalRead(kn) == ACTIV) && !RDBTN) {
    drebezg++;
    if (drebezg >= 3){
      RDBTN = true;
      drebezg = 0;
    }
  }
  if ((digitalRead(kn) == !ACTIV) && RDBTN) {
    drebezg++;
    if (drebezg >= 3){
      RDBTN = false;
       drebezg = 0;
    }
  }
  return RDBTN;
}

P.S.  Чуть дополнил

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

Лично я щитаю, что все эти "очень длинные нажатия" - изобретение лисапедов.  Всё уже придумано до нас, одинарное нажатие, двойное нажатие, длинное нажатие и автоповтор последней кнопки, вот и всё, пожалуй, что может пригодиться в ардуино-жизни, но даже нащёт двойного нажатия я не уверен, все равно оно реализуется через одинарное.  Если сильно надо "очень длинное нажатие", напишы свой класс Switch(тумблер) у которого два устойчивых состояния, "включен" и "нет". 

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

DetSimen пишет:

но даже нащёт двойного нажатия я не уверен

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

ЗЫ: в моем описании выше "3 коротких...", "4 коротких..." и т.д. не есть тройные/четверные и т.д. клики. Там кнопка нажимается неспеша с интервалом не более секунды, ежели случайно пройдет двойной клик, то он не засчитывается. Все должно быть медленно и основательно )))

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

Да и вообще, вместо кнопки нужно использовать тумблер, а для управления прибором с помощью этого тумблера - секундомер.

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

И удлинитель ручки тумблера типа «рубильник» ))