Короткое и длительное нажатие кнопки

Тема в разделе "Arduino & Shields", создана пользователем vvr, 17 ноя 2014.

  1. vvr

    vvr Инженерище

    С кнопкой, подключенной к цифровому пину проблем нет, есть много работающих примеров и я их использую.
    Возникла задача организовать на кнопках, подключённых к аналоговому входу, короткое и длительное нажатие. Кнопки подключаются как на lcd шилде и код оттуда же
    Код (Text):
    #define btnPOS1  0
    #define btnPOS2  1
    #define btnPOS3  2
    #define btnPOS4  3
    #define btnSpeed  4
    #define btnNO    5

    int key      = 0;
    int adc_key_in    = 0;
    int adc_key_prev  = 0;

    int read_buttons()
    {
      adc_key_in = analogRead(1);  
      delay(15);
      int k = (analogRead(1) - adc_key_in);
      if (5 < abs(k)) return btnNO;

      if (adc_key_in > 1000) return btnNO;
      if (adc_key_in < 50)  return btnPOS1;
      if (adc_key_in < 195)  return btnPOS2;
      if (adc_key_in < 380)  return btnPOS3;
      if (adc_key_in < 555)  return btnPOS4;
      if (adc_key_in < 780)  return btnSpeed;
      return btnNO;
    }

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

    void loop()
    {
      adc_key_prev = key ;    
      key = read_buttons();
      if(key == btnPOS1 )
      {
        Serial.println("POS1");
      }
      if(key == btnNO )
      {
        Serial.println("0 POS");
      }
    }
     
    Логика вроде понятна - при нажатии key == btnPOS1 кнопки вкл таймер, при отпускании key == btnNO таймер обнуляется. По прошедшему времени определяем короткое или длительное нажатие.
    Попробовал
    Код (Text):
    if(key == btnPOS1  )
      {
        Time = millis();
        Serial.println(Time);  
      }
     
      if(key == btnNO )
      {  
        Time = 0;
      }
    Значения таймера не обнуляются. Куда копать дальше?
     
  2. vvr

    vvr Инженерище

  3. ImrDuke

    ImrDuke Гик

    А все таки как реализовать длинное\короткое нажатие с аппаратным прерыванием?
     
  4. geher

    geher Гуру

    Прерывание по CHANGE,
    в прерывании смотреть текущее значение на пине, чтобы определить, было это нажатие или отпускание.
    А дальше засекать нажатие, запоминать millis(), засекать отпускание, проверять, сколько времени прошло с последнего нажатия или выполнять действие по длинному нажатию, если с нажатия прошло достаточно времени, но отпускания еще не было.
    Примерно так..
     
  5. X-Dron

    X-Dron Гик

    Вот это


    я делал так
    Код (Text):
        #include <DI.h>        //подключаем библиотеку DI - обработка дискретного входа из набора библиотек от X-Dron
        #include <Timer_P.h>    //подключаем библиотеку Timer_P - работа с таймерами из набора библиотек от X-Dron
        #include <TM1637.h>    //подключаем библиотеку цифрового четырехзначного индикатора

        #define Key_P_PIN 2
        #define Key_M_PIN 3
        #define DISPLAY_CLK_PIN 12  //PIN контакта CLK индикатора
        #define DISPLAY_DIO_PIN 13  //PIN контакта DIO индикатора

        // Создание объектов типа "Дистретный вход" они посажены описанные выше пины. Фильтр антидребезга 20мс.
        DI Key_P(Key_P_PIN, 20);
        DI Key_M(Key_M_PIN, 20);
        TM1637 display(DISPLAY_CLK_PIN, DISPLAY_DIO_PIN);  //создание и инициализация объекта display класса TM1637
        Timer_P Period_T, Delay_T_P, Delay_T_M;
        int Value;
        long Period;
        boolean Key_P_Old, Key_M_Old;

        void setup() {
          //делать pinMode для входов не нужно. Они инициализируются при создании объекта класса DI
          //при работе со входами используется INPUT_PULLUP-режим. Значения входов нормализовываются во время обработки класса.
          //замкнутая кнопка - логическая 1.
          //Включаем и настраиваем индикатор
          display.set();
          display.init();
        }

        void loop() {
          // Обновляем значение дискретных входов
          // Производится их считывание с пинов и фильтрация через внутреннюю переменную класса.
          Key_P.DI_Refresh();
          Key_M.DI_Refresh();

          Delay_T_P.TimerV(Key_P.DI_Read() && !Key_M.DI_Read(), 0, 2, 2500); // если нажата клавиша + запускаем таймер задержки
          Delay_T_M.TimerV(Key_M.DI_Read() && !Key_P.DI_Read(), 0, 2, 2500); // если нажата клавиша - запускаем таймер задержки
          if (!Key_P.DI_Read() && !Key_M.DI_Read()) Period=500; //Инициализируем период, если ничего не нажато
          // Запускаем самосбрасывающийся таймер, если нажата одна из клавиш.
          Period_T.TimerV((!Period_T.Q0() && (Key_P.DI_Read() || Key_M.DI_Read()) && !(Key_P.DI_Read() && Key_M.DI_Read())), 0, 2, Period); // Самосбрасывающийся таймер периода

          if ((Key_P.DI_Read() || Key_M.DI_Read()) && !(Key_P.DI_Read() && Key_M.DI_Read()))
          {
              if ((Key_P.DI_Read() &&  Delay_T_P.Q0()) || (Key_M.DI_Read() &&  Delay_T_M.Q0())) Period=100;
              if (Key_P.DI_Read() && (!Key_P_Old || Period_T.Q0())) Value+=1;
              if (Key_M.DI_Read() && (!Key_M_Old || Period_T.Q0())) Value-=1;
          }
          Key_P_Old = Key_P.DI_Read();
          Key_M_Old = Key_M.DI_Read();

          //Значения для отображения на каждом из 4 разрядов
          int8_t Disp[4];
          //Выводим значение отсрочки срабатывания таймера на дисплей
          Disp[0] = Value/1000;
          Disp[1] = (Value/100)%10;
          Disp[2] = (Value/10)% 10;
          Disp[3] = Value% 10;
          display.display(Disp);
        }

     
    Для кнопок с LCD Shield, но без индикатора так:
    Код (Text):
        #include <Timer_P.h>    //подключаем библиотеку Timer_P - работа с таймерами из набора библиотек от X-Dron
        #include <AnalogKey5.h>

        AnalogKey5 AKeys(10, 144, 329, 505, 742, 10); // установить пороги для срабатывания каждой кнопки, последний параметр зона отклонения
        Timer_P Period_T, Delay_T_P, Delay_T_M; // Таймеры периода и задедержек перехода на ускоренный набор
        int Value;
        long Period;
        boolean Key_P_Old, Key_M_Old;

        void setup() {
          pinMode(A0, INPUT);
        }

        void loop() {
          AKeys.Refresh (analogRead(A0));

          Delay_T_P.TimerV(AKeys.Key1() && !AKeys.Key2(), 0, 2, 2500); // если нажата клавиша + запускаем таймер задержки
          Delay_T_M.TimerV(AKeys.Key2() && !AKeys.Key1(), 0, 2, 2500); // если нажата клавиша - запускаем таймер задержки
          if (!AKeys.Key1() && !AKeys.Key2()) Period=500; //Инициализируем период, если ничего не нажато
          // Запускаем самосбрасывающийся таймер, если нажата одна из клавиш.
          Period_T.TimerV((!Period_T.Q0() && (AKeys.Key1() || AKeys.Key2()) && !(AKeys.Key1() && AKeys.Key2())), 0, 2, Period); // Самосбрасывающийся таймер периода

          if ((AKeys.Key1() || AKeys.Key2()) && !(AKeys.Key1() && AKeys.Key2()))
          {
              if ((AKeys.Key1() &&  Delay_T_P.Q0()) || (AKeys.Key2() &&  Delay_T_M.Q0())) Period=100;
              if (AKeys.Key1() && (!Key_P_Old || Period_T.Q0())) Value+=1;
              if (AKeys.Key2() && (!Key_M_Old || Period_T.Q0())) Value-=1;
          }
          Key_P_Old = AKeys.Key1();
          Key_M_Old = AKeys.Key2();
        }
    Понадобится библиотека класса AnalogKey5. Она по ссылке.
    https://yadi.sk/d/WrKRyFqLeSprm
    В общую библиотеку пока не включил.
     
    Последнее редактирование: 4 фев 2015
  6. snake32

    snake32 Нерд

    ImrDuke нравится это.
  7. X-Dron

    X-Dron Гик

    Можно и это использовать :)