#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <RTClib.h>
#define ERROR_PIN 2
#define I2C_LIGHTS_CONTROLLER_NS 0x10
#define I2C_LIGHTS_CONTROLLER_WE 0x11
#define I2C_DISPLAY_NS 0x20
#define I2C_DISPLAY_WE 0x21
#define BUZZER_NS 4
#define BUZZER_WE 3
#define SENSOR_CAR_NS 6
#define SENSOR_CAR_WE 5
#define SENSOR_WALK_NS 8
#define SENSOR_WALK_WE 7
// Modes:
// 0 - r
// 1 - r+y
// 2 - g
// 3 - y
// 4 - null
uint8_t timersList[] = {3, 1, 0, 3};
uint8_t mode, timer, redNSTimer, redWETimer;
int delayVal;
bool isNS, isError, lastIsError, isSensorShort, isButtonShort;
RTC_DS1307 rtc;
LiquidCrystal_I2C lcdNS(I2C_DISPLAY_NS, 16, 2);
LiquidCrystal_I2C lcdWE(I2C_DISPLAY_WE, 16, 2);
bool isNight() {
DateTime now = rtc.now();
return now.hour() < 6 || now.hour() > 21;
}
void setup() {
Wire.begin();
Serial.begin(115200);
rtc.begin();
lcdNS.init();
lcdNS.backlight();
lcdWE.init();
lcdWE.backlight();
pinMode(ERROR_PIN, INPUT_PULLUP);
pinMode(BUZZER_NS, OUTPUT);
pinMode(BUZZER_WE, OUTPUT);
pinMode(SENSOR_CAR_NS, INPUT);
pinMode(SENSOR_CAR_WE, INPUT);
pinMode(SENSOR_WALK_NS, INPUT);
pinMode(SENSOR_WALK_WE, INPUT);
delayVal = 1000;
mode = 0;
isNS = true;
isError = lastIsError = false;
isSensorShort = false;
timersList[2] = isNight ? 15 : 30;
timer = timersList[mode];
redNSTimer = 0;
redWETimer = 2 * timersList[0] + timersList[2] + timersList[3] + 1;
}
void timerModeFunc() {
if (timer > 0) timer--;
if (redNSTimer > 0) redNSTimer--;
if (redWETimer > 0) redWETimer--;
if (timer <= 0) {
mode++;
if (mode > 3) {
mode = 0;
isNS = !isNS;
if (isNS) {
redWETimer = 2 * timersList[0] + timersList[2] + timersList[3] + 1;
} else {
redNSTimer = 2 * timersList[0] + timersList[2] + timersList[3] + 1;
}
}
timersList[2] = isNight ? 15 : 30;
timer = timersList[mode];
isSensorShort = false;
}
}
void loop() {
delayVal = 1000;
isError = digitalRead((ERROR_PIN)) == LOW ? true : false;
// Obsługa powrotu ze statusu błędu
if (isError != lastIsError) {
lastIsError = isError;
isNS = true;
mode = 0;
timer = timersList[mode];
redNSTimer = 0;
redWETimer = 2 * timersList[0] + timersList[2] + timersList[3] + 1;
}
// Czujniki magnetyczne
if (((isNS && digitalRead((SENSOR_CAR_NS)) == LOW && digitalRead((SENSOR_CAR_WE)) == HIGH) ||
(!isNS && digitalRead((SENSOR_CAR_NS)) == HIGH && digitalRead((SENSOR_CAR_WE)) == LOW)) &&
mode == 2 && !isSensorShort) {
isSensorShort = true;
if (timer > 20) {
timer -= 10;
isNS ? redWETimer -= 10 : redNSTimer -= 10;
} else if (timer > 10) {
timer -= 5;
isNS ? redWETimer -= 5 : redNSTimer -= 5;
}
}
// Czujniki przejście dla pieszych
if (((isNS && digitalRead((SENSOR_WALK_NS)) == HIGH) ||
(!isNS && digitalRead((SENSOR_WALK_WE)) == HIGH)) &&
!isSensorShort) {
isSensorShort = true;
if (timer > 20) {
timer -= 5;
isNS ? redWETimer -= 5 : redNSTimer -= 5;
} else if (timer > 10) {
timer -= 3;
isNS ? redWETimer -= 3 : redNSTimer -= 3;
}
}
// Zmiana stanu
if (isError) {
mode = mode == 3 ? 4 : 3;
} else {
timerModeFunc();
}
// Światła
Wire.beginTransmission(I2C_LIGHTS_CONTROLLER_NS);
Wire.write(isNS || isError ? mode : 0);
Wire.endTransmission();
Wire.beginTransmission(I2C_LIGHTS_CONTROLLER_WE);
Wire.write(!isNS || isError ? mode : 0);
Wire.endTransmission();
// Ekrany
lcdNS.clear();
lcdWE.clear();
if (!isError) {
if (mode == 2) {
isNS ? lcdNS.print(timer) : lcdWE.print(timer);
}
if (redNSTimer > 0) lcdNS.print(redNSTimer);
if (redWETimer > 0) lcdWE.print(redWETimer);
}
// Dźwięk na przejściu
if (!isError && (mode == 2 || mode == 3)) {
isNS ? tone(BUZZER_WE, 250, 100) : tone(BUZZER_NS, 250, 100);
if (mode == 3 || timer <= 2) {
delayVal -= 500;
delay(500);
isNS ? tone(BUZZER_WE, 250, 100) : tone(BUZZER_NS, 250, 100);
}
}
delay(delayVal);
}