#include <Arduino.h> // Команди плати Arduino.
const byte RED_PIN = 8; // Червоний LED.
const byte YELLOW_PIN = 9; // Жовтий LED.
const byte GREEN_PIN = 10; // Зелений LED.
const byte BUTTON_PIN = 2; // Кнопка замикає D2 на GND.
const unsigned long GREEN_MS = 5000; // Мінімум 5 секунд зеленого.
const unsigned long BLINK_MS = 3000; // Три блимання по одній секунді.
const unsigned long HALF_BLINK_MS = 500; // Пів секунди темно, пів секунди світло.
const unsigned long YELLOW_MS = 2000; // 2 секунди жовтого.
const unsigned long RED_MS = 5000; // 5 секунд для переходу.
const unsigned long READY_MS = 1000; // 1 секунда червоного з жовтим.
const unsigned long DEBOUNCE_MS = 30; // Чекаємо стабільного контакту.
enum Phase { GREEN, BLINK, YELLOW, RED, READY }; // Імена п’яти станів.
Phase phase = GREEN; // Починаємо із зеленого.
bool crossingRequested = false; // Чи є запит на перехід.
bool lastReading = HIGH; // Попереднє читання кнопки.
bool buttonState = HIGH; // Стабільний стан кнопки.
unsigned long buttonChangedAt = 0; // Коли змінився контакт кнопки.
unsigned long phaseStartedAt = 0; // Коли почався поточний стан.
void showLights(unsigned long elapsed) {
digitalWrite(RED_PIN, phase == RED || phase == READY); // Червоний у двох станах.
digitalWrite(YELLOW_PIN, phase == YELLOW || phase == READY); // Жовтий у двох станах.
bool flashOn = (elapsed / HALF_BLINK_MS) % 2 == 1; // Чергуємо темну та світлу половини секунди.
bool greenOn = phase == GREEN || (phase == BLINK && flashOn); // Зелений горить постійно або блимає.
digitalWrite(GREEN_PIN, greenOn); // Передаємо обчислений стан на зелений LED.
}
void setup() { // Підготовка після ввімкнення.
pinMode(RED_PIN, OUTPUT); // Вихід червоного LED.
pinMode(YELLOW_PIN, OUTPUT); // Вихід жовтого LED.
pinMode(GREEN_PIN, OUTPUT); // Вихід зеленого LED.
pinMode(BUTTON_PIN, INPUT_PULLUP); // Відпущена кнопка дає HIGH.
phaseStartedAt = millis(); // Запам’ятовуємо початок зеленого.
showLights(0); // Показуємо початковий стан.
}
void readButton(unsigned long now) {
bool reading = digitalRead(BUTTON_PIN); // Читаємо контакт.
if (reading != lastReading) { // Контакт щойно змінився.
lastReading = reading; // Зберігаємо нове читання.
buttonChangedAt = now; // Починаємо відлік стабілізації.
}
if (now - buttonChangedAt >= DEBOUNCE_MS && reading != buttonState) { // Стан стабільний.
buttonState = reading; // Приймаємо зміну кнопки.
if (buttonState == LOW && phase == GREEN) { // Нове натискання на зеленому.
crossingRequested = true; // Зберігаємо запит навіть після відпускання.
}
}
}
void updatePhase(unsigned long now) {
unsigned long elapsed = now - phaseStartedAt; // Тривалість поточного стану.
if (phase == GREEN && crossingRequested && elapsed >= GREEN_MS) { // Можна завершити зелений.
phase = BLINK; // Спершу три блимання зеленого.
} else if (phase == BLINK && elapsed >= BLINK_MS) { // Три блимання завершились.
phase = YELLOW; // Після них вмикаємо жовтий.
} else if (phase == YELLOW && elapsed >= YELLOW_MS) { // Жовтий завершився.
phase = RED; // Вмикаємо червоний.
} else if (phase == RED && elapsed >= RED_MS) { // Час переходу завершився.
phase = READY; // Червоний разом із жовтим.
} else if (phase == READY && elapsed >= READY_MS) { // Повертаємо рух.
phase = GREEN; // Знову зелений.
crossingRequested = false; // Старий запит виконано.
} else { // Час зміни ще не настав.
return; // Залишаємо поточний стан.
}
phaseStartedAt = now; // Запам’ятовуємо початок нового стану.
}
void loop() {
unsigned long now = millis(); // Один показ часу для всіх дій цього оберту.
readButton(now); // Читаємо кнопку та запам’ятовуємо новий запит.
updatePhase(now); // Перемикаємо стан, якщо настав його час.
showLights(now - phaseStartedAt); // Показуємо кольори та оновлюємо блимання.
}