// Forum: https://forum.arduino.cc/t/arduino-millis-steps-for-relay-control-randomly-crashes/1232885
// This Wokwi project: https://wokwi.com/projects/391753526969188353
#define RELAYONE 11
#define RELAYTWO 10
#define SW1_PIN 9
#define LEDSTAT 8
const unsigned long RELAY_ON_INTERVAL = 9000;
const unsigned long PAUSE_INTERVAL = 500;
const unsigned long MOTOR_OFF_INTERVAL = 500; /* not using this */
const unsigned long SPARE_INTERVAL = 750; /* not using this */
unsigned long startMillis;
// true: RELAY signal is ON
// false: RELAY signal is OFF
bool isRELAY = false;
// Tracks the current steps
uint8_t steps = 0;
// Holds the current state
bool relay_one_state = false;
bool relay_two_state = false;
bool led_state = false;
// This is for button debouncing
bool currState = HIGH;
bool prevState = HIGH;
bool buttonState = HIGH;
unsigned long debounceStart = 0;
unsigned long debounceDuration = 50;
void setup() {
pinMode(RELAYONE, OUTPUT);
pinMode(RELAYTWO, OUTPUT);
pinMode(SW1_PIN, INPUT_PULLUP);
pinMode(LEDSTAT, OUTPUT);
Serial.begin(9600);
}
void loop() {
/*
Here is the breakdown of the steps:
0: RELAYONE is on (high)
1: off
2: RELAYTWO is on (high)
3: off
*/
// Logic for the RELAY
// Pseudo code:
// if RELAY is ON, check the current steps
// if steps is 1 and 3
// send PAUSE_INTERVAL
// if steps is 0
// send RELAY_ON_INTERVAL
// if steps is 2
// send RELAY_ON_INTERVAL
// The duration of each signal is achieve using
// the millis() function
// For example:
// if ( ( millis() - startMillis ) >= RELAY_ON_INTERVAL ) {
// steps++;
// startMillis = millis(); // save the start time
// }
// The ( millis() - startMillis ) is basically the elapse time
// since the startMillis is recorded
// so that ( ( millis() - startMillis ) >= RELAY_ON_INTERVAL ) is
// basically for checking if the required interval is achieve.
// If it becomes true, increment the counter and record the time
// and so on
if (isRELAY) {
if ( ( steps == 1 ) ||
( steps == 3 ) ) {
Serial.println("pause");
relay_one_state = false;
relay_two_state = false;
if ( ( millis() - startMillis ) >= PAUSE_INTERVAL ) {
steps++;
startMillis = millis(); // save the start time
}
} else if ( ( steps == 0 )) {
Serial.println("step 0");
relay_one_state = true;
relay_two_state = false;
led_state = true;
if ( ( millis() - startMillis ) >= RELAY_ON_INTERVAL ) {
// signal interval is complete
// move to the next step
steps++;
startMillis = millis(); // save the start time
}
} else if ( ( steps == 2 ) ) {
Serial.println("step 2");
relay_one_state = false;
relay_two_state = true;
if ( ( millis() - startMillis ) >= RELAY_ON_INTERVAL ) {
steps++;
startMillis = millis(); // save the start time
}
} else {
relay_one_state = false;
relay_two_state = false;
if ( ( millis() - startMillis ) >= MOTOR_OFF_INTERVAL ) {
steps++;
startMillis = millis(); // save the start time
}
}
// if the steps reach steps 5, go back to steps 0
if (steps > 4) steps = 0;
}
// Update the output signal
digitalWrite(RELAYONE, relay_one_state);
digitalWrite(RELAYTWO, relay_two_state);
digitalWrite (LEDSTAT, led_state);
/*
This is for debouncing the tactile switch
*/
currState = digitalRead(SW1_PIN);
if (currState != prevState) {
debounceStart = millis();
}
if ((millis() - debounceStart) > debounceDuration) {
if (currState != buttonState) {
buttonState = currState;
if (currState == LOW) {
if ( isRELAY ) {
// currently sending motor sequence, now turn it off
isRELAY = false;
Serial.println("off");
relay_one_state = false;
relay_two_state = false;
led_state = false;
} else {
// currently motor sequence is off, now turn it on
isRELAY = true;
startMillis = millis();
Serial.println("on");
steps = 0;
}
}
}
}
prevState = currState;
// Do other stuffs here, without blocking
}
relays are active high
Arduino + millis + steps for relay control randomly crashes