Untitled

 avatar
unknown
csharp
10 months ago
21 kB
16
Indexable
/*
 * ESP32-S3 Akıllı LED ve Motor Kontrol Sistemi - Simple Fire Simulation
 * Geliştirici: Muharrem Arslan
 * 
 * Özellikler:
 * - Tek dokunuş: Motor aç/kapat + LED kontrol
 * - Çift dokunuş: Parlaklık ayarı (her durumda çalışır)
 * - Basılı tutma: Renk değiştirme (sadece normal modda)
 * - 3x dokunuş: ALEV SİMÜLASYONU (sadece alev renkleri)
 * - Motor hareket ederken touch algılama tamamen kapalı
 * - Motor kapalıyken LED'ler sönük
 * - 18650 batarya koruması
 * - Róbert Ulbricht Fire Algorithm (Basit + Etkili)
 */

#include <FastLED.h>
#include <AccelStepper.h>
#include <EEPROM.h>

// Pin Tanımlamaları
#define LED_PIN         18
#define LED_COUNT       7
#define TOUCH_PIN       T4
#define STEP_PIN        14
#define DIR_PIN         12
#define MT3608_EN_PIN   23
#define BATTERY_PIN     33

// Sistem Sabitleri
#define MOTOR_STEPS     250
#define MOTOR_SPEED     2000
#define MOTOR_ACCEL     1000
#define TOUCH_THRESHOLD 45
#define LONG_PRESS_TIME 1200
#define TRIPLE_TAP_TIME 800
#define MOTOR_TRANSITION_TIME 2000

// Fire Simulation Sabitleri - Basit Algoritma
#define FIRE_BASE_COLOR_R    80      // Temel kırmızı değer
#define FIRE_BASE_COLOR_G    35      // Temel yeşil değer  
#define FIRE_BASE_COLOR_B    0       // Temel mavi değer
#define FIRE_RANDOM_MAX      80      // Maksimum karartma değeri

// Batarya Sabitleri
#define BATTERY_MIN_VOLTAGE   3.0
#define BATTERY_MAX_VOLTAGE   4.2
#define BATTERY_CRITICAL      3.2
#define VOLTAGE_DIVIDER_RATIO 1.27
#define ADC_RESOLUTION        4095
#define ADC_VREF             3.3

// EEPROM Adresleri
#define EEPROM_SIZE     512
#define ADDR_BRIGHTNESS 0
#define ADDR_EFFECT     1
#define ADDR_MOTOR_POS  2
#define ADDR_COLOR_HUE  3

// Nesneler
CRGB leds[LED_COUNT];
AccelStepper stepper(AccelStepper::DRIVER, STEP_PIN, DIR_PIN);

// Fire Simulation Değişkenleri
unsigned long lastFireUpdate = 0;
uint32_t nextUpdateDelay = 100;
bool fireEffectActive = false;

// Sistem Değişkenleri
bool systemOn = false;
bool motorOpen = false;
bool motorMoving = false;
bool batteryLow = false;
bool systemShutdown = false;

// Touch Değişkenleri
unsigned long lastTouchTime = 0;
unsigned long touchStartTime = 0;
unsigned long touchReleaseTime = 0;
int touchCount = 0;
bool longPressActive = false;
bool touchPressed = false;
bool touchProcessed = false;

// Batarya Değişkenleri
float batteryVoltage = 0.0;
uint8_t batteryPercentage = 0;
unsigned long lastBatteryCheck = 0;
unsigned long lowBatteryWarningTime = 0;
bool lowBatteryLedState = false;

// LED ve Renk Değişkenleri
uint8_t brightness = 150;
uint8_t brightnessLevels[] = {64, 127, 191, 255};
uint8_t brightnessIndex = 1;
uint8_t currentHue = 0;
uint8_t savedHue = 0;
bool colorChanging = false;
unsigned long lastColorUpdate = 0;
unsigned long motorStartTime = 0;

void setup() {
    Serial.begin(115200);
    delay(1000);
    Serial.println("=== ESP32 LED Motor Kontrol - Simple Fire Simulation ===");
    Serial.println("Geliştirici: Muharrem Arslan");
    
    // Sistem başlatma
    analogReadResolution(12);
    analogSetAttenuation(ADC_11db);
    
    EEPROM.begin(EEPROM_SIZE);
    loadSettings();
    
    pinMode(MT3608_EN_PIN, OUTPUT);
    pinMode(BATTERY_PIN, INPUT);
    digitalWrite(MT3608_EN_PIN, LOW);
    
    FastLED.addLeds<WS2812B, LED_PIN, GRB>(leds, LED_COUNT);
    FastLED.setBrightness(brightness);
    FastLED.clear();
    FastLED.show();
    
    stepper.setMaxSpeed(MOTOR_SPEED);
    stepper.setAcceleration(MOTOR_ACCEL);
    stepper.setCurrentPosition(0);
    
    touchSetCycles(0x1000, 0x1000);
    
    // Fire simulation başlatma
    initializeFireSimulation();
    
    // Touch test
    Serial.println("\n=== TOUCH SENSOR TEST ===");
    for (int i = 0; i < 5; i++) {
        uint16_t touchVal = touchRead(TOUCH_PIN);
        Serial.println("Touch " + String(i+1) + ": " + String(touchVal));
        delay(200);
    }
    Serial.println("Threshold: " + String(TOUCH_THRESHOLD));
    
    // Batarya kontrolü
    checkBatteryLevel();
    Serial.println("Batarya: " + String(batteryVoltage, 2) + "V (" + String(batteryPercentage) + "%)");
    
    // Kalibrasyon
    if (!batteryLow) {
        performStartupCalibration();
        Serial.println("\n=== SİSTEM HAZIR ===");
        Serial.println("Touch Komutları:");
        Serial.println("- 1x: Motor aç/kapat");
        Serial.println("- 2x: Parlaklık ayarı");
        Serial.println("- Basılı tut: Renk seç (sadece normal modda)");
        Serial.println("- 3x dokunuş: ALEV SİMÜLASYONU (sadece alev renkleri)");
        Serial.println("- Motor hareket ederken TOUCH KAPALI");
    } else {
        Serial.println("UYARI: Düşük batarya - kalibrasyon atlandı");
    }
    
    // Sistem otomatik aç - LED güç kaynağını aktif et
    systemOn = true;
    digitalWrite(MT3608_EN_PIN, HIGH);
    delay(100);
    Serial.println("LED güç kaynağı aktif - Fire efekt hazır");
}

void loop() {
    // Batarya kontrolü (10 saniyede bir)
    if (millis() - lastBatteryCheck > 10000) {
        checkBatteryLevel();
        lastBatteryCheck = millis();
    }
    
    // Düşük batarya kontrolü
    if (batteryLow && !systemShutdown) {
        handleLowBattery();
        return;
    }
    
    if (!systemShutdown) {
        // Motor durumu kontrol et
        checkMotorStatus();
        
        // Touch algılama - SADECE motor durgunken
        if (!motorMoving) {
            handleTouch();
        }
        
        // LED güncelleme - System her zaman aktif
        updateLEDs();
        stepper.run();
    }
    
    delay(10);
}

void initializeFireSimulation() {
    Serial.println("Basit Fire Simulation hazırlandı (Róbert Ulbricht algoritması)");
}

void updateFireSimulation() {
    if (millis() - lastFireUpdate < nextUpdateDelay) return;
    lastFireUpdate = millis();
    
    // Her LED için temel ateş rengi + rastgele karartma
    for (int i = 0; i < LED_COUNT; i++) {
        // Rastgele karartma değeri (0-80 arası)
        int randomDark = random(0, FIRE_RANDOM_MAX);
        
        // RGB değerlerinden karartma değerini çıkar
        int newR = FIRE_BASE_COLOR_R - randomDark;
        int newG = FIRE_BASE_COLOR_G - (randomDark / 2);  // Yeşil daha az kararsın
        int newB = FIRE_BASE_COLOR_B - (randomDark / 2);  // Mavi daha az kararsın
        
        // Negatif değerleri 0'la sınırla
        if (newR < 0) newR = 0;
        if (newG < 0) newG = 0;
        if (newB < 0) newB = 0;
        
        leds[i] = CRGB(newR, newG, newB);
    }
    
    FastLED.setBrightness(brightness);
    FastLED.show();
    
    // Bir sonraki güncelleme için rastgele gecikme (50-150ms)
    nextUpdateDelay = random(50, 150);
}

void checkMotorStatus() {
    if (motorMoving && stepper.distanceToGo() == 0) {
        motorMoving = false;
        Serial.println(">>> MOTOR DURDU - TOUCH AKTİF <<<");
        
        // Touch değişkenlerini temizle
        resetTouchVariables();
        
        // LED durumunu ayarla
        if (!motorOpen) {
            // Motor kapandı - LED'leri kapat
            FastLED.clear();
            FastLED.show();
        }
    }
    
    // Debug mesajları (motor hareket ederken)
    static unsigned long lastDebug = 0;
    if (motorMoving && millis() - lastDebug > 2000) {
        lastDebug = millis();
        Serial.println("Motor hareket - Kalan: " + String(stepper.distanceToGo()) + " - Touch KAPALI");
    }
}

void resetTouchVariables() {
    touchPressed = false;
    touchProcessed = false;
    longPressActive = false;
    colorChanging = false;
    touchCount = 0;
    lastTouchTime = 0;
}

void handleTouch() {
    uint16_t touchValue = touchRead(TOUCH_PIN);
    bool currentTouch = touchValue < TOUCH_THRESHOLD;
    
    // Touch başlangıcı
    if (currentTouch && !touchPressed) {
        touchPressed = true;
        touchStartTime = millis();
        longPressActive = false;
        touchProcessed = false;
        colorChanging = false;
        
        if (millis() - lastTouchTime < TRIPLE_TAP_TIME) {
            touchCount++;
            Serial.println("Art arda touch: " + String(touchCount));
        } else {
            touchCount = 1;
            Serial.println("Yeni touch başladı");
        }
    }
    
    // Touch bırakma
    if (!currentTouch && touchPressed) {
        touchPressed = false;
        touchReleaseTime = millis();
        lastTouchTime = millis();
        
        unsigned long touchDuration = touchReleaseTime - touchStartTime;
        
        if (colorChanging) {
            savedHue = currentHue;
            saveSettings();
            colorChanging = false;
            Serial.println("Renk kaydedildi: " + String(savedHue));
            
            // Seçilen rengi 2 saniye daha göster
            Serial.println("Seçilen renk 2 saniye gösteriliyor...");
            CRGB selectedColor = CHSV(savedHue, 255, 255);
            fill_solid(leds, LED_COUNT, selectedColor);
            FastLED.setBrightness(brightness);
            FastLED.show();
            delay(2000);
            
            touchProcessed = true;
            touchCount = 0;
        } else if (touchDuration >= LONG_PRESS_TIME && !longPressActive) {
            Serial.println("UZUN BASMA - Renk değiştir");
            startColorChanging();
            touchProcessed = true;
            touchCount = 0;
        }
    }
    
    // Uzun basma aktif iken
    if (touchPressed && (millis() - touchStartTime >= LONG_PRESS_TIME) && !colorChanging) {
        colorChanging = true;
        longPressActive = true;
        Serial.println("Renk değiştirme başladı!");
    }
    
    // Touch timeout - komut işleme
    if (touchCount > 0 && !touchPressed && !touchProcessed && 
        (millis() - lastTouchTime > TRIPLE_TAP_TIME)) {
        
        processTouch();
        touchCount = 0;
        touchProcessed = true;
    }
}

void processTouch() {
    Serial.println("Touch işlemi - Count: " + String(touchCount));
    
    if (touchCount == 1) {
        Serial.println(">>> TEK DOKUNUŞ");
        handleSingleTap();
    } else if (touchCount == 2) {
        Serial.println(">>> ÇİFT DOKUNUŞ");
        changeBrightness();
    } else if (touchCount >= 3) {
        Serial.println(">>> ÜÇLÜ DOKUNUŞ");
        handleTripleTap();
    }
}

void handleSingleTap() {
    if (motorMoving) {
        Serial.println("Motor hareket halinde - komut engellendi!");
        return;
    }
    
    if (fireEffectActive) {
        fireEffectActive = false;
        Serial.println("Alev simülasyonu durduruldu");
        saveSettings();
    }
    
    toggleMotor();
}

void toggleMotor() {
    if (batteryLow) {
        Serial.println("Düşük batarya - motor açılamıyor!");
        showLowBatteryWarning();
        delay(1000);
        return;
    }
    
    if (motorMoving) {
        Serial.println("Motor zaten hareket halinde!");
        return;
    }
    
    motorOpen = !motorOpen;
    motorMoving = true;
    motorStartTime = millis();
    
    if (motorOpen) {
        Serial.println(">>> MOTOR AÇILIYOR - TOUCH KAPALI <<<");
        stepper.moveTo(MOTOR_STEPS);
    } else {
        Serial.println(">>> MOTOR KAPANIYOR - TOUCH KAPALI <<<");
        stepper.moveTo(0);
    }
    
    saveSettings();
}

void changeBrightness() {
    brightnessIndex = (brightnessIndex + 1) % 4;
    brightness = brightnessLevels[brightnessIndex];
    saveSettings();
    
    uint8_t percent = (brightness * 100) / 255;
    Serial.println("Parlaklık: %" + String(percent));
    
    if (fireEffectActive || motorMoving) {
        // Fire efektinde veya motor hareketinde parlaklık demosu
        for (int i = 0; i < 3; i++) {
            FastLED.setBrightness(brightness / 4);
            FastLED.show();
            delay(150);
            FastLED.setBrightness(brightness);
            FastLED.show();
            delay(150);
        }
    } else {
        // Önizleme modu (2 saniye)
        Serial.println("Parlaklık önizlemesi...");
        
        CRGB color = CHSV(savedHue, 255, 255);
        fill_solid(leds, LED_COUNT, color);
        FastLED.setBrightness(brightness);
        FastLED.show();
        
        delay(2000);
        
        if (!motorOpen) {
            FastLED.clear();
            FastLED.show();
        }
    }
}

void handleTripleTap() {
    fireEffectActive = !fireEffectActive;
    saveSettings();
    
    if (fireEffectActive) {
        Serial.println("BASIT ALEV SİMÜLASYONU BAŞLATILDI");
        Serial.println("Algoritma: Róbert Ulbricht - Temel renk + rastgele karartma");
        
        // Basit başlangıç efekti
        for (int i = 0; i < 3; i++) {
            fill_solid(leds, LED_COUNT, CRGB(FIRE_BASE_COLOR_R, FIRE_BASE_COLOR_G, FIRE_BASE_COLOR_B));
            FastLED.setBrightness(brightness);
            FastLED.show();
            delay(200);
            FastLED.clear();
            FastLED.show();
            delay(200);
        }
        
        // İlk güncelleme gecikmesini ayarla
        nextUpdateDelay = random(50, 150);
        
    } else {
        Serial.println("Alev simülasyonu durduruldu");
        
        // Söndürme efekti
        for (int fade = brightness; fade > 0; fade -= 20) {
            FastLED.setBrightness(fade);
            FastLED.show();
            delay(50);
        }
        FastLED.clear();
        FastLED.show();
    }
}

void startColorChanging() {
    if (!fireEffectActive) {
        colorChanging = true;
        currentHue = savedHue;
        Serial.println("Renk değiştirme aktif - Mevcut: " + String(currentHue));
    } else {
        Serial.println("Ateş efekti aktifken renk değiştirilemez - Sadece alev renkleri!");
        
        // Uyarı efekti
        for (int i = 0; i < 3; i++) {
            FastLED.setBrightness(brightness / 2);
            FastLED.show();
            delay(150);
            FastLED.setBrightness(brightness);
            FastLED.show();
            delay(150);
        }
    }
}

void updateLEDs() {
    if (motorMoving) {
        updateMotorTransition();
    } else if (!motorOpen && !fireEffectActive && !colorChanging) {
        // Motor kapalı + efekt yok = LED kapalı
        FastLED.clear();
        FastLED.show();
    } else if (colorChanging) {
        updateColorChanging();
    } else if (fireEffectActive) {
        updateFireSimulation();
    } else if (motorOpen) {
        showSolidColor();
    }
}

void updateMotorTransition() {
    if (stepper.distanceToGo() == 0) {
        return; // Motor durmuş
    }
    
    unsigned long elapsed = millis() - motorStartTime;
    float progress = constrain((float)elapsed / MOTOR_TRANSITION_TIME, 0.0, 1.0);
    
    uint8_t targetBrightness;
    if (motorOpen) {
        // Açılırken: 0% → 100%
        targetBrightness = brightness * progress;
    } else {
        // Kapanırken: 100% → 0%
        targetBrightness = brightness * (1.0 - progress);
    }
    
    if (targetBrightness > 0) {
        CRGB color = CHSV(savedHue, 255, 255);
        fill_solid(leds, LED_COUNT, color);
        FastLED.setBrightness(targetBrightness);
        FastLED.show();
    } else {
        FastLED.clear();
        FastLED.show();
    }
}

void updateColorChanging() {
    if (millis() - lastColorUpdate < 30) return;
    lastColorUpdate = millis();
    
    currentHue += 3;
    if (currentHue > 255) currentHue = 0;
    
    CRGB color = CHSV(currentHue, 255, 255);
    fill_solid(leds, LED_COUNT, color);
    FastLED.setBrightness(brightness);
    FastLED.show();
}

void showSolidColor() {
    CRGB color = CHSV(savedHue, 255, 255);
    fill_solid(leds, LED_COUNT, color);
    FastLED.setBrightness(brightness);
    FastLED.show();
}

void checkBatteryLevel() {
    int adcValue = analogRead(BATTERY_PIN);
    float adcVoltage = (adcValue * ADC_VREF) / ADC_RESOLUTION;
    batteryVoltage = adcVoltage * VOLTAGE_DIVIDER_RATIO;
    batteryVoltage = constrain(batteryVoltage, 2.5, 4.3);
    
    if (batteryVoltage >= BATTERY_MAX_VOLTAGE) {
        batteryPercentage = 100;
    } else if (batteryVoltage <= BATTERY_MIN_VOLTAGE) {
        batteryPercentage = 0;
    } else {
        batteryPercentage = ((batteryVoltage - BATTERY_MIN_VOLTAGE) / 
                           (BATTERY_MAX_VOLTAGE - BATTERY_MIN_VOLTAGE)) * 100;
    }
    
    if (batteryVoltage <= BATTERY_CRITICAL && !batteryLow) {
        Serial.println("KRİTİK: Batarya düşük - acil kapatma!");
        batteryLow = true;
        if (systemOn) {
            emergencyShutdown();
        }
    } else if (batteryVoltage > BATTERY_CRITICAL) {
        batteryLow = false;
    }
}

void handleLowBattery() {
    if (millis() - lowBatteryWarningTime > 1000) {
        lowBatteryWarningTime = millis();
        lowBatteryLedState = !lowBatteryLedState;
        
        if (lowBatteryLedState) {
            fill_solid(leds, LED_COUNT, CRGB::Red);
            FastLED.setBrightness(150);
        } else {
            FastLED.clear();
        }
        FastLED.show();
    }
}

void showLowBatteryWarning() {
    for (int i = 0; i < 3; i++) {
        fill_solid(leds, LED_COUNT, CRGB::Red);
        FastLED.setBrightness(150);
        FastLED.show();
        delay(200);
        FastLED.clear();
        FastLED.show();
        delay(200);
    }
}

void emergencyShutdown() {
    Serial.println("ACİL KAPATMA!");
    
    FastLED.clear();
    FastLED.show();
    
    if (motorOpen) {
        Serial.println("Motor güvenli konuma getiriliyor...");
        stepper.moveTo(0);
        while (stepper.distanceToGo() != 0) {
            stepper.run();
            delay(10);
        }
        motorOpen = false;
    }
    
    motorMoving = false;
    digitalWrite(MT3608_EN_PIN, LOW);
    systemOn = false;
    systemShutdown = true;
    
    Serial.println("Sistem güvenle kapatıldı!");
}

void performStartupCalibration() {
    Serial.println("\n=== KALİBRASYON ===");
    
    digitalWrite(MT3608_EN_PIN, HIGH);
    delay(500);
    
    // Başlangıç göstergesi
    for (int i = 0; i < 3; i++) {
        fill_solid(leds, LED_COUNT, CRGB::Blue);
        FastLED.setBrightness(100);
        FastLED.show();
        delay(300);
        FastLED.clear();
        FastLED.show();
        delay(300);
    }
    
    Serial.println("Motor açılıyor...");
    motorMoving = true;
    stepper.moveTo(MOTOR_STEPS);
    
    unsigned long startTime = millis();
    int ledPos = 0;
    
    while (stepper.distanceToGo() != 0) {
        stepper.run();
        
        if (millis() - startTime > 15000) {
            Serial.println("Timeout - kalibrasyon durdu");
            break;
        }
        
        static unsigned long lastLed = 0;
        if (millis() - lastLed > 200) {
            lastLed = millis();
            FastLED.clear();
            leds[ledPos] = CRGB::Green;
            FastLED.setBrightness(150);
            FastLED.show();
            ledPos = (ledPos + 1) % LED_COUNT;
        }
        delay(5);
    }
    
    delay(1000);
    
    Serial.println("Motor kapanıyor...");
    stepper.moveTo(0);
    
    startTime = millis();
    ledPos = LED_COUNT - 1;
    
    while (stepper.distanceToGo() != 0) {
        stepper.run();
        
        if (millis() - startTime > 15000) {
            Serial.println("Geri hareket timeout");
            break;
        }
        
        static unsigned long lastLed2 = 0;
        if (millis() - lastLed2 > 200) {
            lastLed2 = millis();
            FastLED.clear();
            leds[ledPos] = CRGB::Orange;
            FastLED.setBrightness(150);
            FastLED.show();
            ledPos = (ledPos == 0) ? LED_COUNT - 1 : ledPos - 1;
        }
        delay(5);
    }
    
    // Tamamlandı
    for (int i = 0; i < 3; i++) {
        fill_solid(leds, LED_COUNT, CRGB::White);
        FastLED.setBrightness(200);
        FastLED.show();
        delay(200);
        FastLED.clear();
        FastLED.show();
        delay(200);
    }
    
    stepper.setCurrentPosition(0);
    motorOpen = false;
    motorMoving = false;
    
    Serial.println("KALİBRASYON TAMAMLANDI!");
}

void saveSettings() {
    EEPROM.write(ADDR_BRIGHTNESS, brightnessIndex);
    EEPROM.write(ADDR_EFFECT, fireEffectActive ? 1 : 0);
    EEPROM.write(ADDR_MOTOR_POS, motorOpen ? 1 : 0);
    EEPROM.write(ADDR_COLOR_HUE, savedHue);
    EEPROM.commit();
}

void loadSettings() {
    brightnessIndex = EEPROM.read(ADDR_BRIGHTNESS);
    if (brightnessIndex > 3) brightnessIndex = 1;
    brightness = brightnessLevels[brightnessIndex];
    
    uint8_t effect = EEPROM.read(ADDR_EFFECT);
    fireEffectActive = false; // Her zaman kapalı başlasın
    
    uint8_t motorPos = EEPROM.read(ADDR_MOTOR_POS);
    motorOpen = (motorPos == 1);
    if (motorOpen) {
        stepper.setCurrentPosition(MOTOR_STEPS);
    }
    
    savedHue = EEPROM.read(ADDR_COLOR_HUE);
    currentHue = savedHue;
    
    Serial.println("\nAyarlar yüklendi:");
    Serial.println("- Parlaklık: %" + String((brightness * 100) / 255));
    Serial.println("- Alev efekti: " + String(fireEffectActive ? "Aktif" : "Pasif"));
    Serial.println("- Motor: " + String(motorOpen ? "Açık" : "Kapalı"));
    Serial.println("- Renk: " + String(savedHue));
}
Editor is loading...
Leave a Comment