Newcomers to Arduino, soon discover the usefulness of using the Blink Without Delay (BWD) technique for timing events.
As most old timers realize, adding a Flag to this technique can prevent subtle and often unanticipated problems.
For those newcomers who do not know what and why a Flag should be used, hopefully this discussion will shed some light on the topic.
In the code segment below, we are looking for a time interval to expire.
When we want to start event timing with BWD, we make ledOnMillis = millis().
When our time test is true, we turn off a LED.
//**************************************
//has the timing interval expired?
if (millis() - ledOnMillis >= 5000)
{
//turn the red LED OFF 5 seconds after it went ON
digitalWrite(redLED, OFF) ;
}
//**************************************
The problem with the code is, once the interval is up, we repeatably turn off the LED each time this code segment is run.
i.e. millis() - ledOnMillis >= 5000 continues to be true.
This might be okay for most applications but, let's say our LED was turned on somewhere in the sketch in a seldom used part of code, the LED will immediately be turned off when this code segment is executed.
Also, since we are constantly turning off the LED once the delay interval is up, this takes up processor time, therefore, we slow down total code execution time.
We can add a Flag variable to our timing test to prevent the above.
Now when we want to do event timing, we make our Flag = true (which enables timing) and as before, make ledOnMillis = millis().
Once the interval has expired, the Flag variable is set to false.
Since Flag is now false, time checking only happens once.
Each time we need to time our event, we make Flag = true and make ledOnMillis = millis().
//**************************************
//when timing is enabled, has the timing interval expired?
if ( Flag == true && millis() - ledOnMillis >= 5000)
{
//turn the red LED OFF 5 seconds after it went ON
digitalWrite(redLED, OFF);
//disable timing
Flag = false; // <------<<<<<
}
//**************************************
The following two sketches further develop this concept:
#define OFF LOW
#define ON HIGH
unsigned long ledOnMillis;
const unsigned long onTime = 5000;
boolean ledOnFlag = false;
const byte redLED = 13;
const byte onSwitch = 2;
const byte auxOnSwitch = 3;
const byte auxOffSwitch = 4;
byte lastOnSwitchState;
//*********************************************************************************
void setup()
{
Serial.begin(9600);
pinMode(redLED, OUTPUT);
digitalWrite(redLED, OFF);
//switch wired so a press give a LOW
pinMode(onSwitch, INPUT_PULLUP);
//initialize the last State variable
lastOnSwitchState = digitalRead(onSwitch);
pinMode(auxOnSwitch, INPUT_PULLUP);
pinMode(auxOffSwitch, INPUT_PULLUP);
} //END of setup()
//*********************************************************************************
void loop()
{
//**************************************
byte currentState = digitalRead(onSwitch);
//has the ON switch changed state?
if (lastOnSwitchState != currentState)
{
//update to the new state
lastOnSwitchState = currentState;
//did the switch just get pressed i.e. LOW?
if (currentState == LOW)
{
//turn the red LED ON
digitalWrite(redLED, ON);
Serial.println("Turn LED ON");
//the time when the red LED went ON
ledOnMillis = millis();
}
//switch must have gone HIGH
else
{
//nothing to do here
}
} //END of if( lastOnSwitchState != currentState);
//**************************************
//has the timing interval expired?
if (millis() - ledOnMillis >= onTime)
{
//turn the red LED OFF 5 seconds after it went ON
digitalWrite(redLED, OFF);
Serial.println("Turn LED OFF");
//maybe do some other stuff
}
//**************************************
//when the auxiliary on switch is pressed, turn ON the red LED
if (digitalRead(auxOnSwitch) == LOW)
{
//turn the red LED ON
digitalWrite(redLED, ON);
Serial.println("Turn LED ON");
}
//**************************************
//when the auxiliary off switch is pressed, turn OFF the red LED
if (digitalRead(auxOffSwitch) == LOW)
{
//turn the red LED Off
digitalWrite(redLED, OFF);
Serial.println("Turn LED OFF");
}
} //END of loop()
//*********************************************************************************
#define OFF LOW
#define ON HIGH
unsigned long ledOnMillis;
const unsigned long onTime = 5000;
boolean ledOnFlag = false;
const byte redLED = 13;
const byte onSwitch = 2;
const byte auxOnSwitch = 3;
const byte auxOffSwitch = 4;
byte lastOnSwitchState;
//*********************************************************************************
void setup()
{
Serial.begin(9600);
pinMode(redLED, OUTPUT);
digitalWrite(redLED, OFF);
//switch wired so a press give a LOW
pinMode(onSwitch, INPUT_PULLUP);
//initialize the last State variable
lastOnSwitchState = digitalRead(onSwitch);
pinMode(auxOnSwitch, INPUT_PULLUP);
pinMode(auxOffSwitch, INPUT_PULLUP);
} //END of setup()
//*********************************************************************************
void loop()
{
//**************************************
byte currentState = digitalRead(onSwitch);
//when timing is disabled, has the ON switch changed state?
if (ledOnFlag == false && lastOnSwitchState != currentState)
{
//update to the new state
lastOnSwitchState = currentState;
//did the switch just get pressed i.e. LOW?
if (currentState == LOW)
{
//turn the red LED ON
digitalWrite(redLED, ON);
Serial.println("Turn LED ON");
//the time when the red LED went ON
ledOnMillis = millis();
//enable timing
ledOnFlag = true;
}
//switch must have gone HIGH
else
{
//nothing to do here
}
} //END of if (ledOnFlag == false && lastOnSwitchState != currentState)
//**************************************
//if timing is enabled, has the timing interval expired?
if (ledOnFlag == true && millis() - ledOnMillis >= onTime)
{
//turn the red LED OFF 5 seconds after it went ON
digitalWrite(redLED, OFF);
Serial.println("Turn LED OFF");
//disable timing
ledOnFlag = false; // <------<<<<<
//maybe do some other stuff
}
//**************************************
//when the auxiliary on switch is pressed, turn ON the red LED
if (digitalRead(auxOnSwitch) == LOW)
{
//turn the red LED ON
digitalWrite(redLED, ON);
Serial.println("Turn LED ON");
}
//**************************************
//when the auxiliary off switch is pressed, turn OFF the red LED
if (digitalRead(auxOffSwitch) == LOW)
{
//turn the red LED Off
digitalWrite(redLED, OFF);
Serial.println("Turn LED OFF");
//disable timing
ledOnFlag = false;
}
} //END of loop()
//*********************************************************************************
Also, we can disable switch testing while timing is enabled by adding Flag to our change in state code.
This prevents our timing from resetting if the switch is closed while timing is enabled.
//when timing is disabled, has the ON switch changed state?
if (ledOnFlag == false && lastOnSwitchState != currentState)
{
. . .
}