I've spent a few hours moving code around here... Trying to get this timer to ignore subsequent button presses if the time interval between presses is greater than 5 seconds.
3 presses ON, 3 presses OFF works - but will always work regardless of time between presses.
What am I missing here???
// MPS Intent Switch v2.0
// 3 Press ON, 3 Press OFF (if 3 presses within 5 seconds)
// c.2022-24 by Jerry Tucker
#define button1 3 //Push button1 on D3
#define RELAY 2 //RELAY on D2
//-----
const unsigned long Interval = 5000;
unsigned long lastpressTime = 0;
int state = 0; //integer to hold current state
int old = 0; //integer to hold last state
int button1Poll = 0; //integer to hold button1 state
int lastPressTime = 0; //integer to hold last press time
//-----
void setup() {
pinMode(button1, INPUT_PULLUP); //button1 set as input
pinMode(RELAY, OUTPUT); // RELAY as output
digitalWrite(RELAY, HIGH); //set RELAY initial state as OFF
}
//-----
void loop() {
unsigned long currentTime = millis();
//debouncing routine to read button
button1Poll = digitalRead(button1); //poll the state of button1
if (button1Poll == 1) { //check if it has been pressed
delay(50); //wait 50ms
button1Poll = digitalRead(button1); //poll button1 again
if (button1Poll == 0) { // if 0 - considered one press
state = old + 1; //increase state by 1
}
} else { //if button1 has not been pressed
delay(50); //wait 50ms
}
(old = 0);
switch (state) { //react to button1 press & state
case 1: //if state is 1
digitalWrite(RELAY, HIGH); //RELAY off
old = state; //set old state as current state
break;
//if button1 has not been pressed within 5 seconds
if ((currentTime)-lastPressTime > Interval)
;
(state = 0); //set 'state' to zero;
{
case 2:
digitalWrite(RELAY, HIGH);
old = state;
break;
case 3:
digitalWrite(RELAY, LOW); //RELAY on
old = state;
break;
case 4:
digitalWrite(RELAY, LOW); //RELAY on
old = state; //set old state as current state
break;
case 5:
digitalWrite(RELAY, LOW);
old = state;
break;
case 6:
digitalWrite(RELAY, HIGH); //RELAY off
old = 0;
break;
default: //if state is not 1,2,3,4,5,6
digitalWrite(RELAY, HIGH); //RELAY OFF
old = 0; //reset RELAY to off/state
break;
}
}
}
switch (state) { //react to button1 press & state
case 1: //if state is 1
digitalWrite(RELAY, HIGH); //RELAY off
old = state; //set old state as current state
break;
//if button1 has not been pressed within 5 seconds
if ((currentTime)-lastPressTime > Interval)
;
(state = 0); //set 'state' to zero;
{
case 2:
digitalWrite(RELAY, HIGH);
old = state;
break;
case 3:
digitalWrite(RELAY, LOW); //RELAY on
old = state;
break;
case 4:
digitalWrite(RELAY, LOW); //RELAY on
old = state; //set old state as current state
break;
case 5:
digitalWrite(RELAY, LOW);
old = state;
break;
case 6:
digitalWrite(RELAY, HIGH); //RELAY off
old = 0;
break;
default: //if state is not 1,2,3,4,5,6
digitalWrite(RELAY, HIGH); //RELAY OFF
old = 0; //reset RELAY to off/state
break;
}
}
This is unreachable, will never run, besides being perhaps not what you meant:
//if button1 has not been pressed within 5 seconds
if ((currentTime)-lastPressTime > Interval)
;
(state = 0); //set 'state' to zero;
as it is exactly the same as:
state = 0; //set 'state' to zero;
BTW usually statements are not ( inside parentheses )...
Also, I don't think you need old, which look s to be in the middle of this mess. Usually state would just be set dir3ctly by case code that decided the state should change, viz:
case 5:
digitalWrite(RELAY, LOW);
state = 6; // move to next state for next time in the switch/case
break;
So I haven't yet looked at the logic or reviewed your goal.
We've looked at your code, then we played with the general idea.
Some of us have convinced others that unless you keep track of the history, that is to say the times when the button got pressed, you will not be able to reliably detect and react to three button presses within five seconds.
Press, wait one second, press wait one second and press is straightforward and easy.
But look at
Press wait three seconds, press wait three seconds, press twice more within 2 more seconds.
It is the second, third and fourth presses that are within five seconds of each other.
You will have to store the times of the previous two presses and when the next one comes in, compare its time of arrival to that of the second most recent press.
As a new press comes along, the oldest press is no longer important. So you will, when it's all cranking away, be discarding the oldest press time, and adding the newly pressed time to to your tracking.
I will mention that in a case like this, an array will help, and using such an array as a circular buffer will make things a bit easier.
Interesting information, thanks!
I will say that this circuit has been working perfectly (and still does) for a couple of years without the 5 second timeout...
It is for an electronic hand control accelerator for disabled drivers... I started playing around with the "5-second rule" just to try to avoid accidental engagement or disengagement because of fumbling sound hitting the button 3 times.
I can hit the button very rapidly, or hit... wait... hit... wait...hit and have it activate or deactivate the relay.
Should one isolated press of the button do something? If so, you should then set a timer for five seconds, and ignore (don't even look at) the button until it expires:
if time since last press is > 5 seconds
see if the button is pressed and
do whatever that should do
note the time of this, the last button press
Or do you want to make someone press three times close together to get something to happen, and what you don't want is three presses over twenty minutes?
Then tracking them as I outkined seems necessary. Unless it's just a tricky UI thing, where saying "N presses within M seconds" is not literally the rule, and some tolerance is available for missing three press events which would qualify under a strict interpretation.