Двойное нажатие

feel feel
Offline
Зарегистрирован: 20.05.2019

Добрый всем день! Не могу понять, что я делаю не так. 
Задача: если нажали 1 раз на кнопку, и если через 250мс не нажали еще раз, то считать как "pressed" 
             если нажали 1 раз на кнопку и через 250мс нажали еще раз, то считать как "double" 

Получается только получить pressed, а вот с double никак не могу разобраться.

 

#define button1B A0  // пин кнопки button1
int vel;
boolean button1S;   // храним состояния кнопок (S - State)
boolean button1P;   // флажки кнопок на одно нажатие (P - Press)
boolean button1DP;  // флажки кнопок на двойное нажатие (D - Double Pressed)

#define double_timer 250   // время (мс), отведённое на второе нажатие
#define debounce 80        // (мс), антидребезг
unsigned long button1_timer; // таймер последнего нажатия кнопки
unsigned long button1_double; // таймер двойного нажатия кнопки

void setup() {
  Serial.begin(9600);
  pinMode(A0,INPUT);
}

void loop() {
  //-------опрос кнопки--------
vel = analogRead(A0);
if(vel>90) {
  button1S = digitalRead(button1B);
  button(); //отработка кнопки
  //-------опрос кнопки--------
  if (button1P) {
    Serial.println("pressed");
    button1P = 0;
  }
  if (button1DP) {
    Serial.println("double");
    button1DP = 0;
  }
}
}
//------------------------ОТРАБОТКА КНОПКИ-------------------------
void button() {

if (button1S && millis() - button1_timer > debounce) {
  button1_timer = millis();
  if(button1S && millis() - button1_double < double_timer) {
    button1DP = 1;
    button1_double = millis();
  } else {
    button1P = 1;
  }
}
}

 

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

Для начала:

1. что за ерунда у тебя в строках 19 и 20?

2. как подключена кнопка? что должна дать функция digitalRead при нажатии и отпускании?

feel feel
Offline
Зарегистрирован: 20.05.2019

1. Вместо кнопки у меня пьезодатчик, использую как кнопку
2. Кнопка подключена в А0, функция digitalRead должна дать значение, если на нее идет напряжение, то 1, если нет, то 0

asam
asam аватар
Offline
Зарегистрирован: 12.12.2018

feel feel пишет:

1. Вместо кнопки у меня пьезодатчик, использую как кнопку
2. Кнопка подключена в А0, функция digitalRead должна дать значение, если на нее идет напряжение, то 1, если нет, то 0

Вы уж определитесь - читаете эту кнопку как аналоговую или логическую. 

В строках 37 и 39 надо скобки расставить, а то полный бред получатся.

На логику работы не смотрел.

 

feel feel
Offline
Зарегистрирован: 20.05.2019

Так он читает он сначала читается, как аналоговый, а потом как цифровой.
А что неправильно? В 37 и 39 перепроверил, везде скобки закрыты и тела внутри расставлены

b707
Offline
Зарегистрирован: 26.05.2017

feel feel пишет:

37 и 39 перепроверил, везде скобки закрыты и тела внутри расставлены

не имейте привычки так писать условия.

if (button1S && millis() - button1_timer > debounce) {

Во-первых, нечитабельно, во-вторых, с такой привычкой вы рано или поздно не угадаете с приоритетом операций и получится совсем не то, что задумано.

Расставляйте скобки, не жалейти их, они бесплатны:

if (button1S && ( millis() - button1_timer > debounce)) {

 

feel feel
Offline
Зарегистрирован: 20.05.2019

Спасибо большое! Буду теперь иметь ввиду
Поставил скобки, но это ничего не дало. Все осталось по прежнему

Кстати пробовал разные варианты и заметил, что если заменить "button1_timer = millis();" на "button1_double = millis();", то при нажатии выдает double, но при только при одном нажатии

void buttons() {

if (button1S && (millis() - button1_timer > debounce)) {
  button1_double = millis(); // заменил button1_timer = millis();
  if(button1S && (millis() - button1_double < double_timer)) {
    button1DP = 1;
    button1_double = millis();
  } else {
    button1P = 1;
  }
}
}

 

asam
asam аватар
Offline
Зарегистрирован: 12.12.2018

feel feel пишет:

Так он читает он сначала читается, как аналоговый, а потом как цифровой.

Объясните, пожалуйста, в чем глубокий смысл таких действий?

asam
asam аватар
Offline
Зарегистрирован: 12.12.2018


#define ButPin A0
#define DEBOUNCE_TIME 80
#define DOUBLE_TIME 250

enum ButtonStatus
{
    Released,
    Debouncing,
    Pressed,
    DoublePressed,
    Undefined
};

uint8_t GetButton()
{

   static ButtonStatus status = Released;
   static unsigned long DebounceStart;
   bool bt = (digitalRead(ButPin) == LOW);  //bt == TRUE если кнопка нажата. Замените на вашу процедуру считывания кнопки если надо
   unsigned long CurrentTime = millis();
   switch (status)
   {
    case Released:
       if (bt)
       {
           status = Debouncing;
           DebounceStart = CurrentTime;
       }
       break;
    case Debouncing:
       if((CurrentTime - DebounceStart)>=DEBOUNCE_TIME)
       {
           if (bt) status = Pressed;
           else status = Released;
       }
       break;
    case Pressed:
       if (!bt) status = Released;
       else {
          if((CurrentTime - DebounceStart)>=DOUBLE_TIME) status = DoublePressed;
       }
       break;
    case DoublePressed:
       if (!bt) status = Released;
       break;
    default:
       status = Undefined; //этого не должно быть, но на всякий случай...
   }
   if (status == Debouncing) return Pressed;
   return status;

}

void setup() {
  Serial.begin(9600);
  pinMode(ButPin,INPUT_PULLUP);
  Serial.println("Start");
}

void loop() {
  static uint8_t prevButton = Undefined;
  uint8_t button = GetButton();
  if (button != prevButton) 
  {
    Serial.println(button);
    prevButton = button;
  }
  
  delay(1);
  

}

 

feel feel
Offline
Зарегистрирован: 20.05.2019

Для того чтобы установить срабатывания функции, начиная от 90 и выше.
Дело в том, что пьезодатчик очень чувствителен, и, выставляя порог, я избавлюсь от случайной вибрации, которая включит дальнейшую функцию. А перевод в цифру просто для удобства, так как в дальнейшем не имеет значение, какой сигнал будет на пине

strarbit
Offline
Зарегистрирован: 12.06.2016

feel feel пишет:

1. Вместо кнопки у меня пьезодатчик, использую как кнопку
2. Кнопка подключена в А0, функция digitalRead должна дать значение, если на нее идет напряжение, то 1, если нет, то 0

i'm sorry, i don't understand the question. https://youtu.be/MBuywvpG0TY

/*************************************************
   NOTE FREQUENCYS
   *************************************************/
created 2019 by Johan van Vugt

#define B0  31
#define C1  33
#define CS1 35
#define D1  37
#define DS1 39
#define E1  41
#define F1  44
#define FS1 46
#define G1  49
#define GS1 52
#define A1  55
#define AS1 58
#define B1  62
#define C2  65
#define CS2 69
#define D2  73
#define DS2 78
#define E2  82
#define F2  87
#define FS2 93
#define G2  98
#define GS2 104
#define A2  110
#define AS2 117
#define B2  123
#define C3  131
#define CS3 139
#define D3  147
#define DS3 156
#define E3  165
#define F3  175
#define FS3 185
#define G3  196
#define GS3 208
#define A3  220
#define AS3 233
#define B3  247
#define C4  262
#define CS4 277
#define D4  294
#define DS4 311
#define E4  330
#define F4  349
#define FS4 370
#define G4  392
#define GS4 415
#define A4  440
#define AS4 466
#define B4  494
#define C5  523
#define CS5 554
#define D5  587
#define DS5 622
#define E5  659
#define F5  698
#define FS5 740
#define G5  784
#define GS5 831
#define A5  880
#define AS5 932
#define B5  988
#define C6  1047
#define CS6 1109
#define D6  1175
#define DS6 1245
#define E6  1319
#define F6  1397
#define FS6 1480
#define G6  1568
#define GS6 1661
#define A6  1760
#define AS6 1865
#define B6  1976
#define C7  2093
#define CS7 2217
#define D7  2349
#define DS7 2489
#define E7  2637
#define F7  2794
#define FS7 2960
#define G7  3136
#define GS7 3322
#define A7  3520
#define AS7 3729
#define B7  3951
#define C8  4186
#define CS8 4435
#define D8  4699
#define DS8 4978
#define Silence 0

#include <LowPower.h>


int val; // variable for analogread piezo
int knockPin = 2; //interrupt on pin 2 or 3
volatile int interruptSwitch = 0;

unsigned long countInterval = 1200; //max time between knocks
unsigned long startTime;
unsigned long endTime;


//melody
int tempo = 330;
int melodyLength = 145;

int melody[] = {
  C4, E4, G4, E4, G4, E4, C4, E4, G4, E4, G4, E4, B3, E4, G4, E4, G4, E4, B3, E4, G4, E4, G4, E4,
  A3, E4, G4, E4, G4, E4, A3, E4, G4, E4, G4, E4, B3, E4, G4, E4, G4, E4, B3, E4, G4, E4, G4, E4,
  C5, E4, G4, E4, G4, E4, C5, E4, G4, E4, G4, E4, B4, E4, G4, E4, G4, E4, B4, E4, G4, E4, G4, E4,
  A4, E4, G4, E4, G4, E4, A4, E4, G4, E4, G4, E4, B4, E4, G4, E4, G4, E4, B4, E4, G4, E4, G4, E4,
  C5, E5, G5, E4, G5, E5, C5, E5, G5, E4, G5, E5, B4, E5, G5, E4, G5, E5, B4, E5, G5, E4, G5, E5,
  A4, E5, G5, E4, G5, E5, A4, E5, G5, E4, G5, E5, B4, E5, G5, E4, G5, E5, B4, E5, G5, E4, G5, E5,
  C5,
};

// note durations: 4 = quarter note, 8 = eighth note, etc.:
int noteDurations[] = {

  2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
  2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
  2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
  2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
  2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
  2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
  1,

};


// interrupt function
void Interrupt ()
{
  interruptSwitch = 1;
  detachInterrupt (knockPin);
}

void setup() {
  pinMode(knockPin, INPUT);
  Serial.begin (9600);
  attachInterrupt (digitalPinToInterrupt (knockPin), Interrupt, RISING);
}


void loop() {
  pinMode(knockPin, INPUT);
  val = digitalRead (knockPin);
  if (interruptSwitch == 1) {
    delay (200);
    startTime = millis ();
    endTime = millis ();
    while (endTime - countInterval < startTime) {
      val = digitalRead (knockPin);
      endTime = millis();
      if (val == HIGH) {
        for (int thisNote = 0; thisNote < melodyLength; thisNote++) {
          int noteDuration = tempo / noteDurations[thisNote];
          tone(2, melody[thisNote], noteDuration);
          int pauseBetweenNotes = noteDuration * 1.30;
          delay(pauseBetweenNotes);
          noTone(8);
        }
      }
      Serial.println (val);
      interruptSwitch = 0;
    }

  }
  else {
    LowPower.powerDown(SLEEP_8S, ADC_OFF, BOD_OFF);
  }
}

 

feel feel
Offline
Зарегистрирован: 20.05.2019

Спасибо большое за код! Но DoublePressed у меня выводит только если кнопка была зажата после Pressed. Мне важно, чтобы она за 250мс была нажата 2 раза и ардуино давала мне только значение DoublePressed , нежели 2 раза Pressed

feel feel
Offline
Зарегистрирован: 20.05.2019

Спасибо за код! Попробовал сделать вывод в serial.println, ничего не получилось. Возможно из-за функции прерывания, не особо понимаю для чего она тут.

int vel;
int val; // variable for analogread piezo
int knockPin = A0; //interrupt on pin 2 or 3
volatile int interruptSwitch = 0;

unsigned long countInterval = 250; //max time between knocks
unsigned long startTime;
unsigned long endTime;

// interrupt function
void Interrupt ()
{
  interruptSwitch = 1;
  detachInterrupt (knockPin);
}
void setup() {
  pinMode(knockPin, INPUT);
  Serial.begin (9600);
  attachInterrupt (digitalPinToInterrupt (knockPin), Interrupt, RISING);
}

void loop() {
  vel = analogRead(A0);
if(vel>90) {
  pinMode(knockPin, INPUT);
  val = digitalRead (knockPin);
  if (interruptSwitch == 1) {
    delay (200);
    startTime = millis ();
    endTime = millis ();
    while (endTime - countInterval < startTime) {
      val = digitalRead (knockPin);
      endTime = millis();
      if (val == HIGH) {
        Serial.println("Double");
      }
      }
       Serial.println("Pressed");
       interruptSwitch = 0;
     }
  }
}

 

Green
Offline
Зарегистрирован: 01.10.2015

b707 пишет:

не имейте привычки так писать условия.

if (button1S && millis() - button1_timer > debounce) {

Во-первых, нечитабельно, во-вторых, с такой привычкой вы рано или поздно не угадаете с приоритетом операций и получится совсем не то, что задумано.

Расставляйте скобки, не жалейти их, они бесплатны:

if (button1S && ( millis() - button1_timer > debounce)) {


Ну ОЧЕНЬ категорично. Тогда может сразу по две скобки, для надёжности? Как монашка на огурец.)

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

Green пишет:

Ну ОЧЕНЬ категорично. Тогда может сразу по две скобки, для надёжности? Как монашка на огурец.)

А я за.  Я предпочитаю явно расставлять приоритет скобками, а не выискивать его по затертой бумашке, водя пальцем по всем 15-ти уровням и матерно шевеля губами.  Да и, тенболее, с этим вашим лживым С++ никогда нельзя сказать точно, какую сегодня с утра несёт семантику оператор присваивания (да и любой другой). 

Green
Offline
Зарегистрирован: 01.10.2015

Деление с умножением тоже скобками выделяем? Только не нужно своим методам учить других выдавая за истину. Ибо сразу возникает вопрос, на кой хрен вообще эти приоритеты? Выделяем скобочками и ни о чём не думаем.)

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

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

Jeka_M
Jeka_M аватар
Offline
Зарегистрирован: 06.07.2014

Green, ИМХО большинство новичков не знают приоритетов операций. Поэтому тоже придерживаюсь мнения, что лучше приучать новичков расставлять скобки. Хуже от этого точно не будет.

leks
Offline
Зарегистрирован: 22.10.2017

Jeka_M пишет:

Green, ИМХО большинство новичков не знают приоритетов операций. Поэтому тоже придерживаюсь мнения, что лучше приучать новичков расставлять скобки. Хуже от этого точно не будет.

Да, и математика не всегда поможет... Скажи мне несколько лет назад, что если прямая процедура выглядит так : N=x+k1*y+k1*k1*z , тогда обратная так: z=N/k1*k1; y=(N-k1*k1*z)/k1;x=N-k1*k1*z-k1*y - усомнился бы.

vosara
vosara аватар
Offline
Зарегистрирован: 08.02.2014

feel feel пишет:

Добрый всем день! Не могу понять, что я делаю не так. 
Задача: если нажали 1 раз на кнопку, и если через 250мс не нажали еще раз, то считать как "pressed" 
             если нажали 1 раз на кнопку и через 250мс нажали еще раз, то считать как "double" 

Получается только получить pressed, а вот с double никак не могу разобраться.

Попробуйте такой код. Здесь можно фиксировать 1-10 и более нажатий. Без антидребезга - если подойдет помогу

//Додаем при каждом нажатии

#define butoon 12
int regim = 0;
bool flag = 1; // флаг, нажато - не нажато
bool f_time = 0;
uint8_t knopka = 0;
uint32_t time = millis();

void setup() {
  pinMode(butoon, INPUT_PULLUP);
  Serial.begin(9600);
}

void loop() {
  //******  Меняем regim 
  if (digitalRead(butoon) != flag) //если кнопка 0 а flag 1 то ...
  {
    flag = !flag;
    time = millis();
    f_time = 1;
    if (!flag)regim++;
    if (regim > 2)regim = 2;//переключать режимы будем циклично
  }
  if(f_time == 1 && millis() - time >= 250)
  {
    f_time = 0;
    knopka = regim;
    regim = 0;
    Serial.println(knopka); 
  }
}

 

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

Jeka_M пишет:

Green, ИМХО большинство новичков не знают приоритетов операций. Поэтому тоже придерживаюсь мнения, что лучше приучать новичков расставлять скобки. Хуже от этого точно не будет.

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

b707
Offline
Зарегистрирован: 26.05.2017

Green пишет:

Ну ОЧЕНЬ категорично.

Про категоричность формы - согласен. Есть за мной такой грех.

А вот по содержанию остаюсь при том же мнении - скобки более читабельны и страхуют от ошибок.

feel feel
Offline
Зарегистрирован: 20.05.2019

Спасибо большое за код! Он прям идеально подошел. Но у меня, как у начинащего, появились вопросы на счет логики. Почему условия начали выполняться. Ведь первый if не может вначале выполниться, так как вначале значение flag и  button = 1, и второй if тоже из-за начального значения f_time = 0

vosara
vosara аватар
Offline
Зарегистрирован: 08.02.2014

Первый иф сработает - и при нажатии и при отпускании тоесть при любом изменении состояния кнопки, после этого флаг примет значение кнопки и сюда мы больше заходить не будем до следующего изменеия состояния кнопки, кстати здесь мняем f_time = 1 и уже можем заходить во второй if