// Traffic light simulation
//
// https://forum.arduino.cc/t/4-way-traffic-light-with-buttons/931477/12
// states of one trafic light
// by noiasca
// 2021-12-03
enum class Lightstate {RED, REDYELLOW, YELLOW, GREEN}; // for future use: YELLOWBLINK, GREENBLINK, BLACK ...
// the patterns to be shown on the crossing
Lightstate pattern[4][4]
{ // carsVertical carsHorizontal pedestrainVertical pedestrainHorizontal
{Lightstate::RED, Lightstate::GREEN, Lightstate::GREEN, Lightstate::RED}, // 0
{Lightstate::REDYELLOW, Lightstate::YELLOW, Lightstate::RED, Lightstate::RED}, // 1
{Lightstate::GREEN, Lightstate::RED, Lightstate::RED, Lightstate::GREEN}, // 2
{Lightstate::YELLOW, Lightstate::REDYELLOW, Lightstate::RED, Lightstate::RED} // 3
};
// one traffic light needs up to three pins:
struct Light {
const byte redPin;
const byte yellowPin;
const byte greenPin;
};
// lets create 4 traffic lights (in reality there might be 8, but left/right, up/down are the same currently
Light light[4] { // assign pins to the 4 lights:
{2, 3, 4}, // carsVertical
{4, 5, 6}, // carsHorizontal
{7, 255, 8}, // pedestrainVertical (255 - no LED connected)
{9, 255, 10} // pedestrainHorizontal
};
constexpr byte requestVerticalPin = A0; // pedestrain request
constexpr byte requestHorizontalPin = A1; // pedestrain request
const size_t noOfLights = sizeof(light) / sizeof(light[0]); // total number of (individual) traffic lights
const size_t noOfPatterns = sizeof(pattern) / sizeof(pattern[0]); // total number of traffic light pattern
uint32_t previousMillis = -5000; // time management
size_t currentPattern = 0; // actual state of crossing
void show(byte index, Lightstate lightstate) // helper function to output one traffic light
{
byte red = LOW , green = LOW, yellow = LOW;
switch (lightstate)
{
case Lightstate::RED :
red = HIGH;
break;
case Lightstate::REDYELLOW :
red = HIGH;
yellow = HIGH;
break;
case Lightstate::GREEN :
green = HIGH;
break;
case Lightstate::YELLOW :
yellow = HIGH;
break;
}
Serial.print(index); Serial.print(" "); Serial.print(" r"); Serial.print(red); Serial.print(" y"); Serial.print(yellow); Serial.print(" g"); Serial.println(green);
if (light[index].redPin < 255) digitalWrite(light[index].redPin, red);
if (light[index].greenPin < 255) digitalWrite(light[index].greenPin, green);
if (light[index].yellowPin < 255) digitalWrite(light[index].yellowPin, yellow);
}
void timerTraffic() // time management
{
if (millis() - previousMillis > 3000) {
previousMillis = millis();
if (++currentPattern >= noOfPatterns) currentPattern = 0;
setPattern(currentPattern);
}
}
void setPattern(byte newPattern) // set a new state / pattern for the crossing
{
currentPattern = newPattern;
previousMillis = millis();
Serial.print(F("currentPattern=")); Serial.println(currentPattern);
for (size_t i = 0; i < noOfLights; i++) show(i, pattern[currentPattern][i]); // activate the fitting pattern for each light
}
void readButton()
{
if (digitalRead(requestHorizontalPin) == LOW && currentPattern == 0) setPattern(1); // magic numbers ;-(
if (digitalRead(requestVerticalPin) == LOW && currentPattern == 2) setPattern(3); // magic numbers ;-(
}
void setup(void)
{
Serial.begin(115200);
pinMode(requestHorizontalPin, INPUT_PULLUP);
pinMode(requestVerticalPin, INPUT_PULLUP);
for (size_t i = 0; i < noOfLights; i++) {
if (light[i].redPin < 255) pinMode(light[i].redPin, OUTPUT);
if (light[i].yellowPin < 255) pinMode(light[i].yellowPin, OUTPUT);
if (light[i].greenPin < 255) pinMode(light[i].greenPin, OUTPUT);
show(i, Lightstate::YELLOW);
}
}
void loop(void)
{
timerTraffic();
readButton();
}