Опять про кнопки. Обработка нажатия
- Войдите на сайт для отправки комментариев
Ардуино увидел впервые 4 дня назад. Об уровне познаний в программировании судите сами :))
Вводная часть:
Pin3 - вход, получаем сигнал с датчика скорости авто. Pin7 - вход, кнопка. Pin9 - выход, реле. Необходимо запомнить 3 значения скорости: speedUp (скорость растет до заданного значения), speedDown (скорость падает до заданного значения), speedLimit (не равно speedUp, скорость растет до заданного значения).
Алгоритм работы кнопки следующий:
1. Одно короткое нажатие ( до 0,5 сек) - вкл и выкл реле;
2. 2 коротких нажатия (по 0,5 сек) в течение 1 сек - сменить режим speedUp/speedDown/speedLimit;
3. 1 длинное нажатие (более 0,5 сек) - присвоить текущее значение скорости выбранному режиму.
Основную часть накопипастил, несколько строк сам написал - на данный момент имею вот такой код:
/* created Tomasina, forum.amperka.ru created Frud, drive2.ru modified funakoshi 8 April 2015 */ #define BUTTON_PIN 7 #define BUZZER_PIN 4 #define RELAY_PIN 9 int bounceTime = 10; // задержка для подавления дребезга int holdTime = 500; // время, в течение которого нажатие можно считать удержанием кнопки int doubleTime = 1000; // время, в течение которого нажатия можно считать двойным int frequency = 3500; //частота звука "пищалки" int speedMode = 0; //просто чтобы не ругался компилятор boolean lastReading = false; // флаг предыдущего состояния кнопки boolean buttonSingle = false; // флаг состояния "краткое нажатие" boolean buttonDouble = false; // флаг состояния "двойное нажатие" boolean buttonHold = false; // флаг состояния "долгое нажатие" boolean dispState = false; //флаг "включенности" дисплея парктроника long onTime = 0; // переменная обработки временного интервала long lastSwitchTime = 0; // переменная времени предыдущего переключения состояния volatile unsigned long micros_sp = 0; volatile byte sz = 0; //счетчик обнуления volatile unsigned int sp = 0; //скорость volatile unsigned int speedUp = 0; //набор скорости volatile unsigned int speedDown = 0; //снижение скорости volatile unsigned int speedLimit = 0; //предел превышения скорости volatile boolean st = false; void setup() { pinMode(BUTTON_PIN, INPUT); // INPUT_PULLUP подключит кнопку через внутренний резистор attachInterrupt(1, speedometr, RISING); } void loop() { if (sz != 0) { sz--; } else { sp = 0; }; // ================ обработчик состояния кнопки ==================== boolean reading = digitalRead(BUTTON_PIN); /* читаем состояние пина кнопки. Если подключен через внутренний резистор (см. pinMode(BUTTON_PIN, INPUT_PULLUP)), перед digitalRead(BUTTON_PIN) нужен !. */ // проверка первичного нажатия if (reading && !lastReading) { onTime = millis(); } // проверка удержания if (reading && lastReading) { if ((millis() - onTime) > holdTime) { buttonHold = true; } } // проверка отпускания кнопки if (!reading && lastReading) { if (((millis() - onTime) > bounceTime) && !buttonHold) { if ((millis() - lastSwitchTime) >= doubleTime) { lastSwitchTime = millis(); buttonSingle = true; } else { lastSwitchTime = millis(); buttonDouble = true; buttonSingle = false; isButtonDouble(); buttonDouble = false; // сброс состояния после выполнения команды } } if (buttonHold) { buttonDouble = false; isButtonHold(speedMode); buttonHold = false; // сброс состояния после выполнения команды } } lastReading = reading; if (buttonSingle && (millis() - lastSwitchTime) > doubleTime) { buttonDouble = false; isButtonSingle(); buttonSingle = false; // сброс состояния после выполнения команды } // ================ конец обработчика состояния кнопки ================== } // конец loop void isButtonSingle() // действия после одиночного нажатия кнопки { //При однократном "коротком" нажатии кнопки реле замкнётся на 0,5 сек. digitalWrite(RELAY_PIN, HIGH); delay(500); digitalWrite(RELAY_PIN, LOW); } int isButtonDouble() // действия после двойного нажатия кнопки { //Выбрать активный режим (всего 3 режима: speedUp, speedDown, speedLimit) //Просигнализировать о выбранном режиме n-ым количеством бипов (n зависит от активного режима) int regim = 1; regim++; if (regim > 3) { regim = 1; } if (regim == 1) //speedUp { tone(BUZZER_PIN, frequency, 50); speedMode = 1; return speedMode; } if (regim == 2) //speedDown { tone(BUZZER_PIN, frequency, 50); speedMode = 2; return speedMode; } if (regim == 3) //speedLimit { tone(BUZZER_PIN, frequency, 50); speedMode = 3; return speedMode; } } int isButtonHold(int x) // действия после удержания кнопки { //Запомнить значание активному режиму. Об запоминании сигнализировать звуком switch (x) { case 1: //speedUp speedUp = sp; tone(BUZZER_PIN, frequency, 150); return speedUp; break; case 2: //speedDown speedDown = sp; tone(BUZZER_PIN, frequency, 150); return speedDown; break; case 3: //speedLimit speedLimit = sp; tone(BUZZER_PIN, frequency, 150); return speedLimit; break; } } void speedometr() { //измеряем частоту на входе спидометра по прерыванию if (!st) { micros_sp = micros(); } else { sp = (1600000 / (micros() - micros_sp)); } st = !st; sz = 30; }
Помогите пожалуйста с наполнением функций isButtonHold и isButtonDouble. Особенно с последней.
Посмотрите готовые библиотеки для работы с кнопками ClickButton OneButton Button X-Dron
С кнопками там более-менее нормально, вызова функций int isButtonHold(int x), void isButtonSingle(), int isButtonDouble() работают более менее корректно, проверял. (хотя я бы написал по другомую, не нравится мне, что Hold вызывается по отпусканию клнопки, а не по тому, когда интервал истек. Соответственно, с использованием своей библиотеки). Эта часть кода написана Tomasina.
Топикстартера интересует именно наполнение функций.
regim в int isButtonDouble() должен быть либо глобальной переменной либо static (лучше глобальной).
Зацикленная смена режима без if() -
regim = (regim++)%3;
Дальше тоже лучше без if(), на switch (regim) case.
Спасибо за подсказку. Тут собственно моего кода - наполнение функций isButtonHold, isButtonSingle, isButtonDouble. Остальное написано знатоками :)
Так правильно?
И можно поподробнее про (regim++)%3? Справку прочитал и не понял почему
x = 4%5 // x имеет значение 4
А зачем возвращать функции значение глобальной переменной speedMode?
Ну, чтобы использовать speedMode как входящий параметр для isButtonHold. Или это лишнее для ГЛОБАЛЬНОЙ переменной?
лишнее.
Я немного наврал с (regim++)%3; ++ надо ставить до переменной, тогда работает. А с учетом, что режимы у Вас начинаются с 1 и до 3, а воздействовать надо на глобальную переменную, то вся функция isButtonDouble() вырождается в
delay мне, конечно, не нравится, он стопорит на время всю программу ради "аудиозации", но чтобы от него избавиться нужно менять подход к вызову функций.
Ничего себе оптимизация кода :)) Спасибо.