/*
Interview project for Lexington Medical
Prepared 2025-10-27
STM32 Arduino Core (stm32duino)
Specification:
1. With no use of the crosswalk button the traffic lights should cycle between
red/yellow/green per the following sequence:
13 seconds: Mass Ave Green, Beacon St Red
2 seconds: Mass Ave Yellow, Beacon St Red
13 seconds: Mass Ave Red, Beacon St Green
2 seconds: Mass Ave Red, Beacon St Yellow
2. If ever both traffic lights are red, pedestrian light can be green,
otherwise pedestrian light should be red.
3. If the crosswalk button is pressed then whichever traffic light is
currently green (or yellow) should transition if needed to the yellow
state and then after finishing the 2 second yellow state, both traffic
lights should be red for 20 seconds before resuming green on whichever
traffic light holds the longest elapsed time since last being green.
4. Once the crosswalk button has been pressed, further presses should be
queued until one full cycle has finished (meaning 20 seconds for the
pedestrian cycle and 60 seconds for one full traffic cycle).
For reference guides see https://docs.wokwi.com/
*/
extern "C" {
#include "traffic_ctrl.h"
}
// Pin map per diagram.json
constexpr uint8_t PIN_MASS_AVE_RED = A0;
constexpr uint8_t PIN_MASS_AVE_YELLOW = A1;
constexpr uint8_t PIN_MASS_AVE_GREEN = A2;
constexpr uint8_t PIN_BEACON_ST_RED = A5;
constexpr uint8_t PIN_BEACON_ST_YELLOW = A6;
constexpr uint8_t PIN_BEACON_ST_GREEN = A7;
constexpr uint8_t PIN_MASS_AVE_PED_RED = A3;
constexpr uint8_t PIN_MASS_AVE_PED_GREEN = A4;
constexpr uint8_t PIN_BEACON_ST_PED_GREEN = PB5;
constexpr uint8_t PIN_BEACON_ST_PED_RED = PB6;
constexpr uint8_t PIN_BEACON_ST_LEFT_ARROW = PB7;
constexpr uint8_t PIN_BTN = PB0; // active-low, use pull-up
constexpr uint8_t PIN_ERR_SWITCH = PA10; // active-low, use pull-up
// Enums to set light colors for each signal legibly
enum SIGNAL {mass_car, beacon_car, mass_ped, beacon_ped};
enum COLOR {red, yellow, green, green_arrow, off};
void setLight(SIGNAL sig, COLOR col) {
// Set signal sig to light color col
switch(sig) {
case mass_car:
switch(col) {
case red:
digitalWrite(PIN_MASS_AVE_RED, HIGH);
digitalWrite(PIN_MASS_AVE_YELLOW, LOW);
digitalWrite(PIN_MASS_AVE_GREEN, LOW);
break;
case yellow:
digitalWrite(PIN_MASS_AVE_RED, LOW);
digitalWrite(PIN_MASS_AVE_YELLOW, HIGH);
digitalWrite(PIN_MASS_AVE_GREEN, LOW);
break;
case green:
digitalWrite(PIN_MASS_AVE_RED, LOW);
digitalWrite(PIN_MASS_AVE_YELLOW, LOW);
digitalWrite(PIN_MASS_AVE_GREEN, HIGH);
break;
case green_arrow:
// No green arrow signal on Mass Ave
break;
case off:
digitalWrite(PIN_MASS_AVE_RED, LOW);
digitalWrite(PIN_MASS_AVE_YELLOW, LOW);
digitalWrite(PIN_MASS_AVE_GREEN, LOW);
break;
default:
break;
}
break;
case beacon_car:
switch(col) {
case red:
digitalWrite(PIN_BEACON_ST_RED, HIGH);
digitalWrite(PIN_BEACON_ST_YELLOW, LOW);
digitalWrite(PIN_BEACON_ST_GREEN, LOW);
digitalWrite(PIN_BEACON_ST_LEFT_ARROW, LOW);
break;
case yellow:
digitalWrite(PIN_BEACON_ST_RED, LOW);
digitalWrite(PIN_BEACON_ST_YELLOW, HIGH);
digitalWrite(PIN_BEACON_ST_GREEN, LOW);
digitalWrite(PIN_BEACON_ST_LEFT_ARROW, LOW);
break;
case green:
digitalWrite(PIN_BEACON_ST_RED, LOW);
digitalWrite(PIN_BEACON_ST_YELLOW, LOW);
digitalWrite(PIN_BEACON_ST_GREEN, HIGH);
digitalWrite(PIN_BEACON_ST_LEFT_ARROW, LOW);
break;
case green_arrow:
digitalWrite(PIN_BEACON_ST_RED, HIGH);
digitalWrite(PIN_BEACON_ST_YELLOW, LOW);
digitalWrite(PIN_BEACON_ST_GREEN, LOW);
digitalWrite(PIN_BEACON_ST_LEFT_ARROW, HIGH);
break;
case off:
digitalWrite(PIN_BEACON_ST_RED, LOW);
digitalWrite(PIN_BEACON_ST_YELLOW, LOW);
digitalWrite(PIN_BEACON_ST_GREEN, LOW);
digitalWrite(PIN_BEACON_ST_LEFT_ARROW, LOW);
break;
default:
break;
}
break;
case mass_ped:
switch(col) {
case red:
digitalWrite(PIN_MASS_AVE_PED_RED, HIGH);
digitalWrite(PIN_MASS_AVE_PED_GREEN, LOW);
break;
case yellow:
// No yellow light for pedestrians
break;
case green:
digitalWrite(PIN_MASS_AVE_PED_RED, LOW);
digitalWrite(PIN_MASS_AVE_PED_GREEN, HIGH);
break;
case green_arrow:
// No green arrow for pedestrians
break;
case off:
digitalWrite(PIN_MASS_AVE_PED_RED, LOW);
digitalWrite(PIN_MASS_AVE_PED_GREEN, LOW);
break;
default:
break;
}
break;
case beacon_ped:
switch(col) {
case red:
digitalWrite(PIN_BEACON_ST_PED_RED, HIGH);
digitalWrite(PIN_BEACON_ST_PED_GREEN, LOW);
break;
case yellow:
// No yellow light for pedestrians
break;
case green:
digitalWrite(PIN_BEACON_ST_PED_RED, LOW);
digitalWrite(PIN_BEACON_ST_PED_GREEN, HIGH);
break;
case green_arrow:
// No green arrow for pedestrians
break;
case off:
digitalWrite(PIN_BEACON_ST_PED_RED, LOW);
digitalWrite(PIN_BEACON_ST_PED_GREEN, LOW);
break;
default:
break;
}
break;
default:
break;
}
}
void updateLights(LIGHTSTATE lstate) {
// Update LED values according to current state
// Always set reds first for safety
switch(lstate) {
case MGBR:
setLight(beacon_car, red);
setLight(mass_ped, red);
setLight(mass_car, green);
setLight(beacon_ped, green);
break;
case MYBR:
setLight(beacon_ped, red);
setLight(mass_car, yellow);
break;
case MRBG:
setLight(mass_car, red);
setLight(beacon_ped, red);
setLight(beacon_car, green);
setLight(mass_ped, green);
break;
case MRBG_PL:
setLight(mass_car, red);
setLight(mass_ped, red);
setLight(beacon_ped, red);
setLight(beacon_car, green_arrow);
break;
case MRBY:
setLight(mass_ped, red);
setLight(beacon_car, yellow);
break;
case MRBR:
setLight(mass_car, red);
setLight(beacon_car, red);
setLight(mass_ped, green);
setLight(beacon_ped, green);
break;
case ERROR_STOP1:
setLight(mass_car, red);
setLight(beacon_car, off);
setLight(mass_ped, red);
setLight(beacon_ped, red);
break;
case ERROR_STOP2:
setLight(mass_car, off);
setLight(beacon_car, red);
setLight(mass_ped, red);
setLight(beacon_ped, red);
break;
default:
break;
}
}
void setup() {
pinMode(PIN_MASS_AVE_RED, OUTPUT);
pinMode(PIN_MASS_AVE_YELLOW, OUTPUT);
pinMode(PIN_MASS_AVE_GREEN, OUTPUT);
pinMode(PIN_BEACON_ST_RED, OUTPUT);
pinMode(PIN_BEACON_ST_YELLOW, OUTPUT);
pinMode(PIN_BEACON_ST_GREEN, OUTPUT);
pinMode(PIN_MASS_AVE_PED_RED, OUTPUT);
pinMode(PIN_MASS_AVE_PED_GREEN, OUTPUT);
pinMode(PIN_BEACON_ST_PED_RED, OUTPUT);
pinMode(PIN_BEACON_ST_PED_GREEN, OUTPUT);
pinMode(PIN_BEACON_ST_LEFT_ARROW, OUTPUT);
pinMode(PIN_BTN, INPUT_PULLUP); // active-low
pinMode(PIN_ERR_SWITCH, INPUT_PULLUP); // active-low
Serial.begin(115200);
Serial.println("BOOT: dual-road TL controller");
// No additional one-time setup needed in this file
}
void loop() {
// Call periodic functions on traffic controller code
trafficUpdate(!digitalRead(PIN_BTN), !digitalRead(PIN_ERR_SWITCH), millis());
updateLights(getTrafficState());
}
Loading
stm32-bluepill
stm32-bluepill