// https://forum.arduino.cc/t/traffic-light-multiple-timers/1401886/
// pin labels use n, s, e, w for direction
byte buttonpin[] = {2, 3}; // (nsButton, ewButton) two buttons share each pin
byte buttonpinSize = sizeof(buttonpin) / sizeof(buttonpin[0]);
byte ledpin[] = {4, 5, 6, 7, 8, 9, 10, 11};
byte ledpinSize = sizeof(ledpin) / sizeof(ledpin[0]);
byte nsGRN = 4, ewGRN = 5, nsYEL = 6, ewYEL = 7, nsRED = 8, ewRED = 9, nsWHT = 10, ewWHT = 11;
int cycleState;
bool direction, walkButtonPressed = 0;
unsigned long normalCycleTimer, normalCycleTimeout = 2000;
void setup() {
Serial.begin(115200);
initButtons();
initLEDs();
testLEDs(100);
// while (1) testLEDs(500);
// while (1) testButtons();
}
void loop() {
readButtons();
if (walkButtonPressed) {
walkCycle();
walkButtonPressed = 0; // reset walk button flag
} else
normalCycle();
}
// =================
// cycle functions
// =================
void normalCycle() {
// state: 0 >> 1 >> 2 >> 3 |
// NS: GRN >> YEL >> RED >> RED/YEL |
// EW: RED >> RED/YEL >> GRN >> YEL |
if (millis() - normalCycleTimer > normalCycleTimeout) {
normalCycleTimer = millis();
if (cycleState > 3)
cycleState = 0;
clearLEDs();
switch (cycleState) {
case 0: { // N/S moving, E/W stopped
digitalWrite(nsGRN, HIGH);
digitalWrite(ewRED, HIGH);
break;
}
case 1: { // caution
digitalWrite(nsYEL, HIGH);
digitalWrite(ewRED, HIGH);
digitalWrite(ewYEL, HIGH);
break;
}
case 2: { // N/S stopped, E/W moving
digitalWrite(nsRED, HIGH);
digitalWrite(ewGRN, HIGH);
break;
}
case 3: { // caution
digitalWrite(nsRED, HIGH);
digitalWrite(nsYEL, HIGH);
digitalWrite(ewYEL, HIGH);
break;
}
default: break;
}
cycleState++;
}
}
void walkCycle() {
// walkstate: 0 >> 1 >> 2 >> 3 >> 4 >> 5 |
// PARLLEL: GRN >> YEL >> GRN/WHT >> YEL >> RED/YEL >> RED | >> Enter GRN exit RED
// PERPENDICULAR: RED >> YEL >> RED/YEL >> GRN | >> Enter RED Exit GRN
byte parWHT, parRED, parYEL, parGRN, perWHT, perRED, perYEL, perGRN; // temporary pin labels
int cycleDelay = normalCycleTimeout, walkDelay = 8000;
clearLEDs();
// reassign parallel and perpendicular (street) pins to use single function
if (direction == 0) { // N/S button detected
parWHT = nsWHT;
parRED = nsRED;
parYEL = nsYEL;
parGRN = nsGRN;
perWHT = ewWHT;
perRED = ewRED;
perYEL = ewYEL;
perGRN = ewGRN;
} else { // E/W button detected
parWHT = ewWHT;
parRED = ewRED;
parYEL = ewYEL;
parGRN = ewGRN;
perWHT = nsWHT;
perRED = nsRED;
perYEL = nsYEL;
perGRN = nsGRN;
}
// warn all traffic
digitalWrite(parYEL, HIGH);
digitalWrite(perYEL, HIGH);
delay(cycleDelay);
// stop perpendicular traffic
digitalWrite(perYEL, LOW);
digitalWrite(perRED, HIGH);
// continue parallel traffic
digitalWrite(parGRN, HIGH);
digitalWrite(parYEL, LOW);
// start walk
digitalWrite(parWHT, HIGH);
delay(walkDelay);
// end walk
digitalWrite(parWHT, LOW);
// stop parallel traffic
digitalWrite(parGRN, LOW);
digitalWrite(parYEL, HIGH);
delay(cycleDelay);
}
// =================
// device functions
// =================
void initLEDs() {
for (int i = 0; i < ledpinSize; i++)
pinMode(ledpin[i], OUTPUT);
pinMode(LED_BUILTIN, OUTPUT);
}
void initButtons() {
for (int i = 0; i < buttonpinSize; i++)
pinMode(buttonpin[i], INPUT_PULLUP);
}
void clearLEDs() {
for (int i = 0; i < ledpinSize; i++)
digitalWrite(ledpin[i], LOW);
}
void readButtons() {
for (int button = 0; button < buttonpinSize; button++) {
if (digitalRead(buttonpin[button]) == 0) {
walkButtonPressed = 1;
direction = button;
}
}
}
// =================
// utility functions
// =================
void testButtons() {
for (int i = 0; i < buttonpinSize; i++) {
if (digitalRead(buttonpin[i]) == 0) {
digitalWrite(LED_BUILTIN, HIGH);
digitalWrite(nsWHT + i, HIGH);
} else {
digitalWrite(LED_BUILTIN, LOW);
digitalWrite(nsWHT + i, LOW);
}
}
}
void testLEDs(int dly) {
for (int i = 0; i < ledpinSize; i++) {
digitalWrite(ledpin[i], HIGH);
delay(dly);
// digitalWrite(ledpin[i], LOW);
}
for (int i = 0; i < ledpinSize; i++) {
digitalWrite(ledpin[i], LOW);
}
}
N
S
E
W