Запуск таймера с помощью кнопки на Arduino

Демонстрация работы таймера со светодиодом

Несколько примеров, показывающих, как использовать таймер для автоматического выключения светодиода. Первый пример использует кнопку для включения светодиода и функцию delay() для отсчёта времени выключения. Это очень базовый пример того, как не надо делать, используя delay(). После этого примеры расширяют техники из предыдущих руководств, и вводится мигающий светодиод.

Все примеры используют одну и ту же схему.

Схема

  • Пин D10 подключён через резистор 330 Ом к светодиоду и далее к GND

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

Схема подключения кнопки и светодиода

Макетная плата с кнопкой и светодиодом

Пример 1: Базовый таймер с delay() (не рекомендуется)

Для многих людей, когда им нужно, чтобы скетч подождал чего-то, они автоматически обращаются к функции delay(). Использование delay() может работать, но обычно это не лучшее решение. Использование delay() означает, что Arduino не может делать ничего другого и должен ждать, пока то, что вызывает блокировку, не завершится.

//  Sketch: Using a push button switch to turn on an LED with a timer to turn it off. Not the best way.
//  www.martyncurrey.com
//
//  Pins
//  D10 to 330 ohm resister and LED
//  D2 to push button switch with 10K ohm pull down resistor
//

// Define the pins being used
int pin_LED = 10;
int pin_switch = 2;

// variables
boolean oldSwitchState = LOW;
boolean keyPressed = false;
long timer_timeWait = 2000;  // the timer time. 2000ms = 2 seconds

void setup()
{
    Serial.begin(9600);
    Serial.print("Sketch:   ");   Serial.println(__FILE__);
    Serial.print("Uploaded: ");   Serial.println(__DATE__);
    Serial.println(" ");

    pinMode(pin_LED, OUTPUT);
    digitalWrite(pin_LED,LOW);
    pinMode(pin_switch, INPUT);
}

void loop()
{
    keyPressed = checkButtonSwitch();

    if ( keyPressed == true )
    {
         digitalWrite(pin_LED, HIGH);
         delay(timer_timeWait);
         digitalWrite(pin_LED, LOW);
    }

}  // loop


boolean checkButtonSwitch()
{

  boolean key = false;
  boolean newSwitchState1 = digitalRead(pin_switch);      delay(1);
  boolean newSwitchState2 = digitalRead(pin_switch);      delay(1);
  boolean newSwitchState3 = digitalRead(pin_switch);

  if (  (newSwitchState1==newSwitchState2) && (newSwitchState1==newSwitchState3) )
  {
    if ( newSwitchState1 != oldSwitchState )
    {
      if ( newSwitchState1 == HIGH ) { key = true;  }
      else                           { key = false; }
      oldSwitchState = newSwitchState1;
    }
  }
  return key;
}

Ключевая проблема: delay() блокирует код. Блокировка – это когда Arduino не может делать ничего другого и должен ждать, пока то, что вызывает блокировку, не завершится.

Пример 2: Неблокирующий таймер

//  Sketch: Using a push button switch to turn on an LED with a timer to turn off the LED
//  www.martyncurrey.com
//
//
//  Pins
//  D10 to 330 ohm resister and LED
//  D2 to push button switch with 10K ohm pull down resistor
//

// Define the pins being used
int pin_LED = 10;
int pin_switch = 2;

// variables to hold the new and old switch states
boolean oldSwitchState = LOW;

// variables used to control the LED
boolean LEDisON = false;
boolean keyPressed = false;

// variables used for the timer
long timer_timeStart = 0;
long timer_timeWait = 2000;  // the timer time. 2000ms = 2 seconds
boolean timerIsActive = false;


void setup()
{
    Serial.begin(9600);
    Serial.print("Sketch:   ");   Serial.println(__FILE__);
    Serial.print("Uploaded: ");   Serial.println(__DATE__);
    Serial.println(" ");

    pinMode(pin_LED, OUTPUT);
    digitalWrite(pin_LED,LOW);
    pinMode(pin_switch, INPUT);
}


void loop()
{
    keyPressed = checkButtonSwitch();  //  check the status of the button switch

    if ( keyPressed == true )  //  if the button switch is pressed do something
    {
        keyPressed = false;
        turnOnLED();
        startTimer();
    }

    if ( LEDisON == true )  //  if the LED is on check to see if it is time to turn it off
    {
        timerIsActive = checkTimer();
        if (timerIsActive == false) {  stopTimer(); turnOfLED();  }
    }

}  // loop


boolean checkButtonSwitch()
{

  boolean key = false;
  boolean newSwitchState1 = digitalRead(pin_switch);      delay(1);
  boolean newSwitchState2 = digitalRead(pin_switch);      delay(1);
  boolean newSwitchState3 = digitalRead(pin_switch);

  if (  (newSwitchState1==newSwitchState2) && (newSwitchState1==newSwitchState3) )
  {
    if ( newSwitchState1 != oldSwitchState )
    {
      if ( newSwitchState1 == HIGH ) { key = true;  }
      else                           { key = false; }
      oldSwitchState = newSwitchState1;
    }
  }
  return key;
}


void startTimer()
{
  timer_timeStart = millis();
  timerIsActive = true;
}

void stopTimer()
{
  timerIsActive = false;
  timer_timeStart = 0;
}

boolean checkTimer()
{
  boolean timerOn = false;
  if ( millis() - timer_timeStart < timer_timeWait )  { timerOn = true;  }
  return timerOn;
}

void turnOnLED()
{
  digitalWrite(pin_LED, HIGH);
  LEDisON = true;
}


void turnOfLED ()
{
  LEDisON = false;
  digitalWrite(pin_LED, LOW);
}

Ключевое дополнение: Функция checkTimer() использует выражение millis() - timer_timeStart < timer_timeWait для сравнения прошедшего времени с длительностью ожидания.

Разделение кода таким образом делает ``loop()`` максимально коротким и чистым, и упрощает расширение кода в дальнейшем.

Необязательное предотвращение сброса таймера: Измените проверку кнопки на:

if (timerIsActive == false) { keyPressed = checkButtonSwitch(); }

Пример 3: Мигающий светодиод с автоматическим выключением по таймеру

//  Sketch: Using a push button switch to turn on a blinking LED with auto off via a timer
//  www.martyncurrey.com
//
//
//  Pins
//  D10 to 330 ohm resister and LED
//  D2 to push button switch with 10K ohm pull down resistor
//

// Define the pins being used
int pin_LED = 10;
int pin_switch = 2;


// variables to hold the new and old switch states
boolean oldSwitchState = LOW;

// variables to hold the times
unsigned long flashLED_timeNow = 0;
unsigned long flashLED_timePrev = 0;
unsigned int  flashLED_blinkRate = 100; // This is the LED blink rate

// variables used to control the LED
boolean flashingLEDisON = false;
boolean LEDstatus = LOW;
boolean keyPressed = false;

// variables used for the timer
long timer_timeStart = 0;
long timer_timeWait = 2000;  // the timer length of time. 2000ms = 2 seconds
boolean timerIsActive = false;


void setup()
{
    Serial.begin(9600);
    Serial.print("Sketch:   ");   Serial.println(__FILE__);
    Serial.print("Uploaded: ");   Serial.println(__DATE__);
    Serial.println(" ");

    pinMode(pin_LED, OUTPUT);
    digitalWrite(pin_LED,LOW);
    pinMode(pin_switch, INPUT);
}

void loop()
{
    keyPressed = checkButtonSwitch();

    if ( keyPressed == true )
    {
        keyPressed = false;
        startTimer();
        flashingLEDisON = true;
    }


    if ( flashingLEDisON == true )
    {
        timerIsActive = checkTimer();
        if (timerIsActive == true)  { blinkTheLED(); }
        else                        { stopTimer(); turnOfLED();  }
    }

}  // loop


boolean checkButtonSwitch()
{
  boolean key = false;
  boolean newSwitchState1 = digitalRead(pin_switch);      delay(1);
  boolean newSwitchState2 = digitalRead(pin_switch);      delay(1);
  boolean newSwitchState3 = digitalRead(pin_switch);

  if (  (newSwitchState1==newSwitchState2) && (newSwitchState1==newSwitchState3) )
  {
    if ( newSwitchState1 != oldSwitchState )
    {
      if ( newSwitchState1 == HIGH ) { key = true;  }
      else                           { key = false; }
      oldSwitchState = newSwitchState1;
    }
  }
  return key;
}


void startTimer()
{
  timer_timeStart = millis();
  timerIsActive = true;
}

void stopTimer()
{
  timerIsActive = false;
  timer_timeStart = 0;
}



boolean checkTimer()
{
  boolean timerOn = false;
  if ( millis() - timer_timeStart < timer_timeWait )  { timerOn = true;   }
  return timerOn;
}



void blinkTheLED()
{
  flashLED_timeNow = millis();
  if (flashLED_timeNow - flashLED_timePrev >= flashLED_blinkRate )
  {
    flashLED_timePrev = flashLED_timeNow;
    if (LEDstatus == LOW)   { LEDstatus = HIGH; }
    else                    { LEDstatus = LOW;  }
    digitalWrite(pin_LED, LEDstatus);
  }
}

void turnOfLED ()
{
  flashingLEDisON = false;
  digitalWrite(pin_LED, LOW);
}

Пример 4: Без сброса таймера при повторном нажатии

//  Sketch: Using a push button switch to turn on a blinking LED with a timer - no timer reset
//  www.martyncurrey.com
//
//
//  Pins
//  D10 to 330 ohm resister and LED
//  D2 to push button switch with 10K ohm pull down resistor
//

// Define the pins being used
int pin_LED = 10;
int pin_switch = 2;


// variables to hold the new and old switch states
boolean oldSwitchState = LOW;

// variables to hold the times
unsigned long flashLED_timeNow = 0;
unsigned long flashLED_timePrev = 0;
unsigned int  flashLED_blinkRate = 100; // This is the LED blink rate

// variables used to control the LED
boolean flashingLEDisON = false;
boolean LEDstatus = LOW;
boolean keyPressed = false;

// variables used for the timer
long timer_timeStart = 0;
long timer_timeWait = 2000;  // the timer time. 2000ms = 2 seconds
boolean timerIsActive = false;



void setup()
{
    Serial.begin(9600);
    Serial.print("Sketch:   ");   Serial.println(__FILE__);
    Serial.print("Uploaded: ");   Serial.println(__DATE__);
    Serial.println(" ");

    pinMode(pin_LED, OUTPUT);
    digitalWrite(pin_LED,LOW);
    pinMode(pin_switch, INPUT);
}


void loop()
{
    keyPressed = checkButtonSwitch();

    if ( keyPressed == true )
    {
        keyPressed = false;

        if ( checkTimer() == false )
        {
          startTimer();
          flashingLEDisON = true;
        }

    }

    if ( flashingLEDisON == true )
    {
        timerIsActive = checkTimer();
        if (timerIsActive == true) { blinkTheLED(); }
        else                       { stopTimer(); turnOfLED();  }
    }

}  // loop


boolean checkButtonSwitch()
{

  boolean key = false;
  boolean newSwitchState1 = digitalRead(pin_switch);      delay(1);
  boolean newSwitchState2 = digitalRead(pin_switch);      delay(1);
  boolean newSwitchState3 = digitalRead(pin_switch);

  if (  (newSwitchState1==newSwitchState2) && (newSwitchState1==newSwitchState3) )
  {
    if ( newSwitchState1 != oldSwitchState )
    {
      if ( newSwitchState1 == HIGH ) { key = true;  }
      else                           { key = false; }
      oldSwitchState = newSwitchState1;
    }
  }
  return key;
}


void startTimer()
{
  timer_timeStart = millis();
  timerIsActive = true;
}

void stopTimer()
{
  timerIsActive = false;
  timer_timeStart = 0;
}



boolean checkTimer()
{
  boolean timerOn = false;
  if ( millis() - timer_timeStart < timer_timeWait )  { timerOn = true;   }
  return timerOn;
}



void blinkTheLED()
{
  flashLED_timeNow = millis();
  if (flashLED_timeNow - flashLED_timePrev >= flashLED_blinkRate )
  {
    flashLED_timePrev = flashLED_timeNow;
    if (LEDstatus == LOW)   { LEDstatus = HIGH; }
    else                    { LEDstatus = LOW;  }
    digitalWrite(pin_LED, LEDstatus);
  }
}

void turnOfLED ()
{
  flashingLEDisON = false;
  digitalWrite(pin_LED, LOW);
}

Ключевое изменение: Условие if ( checkTimer() == false ) (или эквивалентно if (!checkTimer())) предотвращает перезапуск таймера, пока он активен.

Основные концепции

Логика таймера: Выражение millis() - timer_timeStart < timer_timeWait возвращает TRUE, пока прошедшее время меньше длительности ожидания.

Преимущества перед delay(): Неблокирующие таймеры позволяют Arduino выполнять другой код во время операции отсчёта времени.

Модульный дизайн: Разделение кода таким образом делает loop() максимально коротким и чистым, а расширение кода в будущем – более простым.

Упражнения

  • Увеличьте длительность таймера и реализуйте ручное выключение светодиода по нажатию кнопки, пока он мигает

  • Измените частоту мигания с помощью ввода с кнопки