/*
Arduino Traffic Light Rev 5
Anon Engineering
July 2021
Thanks to AllDigitsMatter, excsniper, and Mindaugas at Discord|Arduino|#coding-help for their suggestions.
For more on timing things without using delay:
https://www.arduino.cc/en/Tutorial/BuiltInExamples/BlinkWithoutDelay
For more on using button states see:
https://www.kasperkamperman.com/blog/arduino/arduino-programming-state-change/
On Wokwi: https://wokwi.com/projects/344621463002677843
Memory usage:
//Without Serial 1.6K flash, 78 bytes SRAM
//With Serial 3.1K flash, 259 bytes SRAM
*/
// Constants
// LED pins, a pair of Red, Yellow, and Green LEDs for "North & South",
// another set of pairs for "East & West". (Two LEDs and resistors per pin.)
const byte NS_RED_PIN = 12; const byte NS_YEL_PIN = 11; const byte NS_GRN_PIN = 10;
const byte EW_RED_PIN = 8; const byte EW_YEL_PIN = 7; const byte EW_GRN_PIN = 6;
// Crosswalk buttons
const byte NS_BTN_PIN = 9;
const byte EW_BTN_PIN = 5;
// Optional buzzer (not implemented here)
//const byte buzzer = 5;
// State constants
const byte NUM_STATES = 6; // States = 0 to 5, (6 total)
// State delay array, NS go, NS caution, All stop, EW go, EW caution, All stop
const long STATE_DELAY[NUM_STATES] = {10000, 3000, 1000, 10000, 3000, 1000};
// Light array
const bool LIGHT_ARR[][NUM_STATES] = {
{false, false, true, true, false, false},
{false, false, true, false, true, false},
{false, false, true, false, false, true},
{true, false, false, false, false, true},
{false, true, false, false, false, true},
{false, false, true, false, false, true}
};
// Globals
// Stores state variable
byte currState = 0;
// Stores last time state changed
unsigned long lastMillis = 0;
// Flags for pedestrian requests
bool nsFlag = false;
bool ewFlag = false;
void checkButtons() {
// Button handling bools
static bool btnNSState = 0;
static bool lastNSBtnState = 0;
static bool btnEWState = 0;
static bool lastEWBtnState = 0;
// Read the NS pedestrian pushbutton input pin
btnNSState = digitalRead(NS_BTN_PIN);
// check if the button is pressed or released
// by comparing the buttonState to its previous state
if (btnNSState != lastNSBtnState) {
// increment the currState on button press
if (btnNSState == 0) {
Serial.println(F("EW Crosswalk request!"));
nsFlag = true;
}
// remember the current state of the button
lastNSBtnState = btnNSState;
}
// add a small debounce delay
delay(20);
// Read the EW pedestrian pushbutton input pin
btnEWState = digitalRead(EW_BTN_PIN);
// check if the button is pressed or released
// by comparing the buttonState to its previous state
if (btnEWState != lastEWBtnState) {
// increment the currState on button press
if (btnEWState == 0) {
Serial.println(F("NS Crosswalk request!"));
ewFlag = true;
}
// remember the current state of the button
lastEWBtnState = btnEWState;
}
// add a small debounce delay
delay(20);
}
void checkFlags() { //, unsigned long lastTime, byte currentState, bool nFlag, bool eFlag) {
// Handle pedestrian flags
// If nsFlag is set and NS traffic isn't already allowed
if (nsFlag && (currState != 0 && currState != 1)) {
currState = 4; // Set EW to caution and continue
lastMillis = millis(); // Reset delay time
}
nsFlag = false; // Always set false, either the mode changed or didn't need to
// If ewFlag is set and EW traffic isn't already allowed
if (ewFlag && (currState != 2 && currState != 3)) {
currState = 1; // Set NS to caution and continue
lastMillis = millis(); // Reset delay time
}
ewFlag = false; // Always set false, either the mode changed or didn't need to
}
void setLights() {
// Set all six lights according to the current state
digitalWrite(NS_GRN_PIN, LIGHT_ARR[currState][0]);
digitalWrite(NS_YEL_PIN, LIGHT_ARR[currState][1]);
digitalWrite(NS_RED_PIN, LIGHT_ARR[currState][2]);
digitalWrite(EW_GRN_PIN, LIGHT_ARR[currState][3]);
digitalWrite(EW_YEL_PIN, LIGHT_ARR[currState][4]);
digitalWrite(EW_RED_PIN, LIGHT_ARR[currState][5]);
}
void setState() {
// Increment the state of the traffic light
// Using an array to avoid code block repetition
for (byte i = 0; i < NUM_STATES; i++) {
// Iterate through all the states
if (currState == i) {
if (millis() - lastMillis >= STATE_DELAY[i]) {
// Update lastMillis & state.
lastMillis = millis();
currState++;
// Reset state to starting point if at the end
if (currState >= NUM_STATES) currState = 0;
Serial.print(F("State "));
Serial.println(currState + 1); // +1 so it prints 1 - 6
}
}
}
}
void setup() {
Serial.begin(115200);
// Set pinModes
pinMode(NS_BTN_PIN, INPUT_PULLUP); pinMode(EW_BTN_PIN, INPUT_PULLUP);
pinMode(NS_GRN_PIN, OUTPUT); pinMode(NS_YEL_PIN, OUTPUT); pinMode(NS_RED_PIN, OUTPUT);
pinMode(EW_GRN_PIN, OUTPUT); pinMode(EW_YEL_PIN, OUTPUT); pinMode(EW_RED_PIN, OUTPUT);
//pinMode(buzzer, OUTPUT);
// Startup message
Serial.println(F("Starting, drive carefully..."));
Serial.print(F("State "));
Serial.println(currState + 1); // Print state + 1 (for fun, instead of 0)
}
void loop() {
// These functions run continuously and quickly (about every 40mS)
checkButtons();
checkFlags();
setLights();
setState();
}
North/South
East/West Cross
East/West
North/South Cross