Built-in project · ESP32 DevKit V1

ESP32 traffic emergency system with RFID

Three roads’ lights take turns on an ESP32. Click the white card beside a road’s MFRC522 reader: that road gets green for 8 s and the others red. The whole build, an ESP32 DevKit and 21 more parts, runs here in your browser on the firmware below; open it in the editor to change the wiring or the code and run it again.

Teaching? Assign it to your class in one click.

Intermediate Runs in your browser. Free, and no account needed.

The parts retail for about $29. On Mokxi they're free.

ESP32 traffic emergency system with RFID · ESP32 DevKit V1live0.000 s 0.00x
Click to open it in the editor
The circuit itself, running here on the simulator. Press what can be pressed; click anything else to open it in the editor.

The code

The firmware exactly as the editor opens it. Change a line there and press Run: it compiles in the browser.

sketch.ino · ESP32 DevKit V1
// Traffic emergency system: an ESP32 runs a junction of three roads.
//
// Each road has a red, yellow and green LED (pin -> 220 ohm -> LED -> GND)
// and its own MFRC522 RFID reader. The lights take turns on their own:
// green 5 s, yellow 2 s, then the next road. When an emergency tag is tapped
// on a road's reader, that road gets green for 8 seconds and the other two
// turn red; then that road goes yellow and the cycle carries on.
//
// The three readers share the SPI bus (SCK 18, MOSI 23, MISO 19) and one
// reset line on 22. Each has its own SDA (chip select): 5, 16 and 17. Only
// the selected reader drives MISO, so they take turns on the one wire.
//
// The timing runs on millis(), never delay(), so the readers are polled all
// the time and a tag is seen the moment it is tapped.
//
// In Mokxi: press Run, then click a card in the tray beside a reader to lay
// it on that reader, and click it again to lift it off. The white card and
// the blue fob are emergency tags; the other two are printed and ignored.

#include <SPI.h>
#include <MFRC522.h>

const byte RST_PIN = 22;
const byte SS_PINS[3] = {5, 16, 17};

MFRC522 readers[3] = {
  MFRC522(SS_PINS[0], RST_PIN),
  MFRC522(SS_PINS[1], RST_PIN),
  MFRC522(SS_PINS[2], RST_PIN),
};

//                        red  yellow green
const byte LIGHTS[3][3] = {{13, 14, 27},   // road 1
                           {26, 25, 33},   // road 2
                           {32, 21, 4}};   // road 3
const byte RED = 0, YELLOW = 1, GREEN = 2;

const unsigned long GREEN_MS = 5000;
const unsigned long YELLOW_MS = 2000;
const unsigned long EMERGENCY_MS = 8000;

// The tags that count as emergency vehicles. Tap any other card and its UID
// is printed, so a new tag can be copied into this list.
const byte EMERGENCY_TAGS[][4] = {
  {0xC3, 0x5A, 0x1E, 0x94},
  {0x7B, 0x02, 0xD4, 0x19},
};
const byte EMERGENCY_COUNT = sizeof(EMERGENCY_TAGS) / sizeof(EMERGENCY_TAGS[0]);

byte road = 0;                 // the road that has right of way
byte phase = GREEN;            // GREEN or YELLOW for that road
bool emergency = false;
unsigned long phaseStart = 0;

void show() {
  for (byte r = 0; r < 3; r++) {
    byte lit = (r == road) ? phase : RED;
    for (byte c = 0; c < 3; c++) digitalWrite(LIGHTS[r][c], c == lit ? HIGH : LOW);
  }
}

void enter(byte newRoad, byte newPhase) {
  road = newRoad;
  phase = newPhase;
  phaseStart = millis();
  show();
  Serial.print("Road ");
  Serial.print(road + 1);
  Serial.println(phase == GREEN ? (emergency ? ": GREEN (emergency)" : ": GREEN") : ": YELLOW");
}

bool isEmergencyTag(const MFRC522::Uid &uid) {
  if (uid.size != 4) return false;
  for (byte t = 0; t < EMERGENCY_COUNT; t++) {
    if (memcmp(uid.uidByte, EMERGENCY_TAGS[t], 4) == 0) return true;
  }
  return false;
}

void printUid(const MFRC522::Uid &uid) {
  for (byte i = 0; i < uid.size; i++) {
    Serial.print(uid.uidByte[i] < 0x10 ? " 0" : " ");
    Serial.print(uid.uidByte[i], HEX);
  }
}

void checkReaders() {
  for (byte r = 0; r < 3; r++) {
    MFRC522 &reader = readers[r];
    if (!reader.PICC_IsNewCardPresent() || !reader.PICC_ReadCardSerial()) continue;
    Serial.print("Reader ");
    Serial.print(r + 1);
    Serial.print(": tag");
    printUid(reader.uid);
    if (isEmergencyTag(reader.uid)) {
      Serial.println(" - EMERGENCY");
      emergency = true;
      enter(r, GREEN);
    } else {
      Serial.println(" - not an emergency tag");
    }
    reader.PICC_HaltA();   // read a tag once per tap, not once a loop
  }
}

void setup() {
  Serial.begin(115200);
  for (byte r = 0; r < 3; r++) {
    for (byte c = 0; c < 3; c++) pinMode(LIGHTS[r][c], OUTPUT);
  }
  SPI.begin();   // SCK 18, MISO 19, MOSI 23
  for (byte r = 0; r < 3; r++) {
    readers[r].PCD_Init();
    Serial.print("Reader ");
    Serial.print(r + 1);
    Serial.print(" on SS ");
    Serial.print(SS_PINS[r]);
    Serial.print(": version 0x");
    Serial.println(readers[r].PCD_ReadRegister(MFRC522::VersionReg), HEX);
  }
  Serial.println("Traffic emergency system ready: tap an emergency tag on a road's reader");
  enter(0, GREEN);
}

void loop() {
  checkReaders();

  unsigned long elapsed = millis() - phaseStart;
  if (emergency) {
    if (elapsed >= EMERGENCY_MS) {
      emergency = false;
      Serial.println("Emergency over, normal cycle resumes");
      enter(road, YELLOW);
    }
  } else if (phase == GREEN && elapsed >= GREEN_MS) {
    enter(road, YELLOW);
  } else if (phase == YELLOW && elapsed >= YELLOW_MS) {
    enter((road + 1) % 3, GREEN);
  }
}

Parts list

24 parts, plus the jumper wires. They retail for about $29; on Mokxi they're free.

How it is wired

27 connections, pin by pin, read from the circuit itself. Each line is one set of pins joined together, by a jumper wire or a breadboard strip.

  • ESP32 DevKit V1 pin D32; Resistor, 220 Ω (7) pin 1
  • ESP32 DevKit V1 pin D33; Resistor, 220 Ω (6) pin 1
  • ESP32 DevKit V1 pin D25; Resistor, 220 Ω (5) pin 1
  • ESP32 DevKit V1 pin D26; Resistor, 220 Ω (4) pin 1
  • ESP32 DevKit V1 pin D27; Resistor, 220 Ω (3) pin 1
  • ESP32 DevKit V1 pin D14; Resistor, 220 Ω (2) pin 1
  • Ground: ESP32 DevKit V1 pin GND; RFID reader, MFRC522 (1) pin GND; RFID reader, MFRC522 (2) pin GND; RFID reader, MFRC522 (3) pin GND; LED, red (1) pin C; LED, yellow (1) pin C; LED, green (1) pin C; LED, red (2) pin C; LED, yellow (2) pin C; LED, green (2) pin C; LED, red (3) pin C; LED, yellow (3) pin C; LED, green (3) pin C
  • ESP32 DevKit V1 pin D13; Resistor, 220 Ω (1) pin 1
  • ESP32 DevKit V1 pin D23; RFID reader, MFRC522 (1) pin MOSI; RFID reader, MFRC522 (2) pin MOSI; RFID reader, MFRC522 (3) pin MOSI
  • ESP32 DevKit V1 pin D22; RFID reader, MFRC522 (1) pin RST; RFID reader, MFRC522 (2) pin RST; RFID reader, MFRC522 (3) pin RST
  • ESP32 DevKit V1 pin D21; Resistor, 220 Ω (8) pin 1
  • ESP32 DevKit V1 pin D19; RFID reader, MFRC522 (1) pin MISO; RFID reader, MFRC522 (2) pin MISO; RFID reader, MFRC522 (3) pin MISO
  • ESP32 DevKit V1 pin D18; RFID reader, MFRC522 (1) pin SCK; RFID reader, MFRC522 (2) pin SCK; RFID reader, MFRC522 (3) pin SCK
  • ESP32 DevKit V1 pin D5; RFID reader, MFRC522 (1) pin SDA
  • ESP32 DevKit V1 pin TX2; RFID reader, MFRC522 (3) pin SDA
  • ESP32 DevKit V1 pin RX2; RFID reader, MFRC522 (2) pin SDA
  • ESP32 DevKit V1 pin D4; Resistor, 220 Ω (9) pin 1
  • ESP32 DevKit V1 pin 3V3; RFID reader, MFRC522 (1) pin 3.3V; RFID reader, MFRC522 (2) pin 3.3V; RFID reader, MFRC522 (3) pin 3.3V
  • Resistor, 220 Ω (1) pin 2; LED, red (1) pin A
  • Resistor, 220 Ω (2) pin 2; LED, yellow (1) pin A
  • Resistor, 220 Ω (3) pin 2; LED, green (1) pin A
  • Resistor, 220 Ω (4) pin 2; LED, red (2) pin A
  • Resistor, 220 Ω (5) pin 2; LED, yellow (2) pin A
  • Resistor, 220 Ω (6) pin 2; LED, green (2) pin A
  • Resistor, 220 Ω (7) pin 2; LED, red (3) pin A
  • Resistor, 220 Ω (8) pin 2; LED, yellow (3) pin A
  • Resistor, 220 Ω (9) pin 2; LED, green (3) pin A

Change it and keep it

Open it in the editor, change the circuit or the code, and keep your version in a free account.