долгое нажатие на кнопку, что не так?

neid86@gmail.com
Offline
Зарегистрирован: 28.10.2014

Всем привет! пытаюсь на одну кнопку навесить несколько функций, короткое нажатие и длинное нажатие!Что делаю не так?

// джойстик
#define rows 3
#define cols 2
// номера кнопок в соответствии со схемой
const byte keys[rows][cols] = 
{
  {1,4},
  {2,5},
  {6,3}
};

// состояния направлений енкодера
const byte encoderdirection[3][3] = // 0 - на месте, 1 - вниз, 2 - вверх
{
  {0, 1, 2},  // 0
  {2, 0, 1},  // 1
  {1, 2, 0}   // 2     
};

// 10 9 8 7 6 5

// строки
// красный ч красный
// коричневый ч желтый 6
// черный ч черный
// столбцы
// зеленый б красный
// голубой б черный
// желтый б желтый

// номера пинов
const byte rowPins[rows] = {10, 9, 8}; // строки (желтый, зеленый, голубой)
const byte colPins[cols] = {7, 5}; // столбцы (черный, красный)
#define encoderPin 6 // пин енкодера (коричневый)
byte encodervalue;

// маски для клавиш
#define MaskMediaButton      1 
#define MaskRadioButton      2
#define MaskVolumeUpButton   4
#define MaskVolumeDownButton 8
#define MaskOkButton         16
#define MaskMuteButton       32 
#define MaskScrollDown       64 
#define MaskScrollUp         128 
#define MaskLongPress        256

unsigned long starttime;
bool workkbd; 

unsigned long startlongpresstime;
bool oldpressed;
/////////////////////////////////////////////////////////////////

void setup() 
{ 
  Serial.begin(9600); 
  int i;
  // строки - на выход
  for (i = 0; i < rows; ++i)
  {
    pinMode(rowPins[i], OUTPUT);
  }
  
  // столбцы - на вход
  for (i = 0; i < cols; ++i)
  {
    pinMode(colPins[i], INPUT);
    digitalWrite(colPins[i], HIGH); // включаем подтягивающий резистор  
  }

  // столбец для енкодера
  pinMode(encoderPin, INPUT);
  digitalWrite(encoderPin, HIGH); // включаем подтягивающий резистор  
   
  encodervalue = 0;
  
  starttime = millis();
  workkbd = false;
  oldpressed = false;
}

// сканирование джойстика
unsigned int scan(void)
{
  int i, j;
  unsigned int code = 0;
  bool pressed = false;        
  for (i = 0; i < rows; ++i)
  {
    digitalWrite(rowPins[i], LOW);

    // кнопки
    for (j = 0; j < cols; ++j)
    {
      if(digitalRead(colPins[j]) == false)
      {
        code |= 1 << (keys[i][j] - 1);
        pressed = true;
      }         
    }
       
    // енкодер
    if (digitalRead(encoderPin) == false)
    {
      int oldencodervalue = encodervalue;
      encodervalue = i;
                        
      switch (encoderdirection[oldencodervalue][encodervalue])
      {
        case 1:  // вниз
          code |= 64;
          break;
        case 2:  // вверх
          code |= 128;
          break;
      }
    }
        
    digitalWrite(rowPins[i], HIGH);    
  }
 if (code |= 16 & pressed == true)
  {
    if (oldpressed == false)
    {
      startlongpresstime = millis();
      
    }
    else
    {
      if (millis() - startlongpresstime > 1000) // значение временного промежутка в мс
      {
        code |= 256;
        startlongpresstime = millis(); // сброс счетчика. иначе признак будет выполняться каждый цикл опроса
      }
    }
  }

  oldpressed = pressed;
  
  return code;
}


// цикл программы
void loop() 
{
  unsigned int code;
  
  code = scan();
  
  if (workkbd == false)
  {
    if (millis() - starttime > 3000)
      workkbd = true;
    
    return;
  }
  
  if (code & MaskMediaButton){delay(250);
    if (code & MaskMediaButton){
    Serial.print("Source>");
    Serial.println();}}
    

  if (code & MaskRadioButton){delay(250);
    if (code & MaskRadioButton){
    Serial.print("Source<");
    Serial.println();}}
    

  if (code & MaskVolumeUpButton){delay(250);
  if (code & MaskVolumeUpButton){
    Serial.print("VolumeUp");
    Serial.println();}}

  if (code & MaskVolumeDownButton){delay(250);
  if (code & MaskVolumeDownButton){
    Serial.print("volumeDown");
    Serial.println();}}

  if (code & MaskOkButton){delay(250);
  if (code & MaskOkButton){
    
    Serial.print("TR");
    Serial.println();
    
   }
  }

  if (code & MaskMuteButton){delay(250);
  if (code & MaskMuteButton){ 
    Serial.print("Mute");
    Serial.println();}}

  if (code & MaskScrollDown){
    Serial.print("RotateDown");
    Serial.println();}

  if (code & MaskScrollUp){
    Serial.print("RotateUp");
    Serial.println();}
  
  if (code & MaskLongPress){
    Serial.print("BAND");
    Serial.println();}
   
}

Serial выводит несколько TR и только потом одно BAND... задача стоит сделать если коротко то TR, если длинно то BAND, а не tr tr tr tr band Помогите что не так делаю

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

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

класс титановый велосипед для тактовой кнопки.

neid86@gmail.com
Offline
Зарегистрирован: 28.10.2014

Да нет спасибо, что мне его подгонять под матрицу надо и не известно что из этого получится...

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

neid86@gmail.com пишет:
не известно что из этого получится...

тот же велосипед и получится.

пользуй мой клас и библиотеку для энкодера http://www.pjrc.com/teensy/td_libs_Encoder.html

*нафига там у тебя матрицы? в чём суть сакральная?

Andy
Andy аватар
Offline
Зарегистрирован: 01.01.2016

В строке 122 какой глубокий смысл в установке бита: if (code |= 16...?

neid86@gmail.com
Offline
Зарегистрирован: 28.10.2014

да ничего сакрального... джойстик подрулевой от рено делаю обработку кнопок, кнопки там организованны в виде матричной клавиатуры 1 2 3

                                     4 5 6

                                     7 8 9

где с 1 по 6 это кнопки, а 7 по 9 это энкодер, который представляет из себя следующее: три контакта, и один общий, одно вращение(один щелчок), замыкатся к примеру на 7, еще один на 8 и далее на 9... в обратную сторону аналогично.

опрос кнопок сделал не без помощи людей(помогли с энкодером т.к. он нестандартный) все работает... но захотелось на некоторые кнопки повесить длинное нажатие. пример с mills() не особо у меня выходит!
 

 

 

neid86@gmail.com
Offline
Зарегистрирован: 28.10.2014

пардон я уже под вечер тупил... целый день возился с milis() и выло следующее, что описал в выше

Andy
Andy аватар
Offline
Зарегистрирован: 01.01.2016

Вернемся к строке 122, что ты хотел в ней написать?

 if (code |= 16 & pressed == true) //у меня фантазии не хватает понять, какой смысл ты хотел заложить в эту строку

neid86@gmail.com
Offline
Зарегистрирован: 28.10.2014

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

if (pressed == true) // из цикла понятно что есть какое то нажатие
  {
    if (oldpressed == false) 
    {
      startlongpresstime = millis(); // есть событие начинаем отсчет времени
      
    }
    else
    {
      if (millis() - startlongpresstime > 1000) // если прошло более 1 сек значение временного промежутка в мс
      {
        code |= 256; 
        startlongpresstime = millis(); // сброс счетчика. иначе признак будет выполняться каждый цикл опроса
      }
    }
  }

 

Andy
Andy аватар
Offline
Зарегистрирован: 01.01.2016

Событие надо генерить по отпусканию кнопки. И нужен антидребезг.

neid86@gmail.com
Offline
Зарегистрирован: 28.10.2014

а можете что то накинуть, как по отпуску делать или просто пример было бы достаточно, что бы понять для начала сам принцип!

Andy
Andy аватар
Offline
Зарегистрирован: 01.01.2016

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

neid86@gmail.com
Offline
Зарегистрирован: 28.10.2014

одна, т.к. как ранее писал это подрулевой джойсик и комбинации там не будет, да и муторно это, запоимнать их... за дорогой следить надо))

Andy
Andy аватар
Offline
Зарегистрирован: 01.01.2016

Тогда мне не понятно назначение масок для клавиш

// маски для клавиш
#define MaskMediaButton      1 
#define MaskRadioButton      2
#define MaskVolumeUpButton   4
#define MaskVolumeDownButton 8
#define MaskOkButton         16
#define MaskMuteButton       32 
#define MaskScrollDown       64 
#define MaskScrollUp         128 
#define MaskLongPress        256

В данной реализации предполагается возможность нажатия нескольких кнопок. Если в любой момент нажимается только одна кнопка разумно возвращать только код этой кнопки. Логичнее будет так:

#define MediaButton      1 
#define RadioButton      2
#define VolumeUpButton   3
#define VolumeDownButton 4
#define OkButton         5
#define MuteButton       6 
#define ScrollDown       7 
#define ScrollUp         8 
#define MaskLongPress    0x10

 

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

Отловили нажатие кнопки, начали считать, дождались отпускания, по подсчитанному  приняли решение. Дребезг убрать.
Как вариант ликвидации дребезга, нажатие не может быть короче 20-100мС (подбирать).
Эт если лисапед уж так не нравится.

Andy
Andy аватар
Offline
Зарегистрирован: 01.01.2016

И с энкодером у меня что-то никак не укладывается в голове, для чего там матрица 3х3...

У энкодера вроде один контакт постоянно замкнут.... нет?

bad_user
Offline
Зарегистрирован: 13.11.2015

попробуйте использовать библиотеку keypad.h

с этой библиотекой удобно работать с событиями кнопки: нажата, отпущена, удержана.

void keypadEvent(KeypadEvent key){
    switch (keypad.getState()){
    case PRESSED:                                                       // НАЖАТА
        if (key == '#') { 
            digitalWrite(ledPin,!digitalRead(ledPin));
            ledPin_state = digitalRead(ledPin);       
        }
        break;

    case RELEASED:                                                    // ОТПУЩЕНА
        if (key == '*') {
            digitalWrite(ledPin,ledPin_state);    
            blink = false;
        }
        break;

    case HOLD:                                                              // УДЕРЖАНИЕ
        if (key == '*') {
            blink = true;    
        }
        break;
    }
}

 

neid86@gmail.com
Offline
Зарегистрирован: 28.10.2014

ну вы посмотрите схему, коричневый провод общий, желтый синий и зеленый., из них всегда один замкнут на коричневый

neid86@gmail.com
Offline
Зарегистрирован: 28.10.2014

накидал по отжатию

     
    if (pressed == true)
    {
    if (oldpressed == false)
    {
      startlongpresstime = millis(); //начал ситать по любому нажатию
    
    if (millis() - startlongpresstime < 1000) //если коротко нажато
     {
      ,,,,,,,,,,,,,,,,
        startlongpresstime = millis(); // сброс счетчика
      }
      else // иначе длинное нажатие
      {
        code |= 256;
        startlongpresstime = millis(); // сброс счетчика
      }
    }
}
neid86@gmail.com
Offline
Зарегистрирован: 28.10.2014

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

neid86@gmail.com
Offline
Зарегистрирован: 28.10.2014

bad_user пишет:

попробуйте использовать библиотеку keypad.h

с этой библиотекой удобно работать с событиями кнопки: нажата, отпущена, удержана.

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

Andy
Andy аватар
Offline
Зарегистрирован: 01.01.2016

neid86@gmail.com пишет:
накидал по отжатию

Тогда уж так:

if (pressed && !oldpressed) //нажатие
{
  startlongpresstime = millis(); //начал считать по любому нажатию
  oldpressed = pressed;//чтобы больше не заходить сюда
}

if (!pressed && oldpressed) //отпускание
{
  if (millis() - startlongpresstime < 1000) //если коротко нажато
  {
  }
  else // иначе длинное нажатие
  {
     code |= 256;
  }
  oldpressed = pressed;//чтобы больше не заходить сюда
}

 

neid86@gmail.com
Offline
Зарегистрирован: 28.10.2014

Andy пишет:

neid86@gmail.com пишет:
накидал по отжатию

Тогда уж так:

if (pressed && !oldpressed) //нажатие
{
  startlongpresstime = millis(); //начал считать по любому нажатию
  oldpressed = pressed;//чтобы больше не заходить сюда
}

if (!pressed && oldpressed) //отпускание
{
  if (millis() - startlongpresstime < 1000) //если коротко нажато
  {
  }
  else // иначе длинное нажатие
  {
     code |= 256;
  }
  oldpressed = pressed;//чтобы больше не заходить сюда
}

 


Вообщем вставил этот кусок кода, история таже, сначала несколько раз нажатие проскакивает кнопки и только, как отпущу кнопку и убрался больше 1 секунды, тогда уже событие))) понятно почему, если целый код смотреть, то видно что после короткого нажатия присваиваеся значение маски, и данный кусок кода не может заблокировать это действие... поэтому и проскальзывает сначало((
Спасибо вам что со мной повозились! Реально думал что можно обработать кнопку на деле все иначе... попробую пару вариантов что накидал выше народ с друшими готовыми примерами попробую переделать и подогнать под себя!