Project 1: Traffic Light Controller

This project is an Arduino-based traffic light control system for a two-way North-South and East-West intersection. It includes vehicle lights, pedestrian crossing lights, buttons, a buzzer, and timing controlled with millis().

Project Video

Download Files

Code Preview

#include <stdio.h>
// Title: Traffic Light Controller
// Author: Ashot Nahapetyan
// Instructors: Narine Hovhannisyan, Satenik Mnatsakanyan
// Course: ENGS110 Intro to Programming
// SPRING 2026

// Defining pins on the Arduino
#define NS_PIN_RED 2
#define NS_PIN_YELLOW 3
#define NS_PIN_GREEN 4
#define EW_PIN_RED 5
#define EW_PIN_YELLOW 6
#define EW_PIN_GREEN 7
#define PED_NS_RED 11
#define PED_NS_GREEN 10
#define PED_EW_RED 9
#define PED_EW_GREEN 8
#define BUZZER A1
#define BTN_NS A2
#define BTN_EW A3

// Timing configurations
#define GREEN_TIME 5000
#define YELLOW_TIME 3000
#define BLINK_TIME 400
#define SAFETY_GAP 0 //change this if you want to add a safety gap
#define PED_TIME 5000
#define PED_WARN_TIME 1500
#define PED_FLASH_RATE 250
#define BUZZ_WAIT_FREQ 880
#define BUZZ_WALK_FREQ 2500

// Custom "State" type storing the current phase as a state, each all red state behaves different
enum State {
  NS_GREEN,
  NS_YELLOW,
  ALL_RED1, 
  PED_NS,
  PED_EW,
  ALL_RED2,
  EW_GREEN,
  EW_YELLOW,
  ALL_RED3
};

State currState = NS_GREEN;
unsigned long stateStart = 0;
// button press flags
bool btnNS = false;
bool btnEW = false;

// vehicle lights
void setNS(bool r, bool y, bool g) {
  digitalWrite(NS_PIN_RED, r ? HIGH : LOW);
  digitalWrite(NS_PIN_YELLOW, y ? HIGH : LOW);
  digitalWrite(NS_PIN_GREEN, g ? HIGH : LOW);
}
void setEW(bool r, bool y, bool g) {
  digitalWrite(EW_PIN_RED, r ? HIGH : LOW);
  digitalWrite(EW_PIN_YELLOW, y ? HIGH : LOW);
  digitalWrite(EW_PIN_GREEN, g ? HIGH : LOW);
}
// both sides red
void setAllRed() {
  setNS(true, false, false);
  setEW(true, false, false);
}

// pedestrian lights
void pedNS_stop() {
  digitalWrite(PED_NS_RED, HIGH);
  digitalWrite(PED_NS_GREEN, LOW);
}
void pedNS_go() {
  digitalWrite(PED_NS_RED, LOW);
  digitalWrite(PED_NS_GREEN, HIGH);
}
void pedNS_SetGreen(bool on) {
  digitalWrite(PED_NS_GREEN, on ? HIGH : LOW);
  digitalWrite(PED_NS_RED, LOW);
}
void pedEW_stop() {
  digitalWrite(PED_EW_RED, HIGH);
  digitalWrite(PED_EW_GREEN, LOW);
}
void pedEW_go() {
  digitalWrite(PED_EW_RED, LOW);
  digitalWrite(PED_EW_GREEN, HIGH);
}
void pedEW_SetGreen(bool on) {
  digitalWrite(PED_EW_GREEN, on ? HIGH : LOW);
  digitalWrite(PED_EW_RED, LOW);
}

void allPedStop() {
  pedNS_stop();
  pedEW_stop();
}


// program core
void changeState(State state) {
  currState = state;
  stateStart = millis();
  switch (state) {
    case NS_GREEN:
      setNS(false, false, true);
      setEW(true,  false, false);
      allPedStop();
      break;

    case NS_YELLOW:
      setNS(false, true, true);
      setEW(true,  false, false);
      allPedStop();
      break;

    case ALL_RED1:
    case ALL_RED2:
    case ALL_RED3:
      setAllRed();
      noTone(BUZZER);
      allPedStop();
      break;

    case PED_NS:
      setAllRed();
      pedNS_go();
      pedEW_stop();
      break;

    case PED_EW:
      setAllRed();
      pedNS_stop();
      pedEW_go();
      break;

    case EW_GREEN:
      setNS(true,  false, false);
      setEW(false, false, true);
      allPedStop();
      break;

    case EW_YELLOW:
      setNS(true,  false, false);
      setEW(false, true,  true);
      allPedStop();
      break;
  }
}

void readButtons() {
  if (digitalRead(BTN_NS) == LOW) btnNS = true;
  if (digitalRead(BTN_EW) == LOW) btnEW = true;
}

void pedestrianPhase(bool isNS) {
  unsigned long elapsed = millis() - stateStart;
  unsigned long remaining = (elapsed < PED_TIME) ? (PED_TIME - elapsed) : 0;
  
  bool inWarning = (remaining > 0 && remaining <= PED_WARN_TIME);

  if (inWarning) {
    unsigned long warningElapsed = PED_WARN_TIME - remaining;
    bool greenOn = (warningElapsed / PED_FLASH_RATE) % 2 == 0;

    if (isNS) {
      pedNS_SetGreen(greenOn);
    } else {
      pedEW_SetGreen(greenOn);
    }
    
    if (greenOn) {
      tone(BUZZER, BUZZ_WALK_FREQ);
    } else {
      noTone(BUZZER);
    }

  } else if (remaining > 0) {
  
    if (isNS) {
      pedNS_go();
    } else {
    pedEW_go();
    }

    bool buzzOn = (elapsed % 200) < 100;
    if (buzzOn) {
      tone(BUZZER, BUZZ_WALK_FREQ);
    } else {
      noTone(BUZZER);
    }

  } else {

    if (isNS) {
      pedNS_stop();
    } else {
      pedEW_stop();
    }
    noTone(BUZZER);
  }
}

void launchtest() {
  setNS(true, false, false);
  setEW(true, false, false);
  delay(500);
  setNS(false, true, false);
  setEW(false, true, false);
  delay(500);
  setNS(false, false, true);
  setEW(false, false, true);
  delay(500);
  setNS(false, false, false);
  setEW(false, false, false);
  pedNS_go(); pedEW_go();
  delay(500);
  pedNS_stop(); pedEW_stop();
  delay(500);
  tone(BUZZER, 880,  150); delay(200);
  tone(BUZZER, 1200, 150); delay(200);
  tone(BUZZER, 2500, 150); delay(250);
  tone(BUZZER, 600, 150); delay(200);
  noTone(BUZZER);
  delay(500);
}
void yellowFlash(int pin) {
  unsigned long now = millis();
  unsigned long interval = now - stateStart;
  bool on = (interval / BLINK_TIME) % 2 == 0;
  digitalWrite(pin, on ? HIGH : LOW);

  if (on) {
    tone(BUZZER, BUZZ_WAIT_FREQ);
  } else {
    noTone(BUZZER);
  }
}

void setup() {
  pinMode(NS_PIN_RED, OUTPUT);
  pinMode(NS_PIN_YELLOW, OUTPUT);
  pinMode(NS_PIN_GREEN, OUTPUT);
  pinMode(EW_PIN_RED, OUTPUT);
  pinMode(EW_PIN_YELLOW, OUTPUT);
  pinMode(EW_PIN_GREEN, OUTPUT);
  pinMode(PED_NS_RED, OUTPUT);
  pinMode(PED_NS_GREEN, OUTPUT);
  pinMode(PED_EW_RED, OUTPUT);
  pinMode(PED_EW_GREEN, OUTPUT);
  pinMode(BUZZER, OUTPUT);
  pinMode(BTN_NS, INPUT_PULLUP);
  pinMode(BTN_EW, INPUT_PULLUP);
  // does these below before starting the main loop
  launchtest();
  allPedStop();
  changeState(NS_GREEN);
}

// program loop
void loop() {
  readButtons();
  unsigned long now = millis();
  unsigned long elapsed = now - stateStart;
  switch (currState) {
    case NS_GREEN:
      if (elapsed >= GREEN_TIME) {
        changeState(NS_YELLOW);
      }
      break;

    case NS_YELLOW:
      yellowFlash(NS_PIN_YELLOW);
      yellowFlash(EW_PIN_YELLOW);
      if (elapsed >= YELLOW_TIME) {
        digitalWrite(NS_PIN_YELLOW, LOW);
        changeState(ALL_RED1);
      }
    break;

    case ALL_RED1:
      if (elapsed >= SAFETY_GAP) {
        if (btnNS) {
          btnNS = false; 
          changeState(PED_NS);
        } else if (btnEW) {
          btnEW = false;
          changeState(PED_EW);
        } else {
          changeState(EW_GREEN);
        }
      }
      break;

    case PED_NS:
      pedestrianPhase(true);
      if (elapsed >= PED_TIME) {
        noTone(BUZZER);
        pedNS_stop();
        if (btnEW) {
          btnEW = false;
          changeState(PED_EW);
        } else {
          changeState(ALL_RED2);
        }
      }
      break;

    case PED_EW:
      pedestrianPhase(false);
      if (elapsed >= PED_TIME) {
        noTone(BUZZER);
        pedEW_stop();
        changeState(ALL_RED2);
        if (btnNS) {
          btnNS = false;
          changeState(PED_NS);
        } else {
          changeState(ALL_RED2);
        }
      }
      break;

    case ALL_RED2:
      if (elapsed >= SAFETY_GAP) {
        changeState(EW_GREEN);
      }
      break;
    
    case EW_GREEN:
      if (elapsed >= GREEN_TIME) {
        changeState(EW_YELLOW);
      }
      break;

    case EW_YELLOW:
      yellowFlash(EW_PIN_YELLOW);
      yellowFlash(NS_PIN_YELLOW);
      if (elapsed >= YELLOW_TIME) {
        noTone(BUZZER);
        digitalWrite(EW_PIN_YELLOW, LOW);
        changeState(ALL_RED3);
      }
      break;

    case ALL_RED3:
      if (elapsed >= SAFETY_GAP) {
        if (btnEW) {
          btnEW = false;
          changeState(PED_EW);
        } else if (btnNS) {
          btnNS = false;
          changeState(PED_NS);
        } else {
          changeState(NS_GREEN);
        }
      }
      break;
  }
}

}