Опять про кнопки. Обработка нажатия
- Войдите на сайт для отправки комментариев
Ардуино увидел впервые 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. Остальное написано знатоками :)
Так правильно?
int regim = 1; int isButtonDouble() // действия после двойного нажатия кнопки { //Выбрать активный режим (всего 3 режима: speedUp, speedDown, speedLimit) //Просигнализировать о выбранном режиме n-ым количеством бипов (n зависит от активного режима) regim = (regim++) % 3; //зацикленная смена режима без использования if switch (regim) { case 1: // speedUp tone(BUZZER_PIN, frequency, 50); speedMode = 1; return speedMode; break; case 2: //speedDown tone(BUZZER_PIN, frequency, 50); speedMode = 2; return speedMode; break; case 3: //speedLimit tone(BUZZER_PIN, frequency, 50); speedMode = 3; return speedMode; break; } }И можно поподробнее про (regim++)%3? Справку прочитал и не понял почему
x = 4%5 // x имеет значение 4
А зачем возвращать функции значение глобальной переменной speedMode?
Ну, чтобы использовать speedMode как входящий параметр для isButtonHold. Или это лишнее для ГЛОБАЛЬНОЙ переменной?
лишнее.
Я немного наврал с (regim++)%3; ++ надо ставить до переменной, тогда работает. А с учетом, что режимы у Вас начинаются с 1 и до 3, а воздействовать надо на глобальную переменную, то вся функция isButtonDouble() вырождается в
void isButtonDouble() // действия после двойного нажатия кнопки { //Выбрать активный режим (всего 3 режима: speedUp, speedDown, speedLimit) //Просигнализировать о выбранном режиме n-ым количеством бипов (n зависит от активного режима) speedMode = (++speedMode) % 4; if (speedMode == 0) speedMode=1; for (int i= 0; i<speedMode; i++){ tone(BUZZER_PIN, frequency, 50); delay(200); } }delay мне, конечно, не нравится, он стопорит на время всю программу ради "аудиозации", но чтобы от него избавиться нужно менять подход к вызову функций.
Ничего себе оптимизация кода :)) Спасибо.