#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <IRremote.h>
// --- PIN CONFIGURATION ---
const int PIN_RED = 12;
const int PIN_YELLOW = 11;
const int PIN_GREEN = 10;
const int PIN_BLUE = 6;
const int PIN_BUZZER = 5; // Siren
const int PIN_TRIG = 9;
const int PIN_ECHO = 8;
const int PIN_SWITCH = 4; // Signal Switch
const int PIN_IR = 7;
// --- OBJECTS ---
LiquidCrystal_I2C lcd(0x27, 16, 2);
// --- VARIABLES ---
enum TrafficMode { AUTO, FORCE_RED, FORCE_GREEN };
TrafficMode currentMode = AUTO;
bool wasActivePreviously = false;
// Timing Variables
unsigned long lastTrafficChange = 0;
unsigned long lastSirenChange = 0;
int autoState = 0;
int sirenState = LOW; // Beep State
// Durations
const int GREEN_DURATION = 1000;
const int YELLOW_DURATION = 500;
const int RED_DURATION = 1000;
void setup() {
pinMode(PIN_RED, OUTPUT);
pinMode(PIN_YELLOW, OUTPUT);
pinMode(PIN_GREEN, OUTPUT);
pinMode(PIN_BLUE, OUTPUT);
pinMode(PIN_BUZZER, OUTPUT);
pinMode(PIN_TRIG, OUTPUT);
pinMode(PIN_ECHO, INPUT);
pinMode(PIN_SWITCH, INPUT);
lcd.init();
lcd.backlight();
lcd.print("System Ready");
delay(1000);
lcd.clear();
IrReceiver.begin(PIN_IR, ENABLE_LED_FEEDBACK);
Serial.begin(9600);
}
void loop() {
// 1. READ SENSORS
long distance = readDistance();
bool signalActive = (digitalRead(PIN_SWITCH) == HIGH);
bool ambulanceClose = (distance < 100);
// 2. CHECK STATUS
bool systemActive = (signalActive && ambulanceClose);
// 3. HANDLE RESET (Connection/Disconnection)
if (systemActive != wasActivePreviously) {
if (systemActive) {
// CONNECTED: Blue Light ON, but SILENT waiting for command
digitalWrite(PIN_BLUE, HIGH);
currentMode = AUTO;
updateLCD("AMBULANCE MODE", "Waiting Cmd...");
IrReceiver.resume();
} else {
// DISCONNECTED: Everything OFF
digitalWrite(PIN_BLUE, LOW);
digitalWrite(PIN_BUZZER, LOW);
currentMode = AUTO;
updateLCD("NORMAL TRAFFIC", "Auto Cycle");
}
wasActivePreviously = systemActive;
}
// 4. ACTIVE BEHAVIOR
if (systemActive) {
// Check Remote
if (IrReceiver.decode()) {
int command = IrReceiver.decodedIRData.command;
if (command == 48) { // Button 1 -> STOP
currentMode = FORCE_RED;
updateLCD("AMBULANCE MODE", "CMD: STOP (RED)");
}
else if (command == 24) { // Button 2 -> GO
currentMode = FORCE_GREEN;
updateLCD("AMBULANCE MODE", "CMD: GO (GREEN)");
}
else if (command == 122) { // Button 3 -> RESUME
currentMode = AUTO;
updateLCD("AMBULANCE MODE", "CMD: RESUME");
}
IrReceiver.resume();
}
}
// 5. CONTROL OUTPUTS (Lights & Buzzer)
// LOGIC: Only sound buzzer if we are FORCING the lights
if (currentMode == FORCE_RED || currentMode == FORCE_GREEN) {
runSafeSiren(); // Beep!
if (currentMode == FORCE_RED) setLights(HIGH, LOW, LOW);
else setLights(LOW, LOW, HIGH);
}
else {
// Mode is AUTO (Silent)
digitalWrite(PIN_BUZZER, LOW); // Silence the buzzer
runAutoCycle();
}
}
// --- HELPER FUNCTIONS ---
// Safe digital beep that won't crash the remote
void runSafeSiren() {
unsigned long currentMillis = millis();
// Toggle sound ON/OFF every 300ms
if (currentMillis - lastSirenChange >= 300) {
lastSirenChange = currentMillis;
if (sirenState == LOW) {
sirenState = HIGH;
analogWrite(PIN_BUZZER, 127); // PWM ON (Creates a tone ~980Hz)
} else {
sirenState = LOW;
analogWrite(PIN_BUZZER, 0); // PWM OFF (Silence)
}
}
}
void updateLCD(String line1, String line2) {
lcd.clear();
lcd.setCursor(0,0);
lcd.print(line1);
lcd.setCursor(0,1);
lcd.print(line2);
}
void runAutoCycle() {
unsigned long currentMillis = millis();
switch (autoState) {
case 0: // GREEN
setLights(LOW, LOW, HIGH);
if (currentMillis - lastTrafficChange >= GREEN_DURATION) {
autoState = 1;
lastTrafficChange = currentMillis;
}
break;
case 1: // YELLOW
setLights(LOW, HIGH, LOW);
if (currentMillis - lastTrafficChange >= YELLOW_DURATION) {
autoState = 2;
lastTrafficChange = currentMillis;
}
break;
case 2: // RED
setLights(HIGH, LOW, LOW);
if (currentMillis - lastTrafficChange >= RED_DURATION) {
autoState = 0;
lastTrafficChange = currentMillis;
}
break;
}
}
void setLights(int r, int y, int g) {
digitalWrite(PIN_RED, r);
digitalWrite(PIN_YELLOW, y);
digitalWrite(PIN_GREEN, g);
}
long readDistance() {
digitalWrite(PIN_TRIG, LOW); delayMicroseconds(2);
digitalWrite(PIN_TRIG, HIGH); delayMicroseconds(10);
digitalWrite(PIN_TRIG, LOW);
return pulseIn(PIN_ECHO, HIGH) * 0.034 / 2;
}(click to edit)