/*
Forum:
Wokwi: https://wokwi.com/projects/439250209557969921
2025/08/13
ec2021
Two signal lights synchronized by time
The signals are for cars and pedestrians moving in the same or opposite direction
* left: Car signals
* right: Pedestrian signals
The timing of both signal lights makes sure that signal A changes to YELLOWRED when both signals A and B are RED
"durationFinalRed" is the time where both signal lights are set to red before one of them changes to YELLOWRED
The pedestrian signal only shows green when the corresponding car signal is green, otherwise it shows red.
*/
constexpr unsigned long durationYellowRed {2000};
constexpr unsigned long durationYellow {4000};
constexpr unsigned long durationGreen {4000};
constexpr unsigned long durationFinalRed {2000};
constexpr unsigned long durationRed = durationYellowRed+durationYellow+durationGreen+durationFinalRed;
struct signalPins {
uint8_t Red;
uint8_t Yellow;
uint8_t Green;
};
enum signalState {RED,FINALRED, YELLOWRED, GREEN, YELLOW};
class SignalLightClass {
private:
signalPins carPin;
signalPins persPin;
signalState carState;
unsigned long startTime = 0;
unsigned long duration;
void handleState(boolean useStartTime) {
if (millis()-startTime > duration || !useStartTime){
startTime = millis();
switch (carState) {
case RED:
carState = FINALRED;
setSignal(HIGH, LOW, LOW, HIGH, LOW);
duration = durationFinalRed;
break;
case FINALRED:
carState = YELLOWRED;
setSignal(HIGH, HIGH, LOW, HIGH, LOW);
duration = durationYellowRed;
break;
case YELLOWRED:
carState = GREEN;
setSignal(LOW, LOW, HIGH, LOW, HIGH);
duration = durationGreen;
break;
case GREEN:
carState = YELLOW;
setSignal(LOW, HIGH, LOW, HIGH, LOW);
duration = durationYellow;
break;
case YELLOW:
carState = RED;
setSignal(HIGH, LOW, LOW, HIGH, LOW);
duration = durationRed;
break;
}
};
};
void setSignal(byte Red, byte Yellow, byte Green, byte pRed, byte pGreen) {
digitalWrite(carPin.Red, Red);
digitalWrite(carPin.Yellow, Yellow);
digitalWrite(carPin.Green, Green);
digitalWrite(persPin.Red, pRed);
digitalWrite(persPin.Green, pGreen);
};
public:
SignalLightClass(signalPins cPins, signalPins pPins) : carPin(cPins), persPin(pPins) {};
void init(signalState startState) {
pinMode(carPin.Red, OUTPUT);
pinMode(carPin.Yellow, OUTPUT);
pinMode(carPin.Green, OUTPUT);
pinMode(persPin.Red, OUTPUT);
pinMode(persPin.Green, OUTPUT);
switch (startState) {
case RED:
carState = YELLOW;
break;
case YELLOW:
carState = GREEN;
break;
case GREEN:
carState = YELLOWRED;
break;
case YELLOWRED:
carState = RED;
break;
}
handleState(false);
};
void run() {
handleState(true);
};
};
SignalLightClass signal1 = {{11, 12, 13}, {9, 0, 10}};
SignalLightClass signal2 = {{17, 16, 15}, {19, 0, 18}};
void setup() {
signal1.init(RED);
signal2.init(YELLOWRED);
}
void loop() {
signal1.run();
signal2.run();
}
Cars and Pedestrians moving North-to-South or South-to-North
Cars and Pedestrians moving East-to-West or West-to-East