Arduino: Короткое нажатие и длинное нажатие

Демонстрация короткого и длинного нажатия с управлением светодиодом

Использование коротких и длинных нажатий вместе добавляет универсальности и даёт дополнительную функциональность одной кнопке. Вы больше не ограничены состояниями «нажато» или «не нажато». Теперь у вас есть «нажато немного» и «нажато подольше».

Это руководство продолжает предыдущую статью о измерении времени нажатия кнопки и предполагает, что вы её прочитали. Если нет – у вас есть домашнее задание.

В этом руководстве мы рассмотрим, как определить, было ли нажатие коротким или длинным.

Схема (Пример 1)

Схема очень простая: одна кнопка, подключённая к Arduino с подтягивающим резистором 10 кОм к земле.

  • Пин D12 подключён к кнопке с подтягивающим резистором 10 кОм к GND

Макетная плата с кнопкой

Схема подключения кнопки к Arduino

Пример 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

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), обеспечивая чистую условную логику. Подход избегает блокирующих задержек, опираясь на неблокирующие переходы состояний и арифметику сравнения миллисекунд.