#include <avr/wdt.h>
// --- Настройки ---
const int NUM_ZONES = 5; // Количество зон сокращено до 5
const unsigned long TEST_PERIOD = 5000; // 5 секунд мигания при старте
const int BLINK_SPEED = 250; // Скорость мигания (мс)
const int DEBOUNCE_SAMPLES = 15; // Фильтр помех
// --- Пины ---
const int PIN_MAIN_SIGNAL = 2;
const int LED_MAIN_GREEN = 3;
const int LED_HEARTBEAT = 13;
// Массивы пинов для 5 зон
const int zoneInputs[NUM_ZONES] = {22, 23, 24, 25, 26};
const int redPins[NUM_ZONES] = {37, 39, 41, 43, 45};
const int greenPins[NUM_ZONES] = {38, 40, 42, 44, 46};
// --- Состояния ---
enum SystemMode { MODE_IDLE, MODE_TESTING, MODE_LIVE };
SystemMode currentMode = MODE_IDLE;
unsigned long testStartMillis = 0;
unsigned long lastBlinkMillis = 0;
bool blinkState = false;
struct Zone {
int debounceCounter;
bool isPresent;
} zones[NUM_ZONES];
int mainSignalCounter = 0;
bool mainSignalPresent = false;
void setup() {
wdt_disable();
pinMode(PIN_MAIN_SIGNAL, INPUT_PULLUP);
pinMode(LED_MAIN_GREEN, OUTPUT);
pinMode(LED_HEARTBEAT, OUTPUT);
for (int i = 0; i < NUM_ZONES; i++) {
pinMode(zoneInputs[i], INPUT_PULLUP);
pinMode(redPins[i], OUTPUT);
pinMode(greenPins[i], OUTPUT);
zones[i].debounceCounter = 0;
zones[i].isPresent = false;
}
wdt_enable(WDTO_2S);
}
void loop() {
wdt_reset();
updateHeartbeat();
readAllInputs();
if (!mainSignalPresent) {
if (currentMode != MODE_IDLE) {
currentMode = MODE_IDLE;
allLedsOff();
}
return;
}
if (mainSignalPresent && currentMode == MODE_IDLE) {
currentMode = MODE_TESTING;
testStartMillis = millis();
digitalWrite(LED_MAIN_GREEN, HIGH);
}
if (currentMode == MODE_TESTING) {
handleTestingPhase();
if (millis() - testStartMillis >= TEST_PERIOD) currentMode = MODE_LIVE;
}
else if (currentMode == MODE_LIVE) {
handleLiveMonitoring();
}
}
// --- Логика опроса ---
void readAllInputs() {
// Главный сигнал
bool rawMain = (digitalRead(PIN_MAIN_SIGNAL) == LOW);
mainSignalCounter = rawMain ? min(mainSignalCounter + 1, DEBOUNCE_SAMPLES) : max(mainSignalCounter - 1, 0);
mainSignalPresent = (mainSignalCounter > (DEBOUNCE_SAMPLES / 2));
// Зоны
for (int i = 0; i < NUM_ZONES; i++) {
bool rawZone = (digitalRead(zoneInputs[i]) == LOW);
zones[i].debounceCounter = rawZone ? min(zones[i].debounceCounter + 1, DEBOUNCE_SAMPLES) : max(zones[i].debounceCounter - 1, 0);
zones[i].isPresent = (zones[i].debounceCounter > (DEBOUNCE_SAMPLES / 2));
}
}
void handleTestingPhase() {
if (millis() - lastBlinkMillis >= BLINK_SPEED) {
lastBlinkMillis = millis();
blinkState = !blinkState;
}
for (int i = 0; i < NUM_ZONES; i++) {
digitalWrite(greenPins[i], blinkState);
digitalWrite(redPins[i], LOW);
}
}
void handleLiveMonitoring() {
for (int i = 0; i < NUM_ZONES; i++) {
digitalWrite(greenPins[i], zones[i].isPresent);
digitalWrite(redPins[i], !zones[i].isPresent);
}
}
void allLedsOff() {
digitalWrite(LED_MAIN_GREEN, LOW);
for (int i = 0; i < NUM_ZONES; i++) {
digitalWrite(greenPins[i], LOW);
digitalWrite(redPins[i], LOW);
}
}
void updateHeartbeat() {
static unsigned long hbMillis = 0;
if (millis() - hbMillis >= 500) {
hbMillis = millis();
digitalWrite(LED_HEARTBEAT, !digitalRead(LED_HEARTBEAT));
}
}