Zweryfikuj kod pod wzgledem użycia w Arduino Nano


// ==== DEFINICJE PINÓW ====
#define SELECT_PIN 4        // Przycisk SELECT - zmiana ekranu i sterowanie
#define BAT_PIN A2          // Wejście analogowe pomiaru napięcia baterii
#define BUZZER_PIN 5        // Buzzer dla alarmu timera
#define VIBRATION_PIN A0     // Czujnik drgań/wibracji

// ==== KONFIGURACJA WYŚWIETLACZA ====
#define SCREEN_WIDTH 128    // Szerokość OLED w pikselach
#define SCREEN_HEIGHT 64    // Wysokość OLED w pikselach
#define OLED_RESET -1       // Pin reset (-1 = brak)

// ==== ADRESY PAMIĘCI EEPROM ====
#define ADDR_RUNTIME 0      // Adres zapisu czasu pracy (4 bajty)
#define ADDR_FILTER 4       // Adres zapisu zużycia filtra (4 bajty)
#define ADDR_INIT_FLAG 8    // Adres flagi inicjalizacji (1 bajt)
#define ADDR_TEMPERATURE 12 // Adres zapisu temperatury (1 bajt)

// ==== STAŁE PROGRAMU ====
#define MAX_FILTER_POINTS 1560.0f   // Maksymalna żywotność filtra w punktach
#define VBAT_MIN 3.0f               // Minimalne napięcie baterii Li-Ion
#define VBAT_MAX 4.2f               // Maksymalne napięcie baterii Li-Ion
#define EEPROM_INIT_FLAG 0xAA       // Wartość flagi oznaczająca zainicjalizowany EEPROM
#define TIMER_DURATION 900000       // Czas timera: 15 minut (15 * 60 * 1000 ms)

// ==== BIBLIOTEKI ====
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <EEPROM.h>

// ==== OBIEKT WYŚWIETLACZA ====
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

// ==== ZMIENNE SYSTEMOWE ====
unsigned long totalRuntime = 0;     // Całkowity czas pracy w milisekundach
float totalPointsUsed = 0.0;        // Zużyte punkty filtra
float currentTemp = 20.0f;          // Stała temperatura 20°C

// ==== ZMIENNE PRECYZYJNEGO POMIARU CZASU ====
unsigned long sessionStartTime = 0;
unsigned long lastRuntimeUpdate = 0;
unsigned long lastFilterUpdate = 0;
unsigned long lastEEPROMSave = 0;
float accumulatedFilterUsage = 0.0;

// ==== ZMIENNE STANU SYSTEMU ====
bool vibrationDetected = false;
bool lastVibrationState = false;
unsigned long vibrationLastChange = 0;

// ==== ZMIENNE TIMERA ====
bool timerRunning = false;
bool alarmActive = false;
unsigned long timerStartTime = 0;
unsigned long timerRemaining = TIMER_DURATION;
unsigned long lastBeepTime = 0;

// ==== ZMIENNE INTERFEJSU UŻYTKOWNIKA ====
int currentScreen = 0;
bool buttonPressed = false;
bool longPressHandled = false;
unsigned long buttonPressStart = 0;
float batteryVoltage = 0.0f;
int batteryPercent = 0;

// ==== ZMIENNE NIEBLOKUJĄCYCH KOMUNIKATÓW ====
bool showingMessage = false;
unsigned long messageStartTime = 0;
unsigned long messageDuration = 0;
String messageText1 = "";
String messageText2 = "";

// ==== ZMIENNE DEBOUNCE ====
unsigned long lastButtonChange = 0;
const unsigned long DEBOUNCE_DELAY = 50;

// ==== ZMIENNE TEMPERATURY ====
float temperatureLevels[] = {10, 15, 20, 25, 30, 35, 40};
const byte TEMP_LEVELS_COUNT = 7;
byte currentTempIndex = 3;

// ==== DEKLARACJE FUNKCJI ====
void updateMainDisplay();
void updateTimerDisplay();
void updateTempDisplay();
void saveToEEPROM();
void resetEEPROM();
void handleButtonPress();
void handleTimer();
void startTimer();
void stopTimer();
void resetTimer();
float getConsumptionRate(float temp);
void updateBatteryStatus();
void handleVibrationDetection();
void updateRuntimePrecise();
void updateFilterUsagePrecise();
void showMessage(String line1, String line2, unsigned long duration);
void handleMessageDisplay();

// ==== FUNKCJA SETUP ====
void setup() {
  Serial.begin(115200);

  if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
    while (true);
  }
  display.clearDisplay();
  display.setTextColor(SSD1306_WHITE);
  display.setTextSize(1);

  pinMode(SELECT_PIN, INPUT_PULLUP);
  pinMode(BAT_PIN, INPUT);
  pinMode(BUZZER_PIN, OUTPUT);
  pinMode(VIBRATION_PIN, INPUT_PULLUP);
  digitalWrite(BUZZER_PIN, LOW);

  if (EEPROM.read(ADDR_INIT_FLAG) != EEPROM_INIT_FLAG) {
    resetEEPROM();
    EEPROM.write(ADDR_INIT_FLAG, EEPROM_INIT_FLAG);
    showMessage("EEPROM", "RESET", 2000);
  } else {
    EEPROM.get(ADDR_RUNTIME, totalRuntime);
    EEPROM.get(ADDR_FILTER, totalPointsUsed);
    EEPROM.get(ADDR_TEMPERATURE, currentTempIndex);
    currentTemp = temperatureLevels[currentTempIndex];
  }

  unsigned long now = millis();
  sessionStartTime = now;
  lastRuntimeUpdate = now;
  lastFilterUpdate = now;
  lastEEPROMSave = now;
  lastVibrationState = digitalRead(VIBRATION_PIN) == HIGH;
}

// ==== GŁÓWNA PĘTLA PROGRAMU ====
void loop() {
  unsigned long now = millis();

  handleButtonPress();
  handleTimer();
  handleVibrationDetection();
  updateBatteryStatus();

  if (vibrationDetected) {
    updateRuntimePrecise();
    updateFilterUsagePrecise();
  }

  unsigned long lastDisplayUpdate = 0;
  if (now - lastDisplayUpdate >= 60000 || currentScreen != 0) {
    lastDisplayUpdate = now;
    display.clearDisplay();
  }

  if ((now - lastEEPROMSave >= 600000) ||
      (!vibrationDetected && lastVibrationState)) {
    saveToEEPROM();
    lastEEPROMSave = now;
  }

  if (showingMessage) {
    handleMessageDisplay();
  } else {
    switch (currentScreen) {
      case 0:
        updateMainDisplay();
        break;
      case 1:
        updateTimerDisplay();
        break;
      case 2:
        updateTempDisplay();
        break;
    }
  }
}

// ==== PRECYZYJNA AKTUALIZACJA CZASU PRACY ====
void updateRuntimePrecise() {
  unsigned long now = millis();
  unsigned long elapsed = now - lastRuntimeUpdate;

  if (elapsed >= 1000) {
    unsigned long secondsElapsed = elapsed / 1000;
    totalRuntime += secondsElapsed * 1000;
    lastRuntimeUpdate += secondsElapsed * 1000;
  }
}

// ==== PRECYZYJNA AKTUALIZACJA ZUŻYCIA FILTRA ====
void updateFilterUsagePrecise() {
  unsigned long now = millis();
  unsigned long elapsed = now - lastFilterUpdate;

  if (elapsed >= 100) {
    float secondsElapsed = elapsed / 1000.0f;
    float litersPerSec = 1.667f;
    float pointsUsed = litersPerSec * secondsElapsed * getConsumptionRate(currentTemp);

    accumulatedFilterUsage += pointsUsed;

    if (accumulatedFilterUsage >= 0.1f) {
      totalPointsUsed += accumulatedFilterUsage;
      accumulatedFilterUsage = 0.0f;
    }

    lastFilterUpdate = now;
  }
}

// ==== OBSŁUGA CZUJNIKA DRGAŃ ====
void handleVibrationDetection() {
  bool currentState = digitalRead(VIBRATION_PIN) == HIGH;

  if (currentState != lastVibrationState) {
    vibrationLastChange = millis();

    if (!currentState && lastVibrationState) {
      saveToEEPROM();
    }

    lastVibrationState = currentState;
  }

  vibrationDetected = currentState;
}

// ==== OBSŁUGA PRZYCISKU SELECT ====
void handleButtonPress() {
  static bool lastButtonState = HIGH;
  bool currentButtonState = digitalRead(SELECT_PIN);
  unsigned long now = millis();

  if (currentButtonState != lastButtonState) {
    lastButtonChange = now;
  }

  if ((now - lastButtonChange) > DEBOUNCE_DELAY) {
    if (currentButtonState == LOW && !buttonPressed) {
      buttonPressStart = now;
      buttonPressed = true;
      longPressHandled = false;
    } else if (currentButtonState == HIGH && buttonPressed) {
      unsigned long pressDuration = now - buttonPressStart;

      if (!longPressHandled) {
        if (pressDuration < 1000) {
          currentScreen = (currentScreen + 1) % 3;
        }
      }

      buttonPressed = false;
      longPressHandled = false;
    }
  }

if (buttonPressed && !longPressHandled) {
  unsigned long pressDuration = now - buttonPressStart;

  if (pressDuration > 1000) {
    if (currentScreen == 2) {
      // Zmiana temperatury
      currentTempIndex = (currentTempIndex + 1) % TEMP_LEVELS_COUNT;
      currentTemp = temperatureLevels[currentTempIndex];
    } else if (currentScreen == 1) {
      // Ekran TIMER
      if (alarmActive) {
        resetTimer();  // Resetuj timer i wyłącz alarm
      } else if (!timerRunning && timerRemaining == TIMER_DURATION) {
        startTimer();  // Uruchom timer
      } else {
        resetTimer();  // Zatrzymaj i zresetuj timer
      }
    }
    longPressHandled = true;
  }
}
 

  lastButtonState = currentButtonState;
}

// ==== OBSŁUGA TIMERA ====
void handleTimer() {
  unsigned long now = millis();

  if (timerRunning && !alarmActive) {
    unsigned long elapsed = now - timerStartTime;

    if (elapsed >= TIMER_DURATION) {
      alarmActive = true;
      timerRunning = false;
      timerRemaining = 0;
      currentScreen = 1;
    } else {
      timerRemaining = TIMER_DURATION - elapsed;
    }
  }

  if (alarmActive && now - lastBeepTime > 500) {
    digitalWrite(BUZZER_PIN, !digitalRead(BUZZER_PIN));
    lastBeepTime = now;
  }
}

// ==== FUNKCJE STEROWANIA TIMEREM ====
void startTimer() {
  timerStartTime = millis();
  timerRunning = true;
  timerRemaining = TIMER_DURATION;
  alarmActive = false;
  digitalWrite(BUZZER_PIN, LOW);
}

void stopTimer() {
  timerRunning = false;
}

void resetTimer() {
  stopTimer();
  timerRemaining = TIMER_DURATION;
  alarmActive = false;
  digitalWrite(BUZZER_PIN, LOW);
}

// ==== WSPÓŁCZYNNIK ZUŻYCIA FILTRA ====
float getConsumptionRate(float temp) {
  if(temp <= 10) return 0.00857f;
  else if(temp <= 15) return 0.01164f;
  else if(temp <= 20) return 0.01500f;
  else if(temp <= 25) return 0.02000f;
  else if(temp <= 30) return 0.02600f;
  else if(temp <= 35) return 0.03391f;
  else return 0.04105f;
}

// ==== AKTUALIZACJA STANU BATERII ====
void updateBatteryStatus() {
  static unsigned long lastBatteryUpdate = 0;
  unsigned long now = millis();

  if (now - lastBatteryUpdate < 5000) return;
  lastBatteryUpdate = now;

  int raw = analogRead(BAT_PIN);
  batteryVoltage = (raw / 1023.0f) * 5.0f * 1.5f;
  batteryPercent = constrain(
    ((batteryVoltage - VBAT_MIN) / (VBAT_MAX - VBAT_MIN)) * 100.0f,
    0, 100
  );
}

// ==== WYŚWIETLANIE EKRANU GŁÓWNEGO ====
void updateMainDisplay() {
  display.clearDisplay();

  display.setTextSize(3);
  display.setCursor(4, 0);

  unsigned long totalMinutes = totalRuntime / 60000;
  unsigned int hours = totalMinutes / 60;
  unsigned int minutes = totalMinutes % 60;

  if (hours < 1000) display.print("0");
  if (hours < 100) display.print("0");
  if (hours < 10) display.print("0");
  display.print(hours);

  display.setTextSize(2);
  display.setCursor(76, 0);
  display.print("H");

  display.setTextSize(3);
  display.setCursor(90, 0);
  if (minutes < 10) display.print("0");
  display.print(minutes);

  display.setTextSize(2);
  display.setCursor(4, 28);
  display.print("F: ");
  display.print(MAX_FILTER_POINTS - totalPointsUsed, 1);

  display.setTextSize(2);
  display.setCursor(4, 50);
  display.print(int(currentTemp));
  display.print((char)247);
  display.print("C");

  if (vibrationDetected) {
    int frame = (millis() / 300) % 4;
    display.fillCircle(69, 56, 2, SSD1306_WHITE);
    if (frame >= 1) display.drawCircle(69, 56, 4, SSD1306_WHITE);
    if (frame >= 2) display.drawCircle(69, 56, 6, SSD1306_WHITE);
    if (frame >= 3) display.drawCircle(69, 56, 8, SSD1306_WHITE);
  }

  display.drawRect(89, 49, 31, 15, SSD1306_WHITE);
  display.drawRect(119, 53, 3, 6, SSD1306_WHITE);

  display.setTextSize(1);
  if (batteryPercent == 100) display.setCursor(93, 53);
  else if (batteryPercent >= 10) display.setCursor(99, 53);
  else display.setCursor(105, 53);
  display.print(batteryPercent);
  display.print("%");

  display.display();
}

// ==== WYŚWIETLANIE EKRANU TIMERA ====
void updateTimerDisplay() {
  display.clearDisplay();

  display.setTextSize(2);
  display.setCursor(33, 0);
  display.println("TIMER");

  unsigned int minutes = timerRemaining / 60000;
  unsigned int seconds = (timerRemaining % 60000) / 1000;

  display.setTextSize(4);
  display.setCursor(5, 22);
  if (minutes < 10) display.print("0");
  display.print(minutes);
  display.print(":");
  if (seconds < 10) display.print("0");
  display.print(seconds);

  display.setTextSize(1);
  display.setCursor(22, 55);
  if (alarmActive) {
    display.print("!!! ALARM !!!");
  } else if (timerRunning) {
    display.setCursor(28, 55);
    display.print("COUNTING...");
  } else if (timerRemaining == TIMER_DURATION) {
    display.setCursor(25, 55);
    display.print("HOLD 1s START");
  } 
  display.display();
}

// ==== WYŚWIETLANIE EKRANU TEMPERATURY ====
void updateTempDisplay() {
  display.clearDisplay();

 display.setTextSize(2);
  display.setCursor(35, 0);
  display.println("TEMP.");

  display.setTextSize(4);
  display.setCursor(23, 22);
  display.print(currentTemp, 0);
  display.setTextSize(3);
  display.setCursor(73, 22);
  display.print((char)247);
  display.print("C");

  display.setTextSize(1);
  display.setCursor(28, 55);
  display.println("HOLD 1s NEXT");

  display.display();
}

// ==== ZAPIS DO EEPROM ====
void saveToEEPROM() {
  if (accumulatedFilterUsage > 0) {
    totalPointsUsed += accumulatedFilterUsage;
    accumulatedFilterUsage = 0.0f;
  }

  EEPROM.put(ADDR_RUNTIME, totalRuntime);
  EEPROM.put(ADDR_FILTER, totalPointsUsed);
  EEPROM.write(ADDR_TEMPERATURE, currentTempIndex);
}

// ==== RESET EEPROM ====
void resetEEPROM() {
  totalRuntime = 0;
  totalPointsUsed = 0.0f;
  accumulatedFilterUsage = 0.0f;
  currentTempIndex = 3;
  currentTemp = temperatureLevels[currentTempIndex];
  EEPROM.put(ADDR_RUNTIME, totalRuntime);
  EEPROM.put(ADDR_FILTER, totalPointsUsed);
  EEPROM.write(ADDR_TEMPERATURE, currentTempIndex);
}

// ==== OBSŁUGA KOMUNIKATÓW ====
void showMessage(String line1, String line2, unsigned long duration) {
  messageText1 = line1;
  messageText2 = line2;
  messageDuration = duration;
  messageStartTime = millis();
  showingMessage = true;
}

void handleMessageDisplay() {
  if (millis() - messageStartTime >= messageDuration) {
    showingMessage = false;
    return;
  }

  display.clearDisplay();
  display.setTextSize(2);
  display.setCursor(25, 10);
  display.println(messageText1);
  display.setCursor(20, 35);
  display.println(messageText2);
  display.display();
}