Длинное и короткое нажатие на Keypad.
- Войдите на сайт для отправки комментариев
Всем привет. Есть програмка, которая в зависимости от того какая клавиша нажата на клавиатуре - запускает разные фунции. что-то вроде такого. Заголовок, сетап-часть и прочее - опускаю за ненадобностью. Импортится Keypad.h модуль. Клава заведена столбцы - на 5-6-7 сам столбец подключен на 8 ногу. Т.е. для выполнения кейса 'a' - нужно чтобы соеденились 5 и 8 ноги, для 'b' - 6 и 8 и тп....
void loop()
{
char key = kpd.getKey();
if(key) // Check for a valid key.
{
switch (key)
{
case 'a':
digitalWrite(13, !digitalRead(13)); //Инвертировать выход
break; //прекратить выполнение программы.
}
{
case 'b':
digitalWrite(14, !digitalRead(14)); //Инвертировать выход
break; //прекратить выполнение программы.
}
{
case 'c':
digitalWrite(15, !digitalRead(15)); //Инвертировать выход
break; //прекратить выполнение программы.
}
}
}
Воспрос - как мне заставить чтобы на длинное нажатие клавиши запускалась другая функция? т.е. чтобы при коротком соединении 5 и 8 ноги (case 'a') - я запускал одну функцию (включение/выключение ноги), а если выводы соеденены долго - то чтобы запускалась другая функция (запись в епром или еще что...)?
UPDATE:
был предложен вариант:
void loop()
{
char key = kpd.getKey();
static char savekey = 0;
if(key)
{
static uint32_t startmillis = 0;
if(!startmillis)
{
startmillis = millis();
savekey = key;
}
else if(millis()-startmillis > 500)
{
startmillis = 0;
switch (key)
{
case 'a':
... // Делаем, то что надо
break; //прекратить выполнение программы.
case 'b':
... // Делаем, то что надо
break; //прекратить выполнение программы.
case 'c':
... // Делаем, то что надо
break; //прекратить выполнение программы.
}
}
key = 0;
}
else if(startmillis)
{
key = savekey;
startmillis = 0;
}
if(key) // Check for a valid key.
{
switch (key)
{
case 'a':
digitalWrite(13, !digitalRead(13)); //Инвертировать выход
break; //прекратить выполнение программы.
case 'b':
digitalWrite(14, !digitalRead(14)); //Инвертировать выход
break; //прекратить выполнение программы.
case 'c':
digitalWrite(15, !digitalRead(15)); //Инвертировать выход
break; //прекратить выполнение программы.
}
}
}
но он не заработал. Конкретно в таком виде компилятор ругался на 46 строку, а когда я вынес переменную глобально - смог прошить ардуинку. Но - на динное нажатие никакой реакции, на короткое - нужно было "попасть в цикл" - т.е. то реагировал на нажатие кнопки соединяющую 5 и 8 ноги - диод на 13 выводе включался-выключался произвольно, а если часто и быстро нажимать кнопку - можно было добится циклического мигания светодиода с равными интервалами...
Пока застопорился с дальнейшими идеями. Кто-то может что-то подсказать?
если кнопка нажата
{
фиксируем время1;
пока кнопка нажата ждем;
фиксируем время2;
вычисляем время зажатия = верямя2-время1.
}
в зависимости от времени зажатия выполняем команды
ну вот вроде выше так и сделано, но не работает. можно чуть в более ардуино-синтаксическом виде? )
Примерно так, но для аналоговой клавиатуры, другой нет. Переменные и условия для своих клавиш переделайте. Срабатывает по отпусканию кнопки. Дребезгом не занимался.
#include <LiquidCrystal.h> LiquidCrystal lcd(8, 9, 4, 5, 6, 7); unsigned long startmillis; byte KEY; byte savekey; void setup() { lcd.begin(16,2); lcd.clear(); } byte key() { int val = analogRead(0); if (val < 50) return 5; else if (val < 150) return 3; else if (val < 350) return 4; else if (val < 500) return 2; else if (val < 800) return 1; else return 0; } void klav1() { switch (KEY) { case 1: lcd.setCursor(0,0); lcd.print("1 dlin"); break; case 2: lcd.setCursor(0,0); lcd.print("2 dlin"); break; case 3: lcd.setCursor(0,0); lcd.print("3 dlin"); break; case 4: lcd.setCursor(0,0); lcd.print("4 dlin"); break; case 5: lcd.setCursor(0,0); lcd.print("5 dlin"); break; } } void klav2() { switch (KEY) { case 1: lcd.setCursor(0,0); lcd.print("1 kor"); break; case 2: lcd.setCursor(0,0); lcd.print("2 kor"); break; case 3: lcd.setCursor(0,0); lcd.print("3 kor"); break; case 4: lcd.setCursor(0,0); lcd.print("4 kor"); break; case 5: lcd.setCursor(0,0); lcd.print("5 kor"); break; } } void loop() { KEY=key(); if (savekey!=KEY && KEY!=0) {savekey=KEY; startmillis=millis();} if (KEY==0 && savekey!=0) { if (millis()-startmillis>1000) { KEY=savekey; savekey=0; klav1(); } else { KEY=savekey; savekey=0; klav2(); } } }#include <LiquidCrystal.h> LiquidCrystal lcd(8, 9, 4, 5, 6, 7); unsigned long startmillis; char KEY; char savekey; void setup() { lcd.begin(16,2); lcd.clear(); } char key() { int val = analogRead(0); if (val < 50) return 'e'; else if (val < 150) return 'c'; else if (val < 350) return 'd'; else if (val < 500) return 'b'; else if (val < 800) return 'a'; else return ' '; } void klav1() { switch (KEY) { case 'a': lcd.setCursor(0,0); lcd.print("1 dlin"); break; case 'b': lcd.setCursor(0,0); lcd.print("2 dlin"); break; case 'c': lcd.setCursor(0,0); lcd.print("3 dlin"); break; case 'd': lcd.setCursor(0,0); lcd.print("4 dlin"); break; case 'e': lcd.setCursor(0,0); lcd.print("5 dlin"); break; } } void klav2() { switch (KEY) { case 'a': lcd.setCursor(0,0); lcd.print("1 kor"); break; case 'b': lcd.setCursor(0,0); lcd.print("2 kor"); break; case 'c': lcd.setCursor(0,0); lcd.print("3 kor"); break; case 'd': lcd.setCursor(0,0); lcd.print("4 kor"); break; case 'e': lcd.setCursor(0,0); lcd.print("5 kor"); break; } } void loop() { KEY=key(); if (savekey!=KEY && KEY!=' ') {savekey=KEY; startmillis=millis();} if (KEY==' ' && savekey!=' ') { if (millis()-startmillis>1000) { KEY=savekey; savekey=' '; klav1(); } else { KEY=savekey; savekey=' '; klav2(); } } }Вот так под ваши текстовые, только не знаю, что ваша функция возвращает, если не нажата ни одна клавиша. У себя в условие вбил пробел. У вас надо смотреть.
Так, если я правильно понимаю - то у вас получается что под разную длинну нажатий выводятся разные "клавиши".
Keypad работает чуток иначе - каждая клавиша - это соединение двух каких-то ног. например case 'a' - это соединение 5 и 8 ноги, case 'b' - 6 и 8 и тд.
Давайте для простоты попробуем в шапке все обозначить.
#include <Keypad.h> static char savekey = 0; static uint32_t startmillis = 0; const byte rows = 1; const byte cols = 1; char keys[rows][cols] = { {'a'}, }; byte rowPins[rows] = {5}; byte colPins[cols] = {8}; Keypad kpd = Keypad(makeKeymap(keys), rowPins, colPins, rows, cols); void setup() { pinMode(13, OUTPUT); pinMode(14, OUTPUT); }Т.е. сведем все до 1 кнопки/кейса.
Попробовал написать скетч, пользуясь вашим примером -
#include <Keypad.h> unsigned long startmillis; char KEY; char savekey; const byte rows = 1; const byte cols = 1; char keys[rows][cols] = { {'a'}, }; byte rowPins[rows] = {5}; byte colPins[cols] = {8}; Keypad kpd = Keypad(makeKeymap(keys), rowPins, colPins, rows, cols); void setup() { pinMode(13, OUTPUT); pinMode(14, OUTPUT); } void klav1() { switch (KEY) { case 'a': digitalWrite(14, !digitalRead(14)); // Делаем, то что надо break; //прекратить выполнение программы. } } void klav2() { switch (KEY) { case 'a': digitalWrite(13, !digitalRead(13)); // Делаем, то что надо break; //прекратить выполнение программы. } } void loop() { char key = kpd.getKey(); KEY=key; if(KEY){startmillis=millis();} // Check for a valid key. { if (millis()-startmillis>1000) { klav1(); } else { klav2(); } } }Работают только короткие нажатия. Длинне никак не реагируют.
Конкретно в таком виде компилятор ругался на 46 строку
{ case 'a': ... // Делаем, то что надо break; //прекратить выполнение программы. case 'b': ... // Делаем, то что надоВ 46 строке компилятору не на что ругается.
он не заработал
void loop() { char key = kpd.getKey(); static char savekey = 0; static uint32_t startmillis = 0; if(key) { if(!startmillis) { startmillis = millis(); savekey = key; } else if(millis()-startmillis > 500) { startmillis = 0; switch (key) { case 'a': ... // Делаем, то что надо break; //прекратить выполнение программы. case 'b': ... // Делаем, то что надо break; //прекратить выполнение программы. case 'c': ... // Делаем, то что надо break; //прекратить выполнение программы. } } key = 0; } else if(startmillis) { key = savekey; startmillis = 0; } if(key) // Check for a valid key. { switch (key) { case 'a': digitalWrite(13, !digitalRead(13)); //Инвертировать выход break; //прекратить выполнение программы. case 'b': digitalWrite(14, !digitalRead(14)); //Инвертировать выход break; //прекратить выполнение программы. case 'c': digitalWrite(15, !digitalRead(15)); //Инвертировать выход break; //прекратить выполнение программы. } } }Ну а если и сейчас не заработает длительное нажатие, то это означает, что с данной библиотекой в текущем варианте это невозможно.
С библиотекой Keypad.h должно работать так:
void loop() { char key = kpd.getKey(); static char savekey = 0; static uint32_t startmillis = 0; if(kpd.getState() == PRESSED) { if(!startmillis) { startmillis = millis(); savekey = key; } else if(millis()-startmillis > 500) { startmillis = 0; switch (savekey) { case 'a': ... // Делаем, то что надо break; //прекратить выполнение программы. case 'b': ... // Делаем, то что надо break; //прекратить выполнение программы. case 'c': ... // Делаем, то что надо break; //прекратить выполнение программы. } } key = 0; } else if(kpd.getState() == HOLD && startmillis) { key = savekey; startmillis = 0; } if(key) // Check for a valid key. { switch (key) { case 'a': digitalWrite(13, !digitalRead(13)); //Инвертировать выход break; //прекратить выполнение программы. case 'b': digitalWrite(14, !digitalRead(14)); //Инвертировать выход break; //прекратить выполнение программы. case 'c': digitalWrite(15, !digitalRead(15)); //Инвертировать выход break; //прекратить выполнение программы. } } }И замените в 33 строке RELEASED на HOLD, иначе нажатия будут срабатывать только через полсекунды.
Огромное спасибо!!! да, так работает. Извиняюсь за некоторую путанницу с кодами и прочим - я достаточно начинающий, поэтому бывают явные "глупости".
Так, если я правильно понимаю - то у вас получается что под разную длинну нажатий выводятся разные "клавиши".
Keypad работает чуток иначе - каждая клавиша - это соединение двух каких-то ног. например case 'a' - это соединение 5 и 8 ноги, case 'b' - 6 и 8 и тд.
Давайте для простоты попробуем в шапке все обозначить.
#include <Keypad.h> static char savekey = 0; static uint32_t startmillis = 0; const byte rows = 1; const byte cols = 1; char keys[rows][cols] = { {'a'}, }; byte rowPins[rows] = {5}; byte colPins[cols] = {8}; Keypad kpd = Keypad(makeKeymap(keys), rowPins, colPins, rows, cols); void setup() { pinMode(13, OUTPUT); pinMode(14, OUTPUT); }Т.е. сведем все до 1 кнопки/кейса.
Попробовал написать скетч, пользуясь вашим примером -
#include <Keypad.h> unsigned long startmillis; char KEY; char savekey; const byte rows = 1; const byte cols = 1; char keys[rows][cols] = { {'a'}, }; byte rowPins[rows] = {5}; byte colPins[cols] = {8}; Keypad kpd = Keypad(makeKeymap(keys), rowPins, colPins, rows, cols); void setup() { pinMode(13, OUTPUT); pinMode(14, OUTPUT); } void klav1() { switch (KEY) { case 'a': digitalWrite(14, !digitalRead(14)); // Делаем, то что надо break; //прекратить выполнение программы. } } void klav2() { switch (KEY) { case 'a': digitalWrite(13, !digitalRead(13)); // Делаем, то что надо break; //прекратить выполнение программы. } } void loop() { char key = kpd.getKey(); KEY=key; if(KEY){startmillis=millis();} // Check for a valid key. { if (millis()-startmillis>1000) { klav1(); } else { klav2(); } } }Работают только короткие нажатия. Длинне никак не реагируют.
Они у вас и не будут реагировать. Вы убрали защелку нажата-ненажата. Дальше логика уже не работает. Для корректной работы вам надо определить, что возвращает функция при ненажатой клавише. Пришел код - нет нажатых клавиш, начали отрабатывать условия. Возможно с этой библиотекой так и не выйдет.
Не, работает с Released. C HOLD - работает не корректно - длинные нажатия не отрабатывают, короткие отрабатывают через раз.
Всем спасибо. Финальный код выглядит так:
#include <Keypad.h> const byte rows = 1; const byte cols = 1; char keys[rows][cols] = { {'a'}, }; byte rowPins[rows] = {5}; byte colPins[cols] = {8}; Keypad kpd = Keypad(makeKeymap(keys), rowPins, colPins, rows, cols); void setup() { pinMode(13, OUTPUT); pinMode(14, OUTPUT); } void loop() { char key = kpd.getKey(); static char savekey = 0; static uint32_t startmillis = 0; if(kpd.getState() == PRESSED) { if(!startmillis) { startmillis = millis(); savekey = key; } else if(millis()-startmillis > 500) { startmillis = 0; switch (savekey) { case 'a': digitalWrite(14, !digitalRead(14)); break; //прекратить выполнение программы. } } key = 0; } else if(kpd.getState() == RELEASED && startmillis) { key = savekey; startmillis = 0; } if(key) // Check for a valid key. { switch (key) { case 'a': digitalWrite(13, !digitalRead(13)); //Инвертировать выход break; //прекратить выполнение программы. } } }Все работает как надо.
Так работает или не работает с RELEASED ?
Работает имено с RELEASED. C HOLD - не работает.
Ну и более оптимально будет так
void loop() { char key = kpd.getKey(); static char savekey = 0; static uint32_t startmillis = 0; if(kpd.getState() == PRESSED) { if(!startmillis) { startmillis = millis(); savekey = key; } else if(millis()-startmillis > 500) { startmillis = 0; Long(savekey); } } //else if(kpd.getState() == HOLD && startmillis) // или с HOLD else if(kpd.getState() == RELEASED && startmillis) // или с RELEASED { startmillis = 0; Shot(savekey); } } void Shot(char _key) { switch (_key) { case 'a': digitalWrite(13, !digitalRead(13)); //Инвертировать выход break; //прекратить выполнение программы. case 'b': digitalWrite(14, !digitalRead(14)); //Инвертировать выход break; //прекратить выполнение программы. case 'c': digitalWrite(15, !digitalRead(15)); //Инвертировать выход break; //прекратить выполнение программы. } } void Long(char _key) { switch (_key) { case 'a': ... // Делаем, то что надо break; //прекратить выполнение программы. case 'b': ... // Делаем, то что надо break; //прекратить выполнение программы. case 'c': ... // Делаем, то что надо break; //прекратить выполнение программы. } }Кстати, а почему я не могу тут
elseif(millis()-startmillis > 500)указать больше чем 500? например если мне задержка нужна в 2500-3000? Если пробую указать даже 600 - то ничего не происходит по долгому нажатию.Причем меньше чем 500 - установить могу, отрабатывает корректно. больше - просто перестают работать "долгие" нажатия.
Потому что setHoldTime по-умолчанию 500 после этого state меняется на hold а Вы ловите Pressed и Released.
В чём вообще прикол, используя библиотеку самому считать время, когда это уже реализовано в библиотеке?
Слушайте, а в чем фишка этой библиотеки? Может она и мне нужна?
Точно. Прописал в setup части - kbp.setHoldTime = 2500; и стало считать большие значения.
Я бы с радостью использовал все, что есть в библиотеке - но знаний пока не хватает.
Она по сути кейпад делает.
А 8 пинов на 16 клавиш, это не слишком щедро? Есть ведь варианты на 1 или 2
http://arduino.ru/forum/programmirovanie/rabota-s-knopkami-v-pomoshch-novichku?page=4#comment-86325
http://arduino.ru/forum/programmirovanie/podklyuchenie-matrichnoi-klaviatury-po-i2c
Сам правда не проверял, мне больше трех пока было не надо.
Потому что setHoldTime по-умолчанию 500 после этого state меняется на hold а Вы ловите Pressed и Released.
В чём вообще прикол, используя библиотеку самому считать время, когда это уже реализовано в библиотеке?
Все верно, просто нужно внимательнее читать описание библиотек.
void loop() { char key = kpd.getKey(); if(key && kpd.getState() == PRESSED) { switch (key) { case 'a': digitalWrite(13, !digitalRead(13)); //Инвертировать выход break; //прекратить выполнение программы. case 'b': digitalWrite(14, !digitalRead(14)); //Инвертировать выход break; //прекратить выполнение программы. case 'c': digitalWrite(15, !digitalRead(15)); //Инвертировать выход break; //прекратить выполнение программы. } } if(key && kpd.getState() == HOLD) { switch (key) { case 'a': ... // Делаем, то что надо break; //прекратить выполнение программы. case 'b': ... // Делаем, то что надо break; //прекратить выполнение программы. case 'c': ... // Делаем, то что надо break; //прекратить выполнение программы. } } }Как-то у меня последний пример не заработал. короткие нажатия работают нормально, длинные нет. Может я что-то в сетап-части упустил?
Так. поскольку чуток в голове уже инфы появилось, перечитал еще раз документацию к библиотеке, и посмотрел в очередной раз примеры. И оказалось, что пример "EventKeypad" очень похож на то, что мне нужно (наконец-то я это смог увидеть).
void setup() { pinMode(13, OUTPUT); pinMode(14, OUTPUT); pinMode(15, OUTPUT); kpd.setHoldTime(1000); kpd.addEventListener(keypadEvent); } void loop() { char key = kpd.getKey(); } void keypadEvent(KeypadEvent key){ switch (kpd.getState()){ case PRESSED: // a to e = select wich relay is HIGH/LOW if (key == 'a') { digitalWrite(13, !digitalRead(13)); //Инвертировать выход //прекратить выполнение программы. } if (key == 'b') { digitalWrite(14, !digitalRead(14)); //Инвертировать выход //прекратить выполнение программы. } if (key == 'c) { digitalWrite(15, !digitalRead(15)); //Инвертировать выход //прекратить выполнение программы. } break; case HOLD: if (key == 'a'){ ... // Делаем, то что надо } if (key == 'b'){ ... // Делаем, то что надо } if (key == 'c'){ ... // Делаем, то что надо } break; } }Работает.