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