Двойное нажатие
- Войдите на сайт для отправки комментариев
Пнд, 20/05/2019 - 23:07
Добрый всем день! Не могу понять, что я делаю не так.
Задача: если нажали 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;
}
}
}
Для начала:
1. что за ерунда у тебя в строках 19 и 20?
2. как подключена кнопка? что должна дать функция digitalRead при нажатии и отпускании?
1. Вместо кнопки у меня пьезодатчик, использую как кнопку
2. Кнопка подключена в А0, функция digitalRead должна дать значение, если на нее идет напряжение, то 1, если нет, то 0
1. Вместо кнопки у меня пьезодатчик, использую как кнопку
2. Кнопка подключена в А0, функция digitalRead должна дать значение, если на нее идет напряжение, то 1, если нет, то 0
Вы уж определитесь - читаете эту кнопку как аналоговую или логическую.
В строках 37 и 39 надо скобки расставить, а то полный бред получатся.
На логику работы не смотрел.
Так он читает он сначала читается, как аналоговый, а потом как цифровой.
А что неправильно? В 37 и 39 перепроверил, везде скобки закрыты и тела внутри расставлены
37 и 39 перепроверил, везде скобки закрыты и тела внутри расставлены
не имейте привычки так писать условия.
if (button1S && millis() - button1_timer > debounce) {Во-первых, нечитабельно, во-вторых, с такой привычкой вы рано или поздно не угадаете с приоритетом операций и получится совсем не то, что задумано.
Расставляйте скобки, не жалейти их, они бесплатны:
if (button1S && ( millis() - button1_timer > debounce)) {Спасибо большое! Буду теперь иметь ввиду
Поставил скобки, но это ничего не дало. Все осталось по прежнему
Кстати пробовал разные варианты и заметил, что если заменить "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; } } }Так он читает он сначала читается, как аналоговый, а потом как цифровой.
Объясните, пожалуйста, в чем глубокий смысл таких действий?
#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); }Для того чтобы установить срабатывания функции, начиная от 90 и выше.
Дело в том, что пьезодатчик очень чувствителен, и, выставляя порог, я избавлюсь от случайной вибрации, которая включит дальнейшую функцию. А перевод в цифру просто для удобства, так как в дальнейшем не имеет значение, какой сигнал будет на пине
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); } }Спасибо большое за код! Но DoublePressed у меня выводит только если кнопка была зажата после Pressed. Мне важно, чтобы она за 250мс была нажата 2 раза и ардуино давала мне только значение DoublePressed , нежели 2 раза Pressed
Спасибо за код! Попробовал сделать вывод в 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; } } }не имейте привычки так писать условия.
if (button1S && millis() - button1_timer > debounce) {Во-первых, нечитабельно, во-вторых, с такой привычкой вы рано или поздно не угадаете с приоритетом операций и получится совсем не то, что задумано.
Расставляйте скобки, не жалейти их, они бесплатны:
if (button1S && ( millis() - button1_timer > debounce)) {Ну ОЧЕНЬ категорично. Тогда может сразу по две скобки, для надёжности? Как монашка на огурец.)
Ну ОЧЕНЬ категорично. Тогда может сразу по две скобки, для надёжности? Как монашка на огурец.)
А я за. Я предпочитаю явно расставлять приоритет скобками, а не выискивать его по затертой бумашке, водя пальцем по всем 15-ти уровням и матерно шевеля губами. Да и, тенболее, с этим вашим лживым С++ никогда нельзя сказать точно, какую сегодня с утра несёт семантику оператор присваивания (да и любой другой).
Деление с умножением тоже скобками выделяем? Только не нужно своим методам учить других выдавая за истину. Ибо сразу возникает вопрос, на кой хрен вообще эти приоритеты? Выделяем скобочками и ни о чём не думаем.)
Я, к щастью, никаво и не учу, ибо не способен. Я просто говорю, как делаю я. И всё. Кто-то разделяет взгляды старого олкаголека, кто-то твои, важен любой плюрализьм мнений.
Green, ИМХО большинство новичков не знают приоритетов операций. Поэтому тоже придерживаюсь мнения, что лучше приучать новичков расставлять скобки. Хуже от этого точно не будет.
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 - усомнился бы.
Добрый всем день! Не могу понять, что я делаю не так.
Задача: если нажали 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); } }Green, ИМХО большинство новичков не знают приоритетов операций. Поэтому тоже придерживаюсь мнения, что лучше приучать новичков расставлять скобки. Хуже от этого точно не будет.
Ну ОЧЕНЬ категорично.
Про категоричность формы - согласен. Есть за мной такой грех.
А вот по содержанию остаюсь при том же мнении - скобки более читабельны и страхуют от ошибок.
Спасибо большое за код! Он прям идеально подошел. Но у меня, как у начинащего, появились вопросы на счет логики. Почему условия начали выполняться. Ведь первый if не может вначале выполниться, так как вначале значение flag и button = 1, и второй if тоже из-за начального значения f_time = 0
Первый иф сработает - и при нажатии и при отпускании тоесть при любом изменении состояния кнопки, после этого флаг примет значение кнопки и сюда мы больше заходить не будем до следующего изменеия состояния кнопки, кстати здесь мняем f_time = 1 и уже можем заходить во второй if