#include "LiquidCrystal_I2C.h"
// ===== LCD =====
#define I2C_ADDR 0x27
#define LCD_COLUMNS 20
#define LCD_LINES 4
// ===== Pins =====
const int LED_PIN = D13; // Діод 2
const int BUTTON_PIN = PC13; // Кнопка B1
// ===== Constants =====
const unsigned long INFINITE_DURATION = 0xFFFFFFFFUL;
const unsigned long DURATIONS[4] = {
2000UL,
1000UL,
10000UL,
INFINITE_DURATION
};
const float FREQUENCIES[4] = {
6.0f,
12.0f,
2.0f,
0.0f
};
unsigned long HALF_MS[4];
// ===== State =====
int currentStage = 0; // 0..3
int dir = 1; // +1 = прямий, -1 = реверс
bool finished = false;
unsigned long stageStart = 0;
unsigned long lastToggle = 0;
bool ledState = LOW;
// ===== Debounce =====
const unsigned long DEBOUNCE_MS = 40;
int lastRaw = HIGH;
int stableState = HIGH;
unsigned long lastBounce = 0;
const int PRESSED_LEVEL = LOW; // при INPUT_PULLUP натиснута -> LOW
// ===== Setup =====
void setup() {
pinMode(LED_PIN, OUTPUT);
pinMode(BUTTON_PIN, INPUT_PULLUP);
digitalWrite(LED_PIN, LOW);
for (int i = 0; i < 4; ++i) {
if (FREQUENCIES[i] > 0.0f) {
HALF_MS[i] = (unsigned long)(500.0f / FREQUENCIES[i] + 0.5f);
} else {
HALF_MS[i] = 0;
}
}
Serial.begin(115200);
delay(50);
lastRaw = digitalRead(BUTTON_PIN);
stableState = lastRaw;
lastBounce = millis();
stageStart = millis();
lastToggle = millis();
ledState = LOW;
Serial.println("--- START ---");
Serial.print("Start stage: ");
Serial.print(currentStage);
Serial.print(" dir: ");
Serial.println(dir);
}
// ===== Helpers =====
bool isFinalForDir(int stageIndex, int d) {
// прямий режим: фінальний stage 3
if (d == 1 && stageIndex == 3) return true;
// реверс: фінальний stage 0
if (d == -1 && stageIndex == 0) return true;
return false;
}
// ===== Loop =====
void loop() {
unsigned long now = millis();
// ----- debounce -----
int raw = digitalRead(BUTTON_PIN);
if (raw != lastRaw) lastBounce = now;
lastRaw = raw;
if ((now - lastBounce) > DEBOUNCE_MS) {
if (raw != stableState) {
stableState = raw;
if (stableState == PRESSED_LEVEL) {
// натискання кнопки
dir = -dir;
Serial.print("BUTTON pressed -> new dir = ");
Serial.println(dir == 1 ? "FORWARD" : "REVERSE");
currentStage = (dir == 1) ? 0 : 3;
stageStart = now;
lastToggle = now;
ledState = LOW;
digitalWrite(LED_PIN, ledState);
finished = false;
Serial.print("Start stage after toggle: ");
Serial.println(currentStage);
}
}
}
if (finished) {
digitalWrite(LED_PIN, HIGH);
delay(2);
return;
}
// ----- stage timing -----
unsigned long rawDuration = DURATIONS[currentStage];
bool finalForDir = isFinalForDir(currentStage, dir);
unsigned long durationForCheck = rawDuration;
// INFINITE_DURATION застосовуємо лише для фінального етапу
if (rawDuration == INFINITE_DURATION && !finalForDir) {
durationForCheck = 1;
}
unsigned long elapsed = now - stageStart;
if (durationForCheck != INFINITE_DURATION && elapsed >= durationForCheck) {
int next = currentStage + dir;
if (next < 0 || next > 3) {
finished = true;
digitalWrite(LED_PIN, HIGH);
Serial.println("Reached sequence end -> finished (LED ON).");
} else {
currentStage = next;
stageStart = now;
lastToggle = now;
ledState = LOW;
digitalWrite(LED_PIN, ledState);
Serial.print("Transition -> now stage ");
Serial.print(currentStage);
Serial.print(" (freq=");
Serial.print(FREQUENCIES[currentStage]);
Serial.println(" Hz)");
}
}
// ----- frequency selection -----
float freq;
if (dir == 1) {
// прямий режим
freq = FREQUENCIES[currentStage];
} else {
// реверс:
// stage 3 -> постійно
// stage 2 -> 2 Гц
// stage 1 -> 12 Гц
// stage 0 -> 6 Гц
switch (currentStage) {
case 3: freq = 0.0f; break;
case 2: freq = 2.0f; break;
case 1: freq = 12.0f; break;
case 0: freq = 6.0f; break;
}
}
// ----- LED control -----
if (freq > 0.0f) {
unsigned long half = (unsigned long)(500.0f / freq + 0.5f);
if (now - lastToggle >= half) {
ledState = !ledState;
digitalWrite(LED_PIN, ledState);
lastToggle = now;
}
} else {
// постійне світло
digitalWrite(LED_PIN, HIGH);
}
delay(2);
}