Arduino: Короткое нажатие и длинное нажатие
Использование коротких и длинных нажатий вместе добавляет универсальности и даёт дополнительную функциональность одной кнопке. Вы больше не ограничены состояниями «нажато» или «не нажато». Теперь у вас есть «нажато немного» и «нажато подольше».
Это руководство продолжает предыдущую статью о измерении времени нажатия кнопки и предполагает, что вы её прочитали. Если нет – у вас есть домашнее задание.
В этом руководстве мы рассмотрим, как определить, было ли нажатие коротким или длинным.
Схема (Пример 1)
Схема очень простая: одна кнопка, подключённая к Arduino с подтягивающим резистором 10 кОм к земле.
Пин D12 подключён к кнопке с подтягивающим резистором 10 кОм к GND
Пример 1: Определение типа нажатия
Первый пример демонстрирует довольно простой сценарий: при обнаружении короткого нажатия в Serial Monitor выводится «short press» («короткое нажатие»), а при обнаружении длинного нажатия – «long press» («длинное нажатие»).
Скетч вводит несколько ключевых переменных и состояний для отслеживания поведения кнопки. Он использует функции измерения времени для определения длительности нажатия кнопки и сравнивает эту длительность с заранее определённым порогом для классификации типа нажатия.
Порог настраивается: const long SHORT_KEY_PRESS_MAX_DURATION = 1000; (1000 мс = 1 секунда).
// Sketch: Arduino - Long press. Short press 001
// Determine if a key press was short or long
// www.martyncurrey.com
// Pins
// D12 to push button switch with 10K ohm pull down resistor
const int PIN_PUSH_BUTTON_SWITCH = 12;
// variables
boolean switchState = LOW;
boolean oldSwitchState = LOW;
long timer_timeStart = 0;
long timer_timeStop = 0;
byte state = 0;
const byte CLOSEDtoOPEN = 1;
const byte OPENtoCLOSED = 2;
const byte SHORT_PRESS = 3;
const byte LONG_PRESS = 4;
// the maximum a short short press is
const long SHORT_KEY_PRESS_MAX_DURATION = 1000;
byte pressType = 0;
void setup()
{
Serial.begin(9600);
Serial.print("Sketch: "); Serial.println(__FILE__);
Serial.print("Uploaded: "); Serial.println(__DATE__);
Serial.println(" ");
pinMode(PIN_PUSH_BUTTON_SWITCH, INPUT);
}
void loop()
{
state = checkSwitch();
if (state == OPENtoCLOSED) { startTimer(); }
else if (state == CLOSEDtoOPEN) { pressType = stopTimer(); }
if (pressType == SHORT_PRESS)
{
Serial.println("Short key press detected");
pressType = 0;
}
else if (pressType == LONG_PRESS)
{
Serial.println("Long key press detected");
pressType = 0;
}
} // loop
int checkSwitch()
{
byte returnVal = 0;
// simple debounce
boolean newSwitchState1 = digitalRead(PIN_PUSH_BUTTON_SWITCH); delay(1);
boolean newSwitchState2 = digitalRead(PIN_PUSH_BUTTON_SWITCH); delay(1);
boolean newSwitchState3 = digitalRead(PIN_PUSH_BUTTON_SWITCH);
if ( (newSwitchState1==newSwitchState2) && (newSwitchState1==newSwitchState3) )
{
if (newSwitchState1 != oldSwitchState)
{
// OPEN => CLOSED
if ( oldSwitchState == LOW && newSwitchState1 == HIGH )
{
returnVal = OPENtoCLOSED;
}
// CLOSED => OPEN
if ( oldSwitchState == HIGH && newSwitchState1== LOW )
{
returnVal = CLOSEDtoOPEN;
}
oldSwitchState = newSwitchState1;
}
} // if ( (newSwitchState1==newSwitchState2) && (newSwitchState1==newSwitchState3) )
return returnVal;
} // int checkSwitch()
void startTimer()
{
timer_timeStart = millis(); // start the timer
}
byte stopTimer()
{
// stop the timer. Return a flag to indicate the duration of the key press
timer_timeStop = millis();
long timePressed = timer_timeStop - timer_timeStart;
byte returnVal = 0;
if (timePressed <= SHORT_KEY_PRESS_MAX_DURATION) { returnVal = SHORT_PRESS;}
else { returnVal = LONG_PRESS;}
return returnVal;
}
Вывод в Serial Monitor
Пример 2: Управление светодиодом
Этот пример расширяет концепцию визуальной обратной связью:
Схема (Пример 2)
Кнопка на пине D12
Светодиод на пине D4 с резистором 330 Ом
Поведение
Кнопка нажата – светодиод включается сразу
Короткое нажатие отпущено – светодиод выключается
Длинное нажатие отпущено – светодиод остаётся включённым
Это демонстрирует практическое управление состоянием, где тип нажатия определяет последующее поведение.
// Sketch: Arduino - Long press. Short press 02
// Turn on an LED with a long press
// www.martyncurrey.com
// Pins
// D12 to push button switch with 10K ohm pull down resistor
// D4 LED with 330 ohm resitor to ground
const int PIN_PUSH_BUTTON_SWITCH = 12;
const int PIN_RED_LED = 4;
// variables
boolean switchState = LOW;
boolean oldSwitchState = LOW;
long timer_timeStart = 0;
long timer_timeStop = 0;
byte state = 0;
const byte CLOSEDtoOPEN = 1;
const byte OPENtoCLOSED = 2;
const byte SHORT_PRESS = 3;
const byte LONG_PRESS = 4;
// the maximum time for a short press
const long SHORT_KEY_PRESS_MAX_DURATION = 1000; // 1000ms is 1 second
byte pressType = 0;
void setup()
{
Serial.begin(9600);
Serial.print("Sketch: "); Serial.println(__FILE__);
Serial.print("Uploaded: "); Serial.println(__DATE__);
Serial.println(" ");
pinMode(PIN_PUSH_BUTTON_SWITCH, INPUT);
pinMode(PIN_RED_LED, OUTPUT);
digitalWrite(PIN_RED_LED,LOW); // not really required but makes me feel better.
}
void loop()
{
state = checkSwitch();
if (state == OPENtoCLOSED)
{
startTimer();
turnOnLED();
}
else if (state == CLOSEDtoOPEN)
{
pressType = stopTimer();
if (pressType == SHORT_PRESS)
{
turnOffLED();
pressType = 0;
}
if (pressType == LONG_PRESS)
{
// leave the LED on.
}
}
} // loop
int checkSwitch()
{
byte returnVal = 0;
// simple debounce
boolean newSwitchState1 = digitalRead(PIN_PUSH_BUTTON_SWITCH); delay(1);
boolean newSwitchState2 = digitalRead(PIN_PUSH_BUTTON_SWITCH); delay(1);
boolean newSwitchState3 = digitalRead(PIN_PUSH_BUTTON_SWITCH);
if ( (newSwitchState1==newSwitchState2) && (newSwitchState1==newSwitchState3) )
{
if (newSwitchState1 != oldSwitchState)
{
// OPEN => CLOSED
if ( oldSwitchState == LOW && newSwitchState1 == HIGH )
{
returnVal = OPENtoCLOSED;
}
// CLOSED => OPEN
if ( oldSwitchState == HIGH && newSwitchState1== LOW )
{
returnVal = CLOSEDtoOPEN;
}
oldSwitchState = newSwitchState1;
}
} // if ( (newSwitchState1==newSwitchState2) && (newSwitchState1==newSwitchState3) )
return returnVal;
} // int checkSwitch()
void startTimer()
{
timer_timeStart = millis(); // start the timer
}
byte stopTimer()
{
// stop the timer. Return a flag to indicate the duration of the key press
timer_timeStop = millis();
long timePressed = timer_timeStop - timer_timeStart;
byte returnVal = 0;
if (timePressed <= SHORT_KEY_PRESS_MAX_DURATION) { returnVal = SHORT_PRESS;}
else { returnVal = LONG_PRESS;}
return returnVal;
}
void turnOnLED()
{
digitalWrite(PIN_RED_LED,HIGH);
}
void turnOffLED()
{
digitalWrite(PIN_RED_LED,LOW);
}
Основные моменты реализации
Функция checkSwitch() возвращает константы состояния (OPENtoCLOSED, CLOSEDtoOPEN), обеспечивая чистую условную логику. Подход избегает блокирующих задержек, опираясь на неблокирующие переходы состояний и арифметику сравнения миллисекунд.