// https://arduino.stackexchange.com/questions/95476/fixing-a-pedestrian-traffic-light-sequence-pattern-in-a-cycle-using-millis-and-w
// for simulation, see https://wokwi.com/projects/389132610627050497
const int redLED = 2;
const int greenLED = 3;
unsigned int timeInterval [4] = { 5, 3, 4, 0}; // timers reload with these values
unsigned int timeCounter [4] = { 0, 0, 0, 0}; // these are the actual timers
//boolean reloadable [4] = {true, true, false, false}; // this determines if the timer will restart upon reaching end
// put value in <timeCounter> for oneshot event
// 3rd and 4th timers are not used in this example sketch
boolean tick [4] = {false, false, false, false}; // countdown timers flags
boolean mainTick = false;
boolean subTick = false;
boolean red = false;
boolean green = false;
boolean blink = false;
unsigned long previousMillis = 0;
void setup() {
Serial.begin(115200);
//memcpy(timeCounter, timeInterval, 4 * sizeof(long)); // preload timers
green = true; // start with green
timeCounter[0] = 1; // load the first counter
}
void loop() {
unsigned long currentMillis = millis();
// -------------------------------------------------------------------
if (currentMillis - previousMillis >= 500) { // 0.5 s tick
previousMillis = currentMillis;
subTick = !subTick; // alternate the value
if (subTick) {
mainTick = true; // 1 s tick
// Serial.println("tick"); // debugging code
for (int i = 0; i < 4; i++) { // keep track of 4 time intervals
timeCounter[i]-- ; // decrement counter
if (timeCounter[i] == 0) {
// if (reloadable[i]) timeCounter[i] = timeInterval[i]; // reached zero, reload counter if it is reloadable
tick[i] = true; // emit a "tick"
}
}
}
}
// -------------------------------------------------------------------
if (mainTick) { // 1 s tick
}
// -------------------------------------------------------------------
if (tick[0]) { //
tick[0] = false;
timeCounter[1] = timeInterval[1]; // setup the next tick
red = false; // setup flags
green = true;
blink = false;
}
// -------------------------------------------------------------------
if (tick[1]) { //
tick[1] = false; // clear flag so that code runs only once every tick
timeCounter[2] = timeInterval[2]; // setuop the next tick
red = true;
green = false;
blink = false;
}
// -------------------------------------------------------------------
if (tick[2]) { //
tick[2] = false; // clear flag so that code runs only once every tick
timeCounter[0] = timeInterval[0]; // setuop the next tick
red = false;
green = false;
blink = true;
}
// -------------------------------------------------------------------
if (mainTick) { // can have multiples of these
mainTick = false; // clear the flag in the last one
}
// -------------------------------------------------------------------
digitalWrite(redLED , red ? HIGH:LOW); // C++ ternary operator
digitalWrite(greenLED, green ? HIGH:LOW);
digitalWrite(redLED , blink && subTick? HIGH:LOW); // subTick changes every 500 ms
}