// A state machine is used, only to make it more clear what is going on.
//
// When a button is pressed, the input turns HIGH.
// Are there an external pulldown resistors ?
//
// Normally only one 'enum' is used for the state, that controls the code.
// This sketch has also a 'enum' for the buttons, which is called the input state.
// define the different states for this sketch.
// An 'enum' is like a number of #define with increasing numbers.
enum
{
WAIT_FOR_BOTH_OFF,
WAIT_FOR_BOTH_ON,
SAFETY_WINDOW,
RELAY_ON,
} state; // an 'enum' is automatically an integer. <- it is not an integer
// define the different input states.
enum
{
BOTH_OFF, // no buttons are pressed.
BOTH_ON, // both buttons are pressed.
SOMETHING_ELSE, // probably one of the buttons is pressed.
};
const int ButtonPin1 = 2;
const int ButtonPin2 = 3;
// The previousMillis is used twice for two different things.
// That is okay in this state machine.
unsigned long previousMillis;
const unsigned long RelayOnTime = 1000; // Length of time for relay
const unsigned long PushTimeWindow = 1000; // Length of time to allow two pushes
// Counters for the number of failed relay triggers and successful cycles.
// They can probably be normal integers as well.
unsigned long failed = 0;
unsigned long success = 0;
void setup()
{
Serial.begin(9600);
Serial.println("Hello");
pinMode(ButtonPin1, INPUT);
pinMode(ButtonPin2, INPUT);
pinMode(LED_BUILTIN, OUTPUT); // LED_BUILTIN for testing
Serial.println("Going to WAIT_FOR_BOTH_OFF state");
state = WAIT_FOR_BOTH_OFF;
}
void loop()
{
unsigned long currentMillis = millis();
// Collect all input data.
int inputState = getInputState();
// Process the data in a state machine.
// The output part is also in the state machine.
switch(state)
{
case WAIT_FOR_BOTH_OFF:
// Both buttons must be released to be able to continue.
if(inputState == BOTH_OFF)
{
// Prepare to go to the next state.
Serial.println("Going to WAIT_FOR_BOTH_ON state");
state = WAIT_FOR_BOTH_ON;
}
break;
case WAIT_FOR_BOTH_ON:
// This is the state when everything is idle and no buttons are pressed.
// Normally both buttons are released,
// but when both are pressed, then go to the next state.
if(inputState == BOTH_ON)
{
// Prepare to go to the next state.
Serial.println("Going to SAFETY_WINDOW state");
previousMillis = currentMillis;
state = SAFETY_WINDOW;
}
break;
case SAFETY_WINDOW:
if(inputState != BOTH_ON)
{
// During the safety time window, a button was released.
// Return to idle.
Serial.println("Going to WAIT_FOR_BOTH_OFF state");
state = WAIT_FOR_BOTH_OFF;
}
else if(currentMillis - previousMillis >= PushTimeWindow)
{
// The buttons are still pressed.
// The time window has reached the end.
// Prepare to go to the next state.
Serial.println("Going to RELAY_ON state");
previousMillis = currentMillis;
digitalWrite(LED_BUILTIN, HIGH); // LED_BUILTIN for testing
state = RELAY_ON;
}
break;
case RELAY_ON:
if(inputState != BOTH_ON)
{
// One of the buttons was released.
// Stop the relay and return to idle.
// Although the relay was triggered, it was not succesful.
failed++;
Serial.print("Failed=");
Serial.println(failed);
Serial.println("Going to WAIT_FOR_BOTH_OFF state");
digitalWrite( LED_BUILTIN, LOW); // LED_BUILTIN for testing
state = WAIT_FOR_BOTH_OFF;
}
else if(currentMillis - previousMillis >= RelayOnTime)
{
// Everyting was okay.
// The buttons are still pressed.
// It was complete and succesful.
// It is time to turn off the relay and return to idle.
success++;
Serial.print("Success=");
Serial.println(success);
Serial.println("Going to WAIT_FOR_BOTH_OFF state");
digitalWrite(LED_BUILTIN, LOW); // LED_BUILTIN for testing
state = WAIT_FOR_BOTH_OFF;
}
break;
default:
Serial.println("Error, unknown state");
break;
}
}
// This function returns the input state.
// There is no StateChangeDetection, because a state machine is used.
int getInputState()
{
int returnInputState;
// Read the buttons and create a input state according to the 'enum' values.
int ButtonState1 = digitalRead(ButtonPin1);
int ButtonState2 = digitalRead(ButtonPin2);
if(ButtonState1 == LOW && ButtonState2 == LOW)
{
returnInputState = BOTH_OFF;
}
else if(ButtonState1 == HIGH && ButtonState2 == HIGH)
{
returnInputState = BOTH_ON;
}
else
{
// Not both on, not both off, so it must be something else.
returnInputState = SOMETHING_ELSE;
}
return(returnInputState);
}
Correction nov 4, 2017
Oops, an 'enum' is not automatically an integer. An 'enum' is its own type. Its type is more like the type of a union or struct.