Долгое нажатие клавиши

Тема в разделе "Arduino & Shields", создана пользователем ZVEN, 3 май 2017.

  1. ИгорьК

    ИгорьК Гуру

    ... и, главное, новичку-ТС понятно.
     
    ostrov нравится это.
  2. ostrov

    ostrov Гуру

    Давайте пример нежесткой выборки и абстракции. А так звучит красиво.
     
  3. qwone

    qwone Гик

    Полный пакет здесь https://yadi.sk/d/XQJnIzg43HEeJa
    Ну головной файл тут
    Код (C++):
    /* Cl_do_btn.ino
        кнопка
    */

    void none() {}
    void f1() {
      Serial.println("knok1-knok1");
    }
    void f2() {
      Serial.println("knok2-knok2");
    }
    #include "Cl_do_btn.h"
    Cl_do_btn btn1(2, 0, none); //пин 2, 0 уров наж.кнопки , выполнить функцию none()
    Cl_do_btn btn2(3, 0, none); //пин 3, 0 уров наж.кнопки , выполнить функцию none()

    void setup() {
      Serial.begin(9600);
      btn1.setup();
      btn1.Do_Btn = f1;
      btn2.setup();
      btn2.Do_Btn = f2;
    }
    void loop() {
      btn1.loop();
      btn2.loop();
    }

    Здесь вы видете, что можно програмно задавать и менять действие при нажатии клавиши. Такая себе нежесткая логика. А поменяв подключаемый модуль можно подключить или аналоговую клавиатуру или ИК приемник.
     
    ИгорьК нравится это.
  4. mcureenab

    mcureenab Гуру

    Что делает это выражение?
    Код (C++):

    class Cl_do_btn {
    ....
        bool low;
    ....
        inline bool read() {
          return digitalRead(pin)^low;  // ???
        };
    ....
     
     
  5. mcureenab

    mcureenab Гуру

    Для инициализации членов класса в конструкторе есть специальный раздел.

    Код (C++):
    Cl_do_btn::Cl_do_btn(byte _pin, bool high, void (* _Do_Btn)()):
      pin(_pin),
      low (!high),
      Do_Btn (_Do_Btn)
    {
    }
     
    Если не делать так, то члены класса сначала принимают значения по умолчанию, а затем в теле конструктора им присваиваются новые значения. Двойная работа.
    Нужно учесть что инициализация происходит в порядке объявления членов в классе, а не как они перечислены в конструкторе.
     
  6. ostrov

    ostrov Гуру

    Это инверсия так сделана?
    Код (C++):
    return digitalRead(pin)^low;
     
  7. ostrov

    ostrov Гуру

    То есть функция так же циклически вызывается, внутри ожидается факт отпускания кнопки с засеканием времени удержания. Собственно все это можно же сделать обычной функцией с парой-тройкой строк внутри. Разве что библиотекой удобнее пользоваться тем же новичкам. А по размеру кода как дела обстоят? Проверить не могу, не дома.
     
  8. mcureenab

    mcureenab Гуру

    Недокументированная фича. Предполагается, что LOW это 0. А HIGH это 1.
     
  9. qwone

    qwone Гик

    Скорее всего вы заблуждаетесь. Этот класс создан для того что бы не парить мозг при переделке, когда уровень нажатой кнопки 0 , а когда единица. Можно было назвать переменную ON или оn, но для меня это слово зарезевировано для функции "включить". Так что пришлось назвать ее high. То есть если high = 1, то уровень нажатой клопки 1. Но операция "Исключающая ИЛИ" [^] немного неудобно устроена Уровень тогда был бы digitalRead(pin)^(!high) . Но что бы не напрягать себе голову я применил digitalRead(pin)^low. Просто . Тем более класс я рисовал для себя.
     
  10. qwone

    qwone Гик

    Разумеется можно даже написать и в коде любителям. Я вообще-то борюсь с программами - простынями в 100-200-1000 строк. Так что там функция, там функция и привет простыня. А там где простыня, может быть глюки, как минимум с совпадением названий переменных.

    Если вам интересно , то я подкину еще один код. Пакет здесь.https://yadi.sk/d/ZYZuO8v93HiDs4
    Код (C++):
    /* Plug_btm.ino
       подключить кнопку->2 // при нажатии сделать фукнцию 1
       подключить кнопку->3 // при нажатии сделать фукнцию 2
    */

    #include "Cl_do_btn.h"
    void f1() {
      Serial.println("knok1-knok1");
    }
    void f2() {
      Serial.println("knok2-knok2");
    }
    void setup() {
      Serial.begin(9600);
      Plug_btm(2, 0, f1); //пин 2, 0 уров наж.кнопки , выполнить функцию f1()
      Plug_btm(3, 0, f2); //пин 3, 0 уров наж.кнопки , выполнить функцию f2()
    }
    void loop() {
      Btns_loop();
    }
     
    Последнее редактирование: 5 май 2017
  11. Eragon

    Eragon Нерд

    А можно пример кода, на словах не понятно( Я находил пример кода, там почти то, что мне надо, но работает этот код криваовато...
    Код (C++):
    #define buttonPin 19 // analog input pin to use as a digital input
    #define ledPin1 9 // digital output pin for LED 1 indicator
    #define ledPin2 8 // digital output pin for LED 2 indicator

    #define debounce 20 // ms debounce period to prevent flickering when pressing or releasing the button
    #define holdTime 2000 // ms hold period: how long to wait for press+hold event

    // Button variables
    int buttonVal = 0; // value read from button
    int buttonLast = 0; // buffered value of the button's previous state
    long btnDnTime; // time the button was pressed down
    long btnUpTime; // time the button was released
    boolean ignoreUp = false; // whether to ignore the button release because the click+hold was triggered

    // LED variables
    boolean ledVal1 = false; // state of LED 1
    boolean ledVal2 = false; // state of LED 2


    //=================================================


    void setup()
    {

    // Set button input pin
    pinMode(buttonPin, INPUT);
    digitalWrite(buttonPin, HIGH );

    // Set LED output pins
    pinMode(ledPin1, OUTPUT);
    digitalWrite(ledPin1, ledVal1);
    pinMode(ledPin2, OUTPUT);
    digitalWrite(ledPin2, ledVal2);

    }


    //=================================================


    void loop()
    {

    // Read the state of the button
    buttonVal = digitalRead(buttonPin);

    // Test for button pressed and store the down time
    if (buttonVal == LOW && buttonLast == HIGH && (millis() - btnUpTime) > long(debounce))
    {
    btnDnTime = millis();
    }

    // Test for button release and store the up time
    if (buttonVal == HIGH && buttonLast == LOW && (millis() - btnDnTime) > long(debounce))
    {
    if (ignoreUp == false) event1();
    else ignoreUp = false;
    btnUpTime = millis();
    }

    // Test for button held down for longer than the hold time
    if (buttonVal == LOW && (millis() - btnDnTime) > long(holdTime))
    {
    event2();
    ignoreUp = true;
    btnDnTime = millis();
    }

    buttonLast = buttonVal;

    }


    //=================================================
    // Events to trigger by click and press+hold

    void event1()
    {
    ledVal1 = !ledVal1;
    digitalWrite(ledPin1, ledVal1);
    }

    void event2()
    {
    ledVal2 = !ledVal2;
    digitalWrite(ledPin2, ledVal2);
    }
     
  12. ostrov

    ostrov Гуру

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

    qwone Гик

    Если вам надо отличать короткое и длинное нажатие (0,5 сек) то Пакет здесь https://yadi.sk/d/CB38v5-13F3VQM
    И да он написан в более давнишнем стиле.
    Код (C++):
    /*Class_do_btn_long.ino
      кнопка 1    ->2 (btn1_pin)  кнопка
    */

    #include "Cl_do_btn_long.h"
    const byte btn1_pin = 2;
    Cl_do_btn_long Btn1(btn1_pin);// подключить кнопку на выв 2
    void Do_Btn1() {
      Serial.println("Do_Btn1");
    };
    void DoLong_Btn1() {
      Serial.println("DoLong_Btn1");
    };
    void setup() {
      Serial.begin(9600);
      Btn1.setup();
    }
    void loop() {
      Btn1.loop(& Do_Btn1, &DoLong_Btn1);
    }
     
  14. Eragon

    Eragon Нерд

    А время длинного нажатия можно менять?
     
  15. Eragon

    Eragon Нерд

    ОК! :) Спасибо!
     
  16. qwone

    qwone Гик

    Да .
    Код (C++):
    /*Cl_do_btn_long.h
    */

    #ifndef Cl_do_btn_long_h
    #define Cl_do_btn_long_h

    #include "Arduino.h"
    class Cl_do_btn_long {
      public:
        Cl_do_btn_long(byte _pin);
        void setup();
        void loop(void (* Do_1)(), void (* Do_3)());
      private:
        byte pin ;
        bool btn, btn_old;
        bool bounce_btn = 0; // антидребезговый флаг
        uint32_t past = 0 ;
        const uint32_t time = 500 ;//<--------- здесь и выставляй время
        bool flag = 0;
        uint32_t past_flag = 0 ;
    };
     
  17. mcureenab

    mcureenab Гуру

    Я не про вашу переменную high, а про библиотечные константы HIGH и LOW, которые возвращает digitalRead.
    С чего вы взяли что HIGH^true = HIGH^1 это 0 = false?
     
  18. qwone

    qwone Гик

    Ну не знаю. Может у вас digitalRead возвращает библиотечные константы HIGH и LOW. У меня возвращает булевые 1 и 0. Да true , false я предпочитаю не использовать. Так мне легче отлаживать и плотнее запись кода.
     
  19. Eragon

    Eragon Нерд

    Трудновато для понимания, тем более ООП ещё не изучал:(
     
  20. ostrov

    ostrov Гуру

    Вот пример как отличать долгое от недолгого в трех градациях. Но здесь будет срабатывать только после того как кнопка будет отжата в зависимости от того сколько была нажата. Если нужно чтоб срабатывало само после удержания кнопки более какого то времени, потребуется доработать.
    Код (C++):
    #define BUT_1 8 // пин кнопки

    void setup() {
      pinMode(BUT_1, INPUT_PULLUP);
      pinMode(13, OUTPUT);
    }

    void loop() {
      keyPress_1();
      // keyPress_2();
      // keyPress_3();
      // делаем что то еще
    }

    void keyPress_1() {
      static unsigned long timerInc = 0;
      static unsigned long timerPress;
      static unsigned long tPress;
      static byte butStat[2];
      if (timerInc > millis()) return;
      butStat[0] = butStat[1];
      butStat[1] = digitalRead(BUT_1);
      if (!butStat[1] && butStat[0]) timerPress = millis(); // нажали
      if (butStat[1] && !butStat[0]) {                      // отжали
        tPress = millis() - timerPress;
        if (tPress > 5000) {
          digitalWrite(13, HIGH);
          // более 5 сек
        } else if (tPress > 2000) {
          digitalWrite(13, LOW);
          // более 2 сек, но менее 5 сек
        } else {
          // менее 2 сек
        }
      }
      timerInc = millis() + 100;      // пауза опроса
    }