Proje için yardım/öneri (24.03.25 güncelleme)

Kodda ufak farklar var, evdeki pc de kaldı son yüklediğim. şuan kodda güncellemeler yapıyorum resetleme halinde kaldığı yerden devam etmesi ile ilgili. Güncel kodu bittiğinde yeniden paylaşırım.


Evet arduino üzerinden besledim röleleri 9v 1a. Bende dolabı karıştırıp eski telefon adaptörünü buldum azönce 5v 2a yeterli olur inşallah :) Kabloları kısaltmaya kalkarsam çok gergin olacakmış gibi. 2-3cm de olsa kısatmamı önerirseniz onu da yapayım.
Denediğim yer ile aramda 60km mesafe var, haftasonu deneyip haftaiçi düzeltmeleri yapıyorum. Almam gereken birşey varsa gitmeden toparlamak için öğrenmeye çalışıyorum.
Eski yaptığım sistemde şuan kaz yumurtalarını koydum, o karadüzen çalıştığı için böyle sorunlarla karşılaşmıyorum. Kayınpeder tavuk yumurtalarını biriktirmeye başladı, bayramda çalıştırabilirsem çok güzel olacak :) :)
2-3 cm kısaltmaya gerek yok. Haftada 1 deneme yaparak sorun çözmek zor. Ama beslemeden gidelim. 3 röle kullanıyorsun gibi görünüyor.
1742824601976.png

5V olan röleler eğer bunlarla aynıysa 89mA akım çekiyorlar üçü aynı anda açılsa ~270mA çeker arduino ve ekran da 50mA çekse 320mA 9V beslemeden 5V'ye voltaj düşümünden 4*0,32=1,28W güç yapıyor.
Değerler regülatörün datasheetten, bazıları 150C/W bir tanesi 90C/W denk geldi >>>
1742825400043.png


SOT-223 kılıf için regülatörün junction sıcaklığı 90*1,28=115 derece + ortam sıcaklığı olur. Bu da iyimser hesap. Muhtemelen bu rölelerin beraber açıldığı bir süre denk gelince regülatör sıcaklıktan dolayı voltaj kesiyordur.

Önce arduinoyu USB girişten, USB şarj adaptörüyle beslemeyi deneyin, olmadı röle beslemesini ayırmayı denersiniz. En son kablolarla uğraşırsınız.
 
Sorun yazılımsal da olabilir. değişkenlerin taşıyor olabilir. Röle kartini söküp devreyi bir kaç gün acik bırakın. resetlenme olup olmadığını kontrol edin.
 
Kod:
#include <Wire.h>
#include <Adafruit_PCD8544.h>
#include <Adafruit_SHT31.h>
#include <RTClib.h>
#include <EEPROM.h>
#include <avr/wdt.h>

// Pin tanımlamaları
#define RELAY1 5        // Isıtıcı
#define RELAY2 6        // Nemlendirici
#define RELAY3 7        // Fan
#define RELAY4 8        // Motor
#define ROW1 22         // Tuş takımı satır 1
#define ROW2 24         // Tuş takımı satır 2
#define ROW3 26         // Tuş takımı satır 3
#define ROW4 28         // Tuş takımı satır 4
#define COL1 30         // Tuş takımı sütun 1
#define COL2 32         // Tuş takımı sütun 2
#define COL3 34         // Tuş takımı sütun 3
#define COL4 36         // Tuş takımı sütun 4
#define BACKLIGHT_PIN A5 // LCD Arka ışık

// SHT31 Sensör adresleri
#define SHT31_1_ADDR 0x44  // İlk sensör I2C adresi
#define SHT31_2_ADDR 0x45  // İkinci sensör I2C adresi

// EEPROM adres haritası
#define EEPROM_TYPE 0           // Kuluçka tipi (1 byte)
#define EEPROM_START_TIME 1     // Başlangıç zamanı (4 byte)
#define EEPROM_TEMP 5           // Hedef sıcaklık (4 byte)
#define EEPROM_HUM 9            // Hedef nem (4 byte)
#define EEPROM_ERROR_FLAG 13    // Hata durumu (1 byte)
#define EEPROM_TEMP_OFFSET 14   // Sıcaklık offset (4 byte)
#define EEPROM_HUM_OFFSET 18    // Nem offset (4 byte)
#define EEPROM_MOTOR_DURATION 22 // Motor çalışma süresi (4 byte)
#define EEPROM_MOTOR_INTERVAL 26 // Motor çalışma aralığı (4 byte)
#define EEPROM_CHECKSUM 30      // Veri doğrulama (1 byte)

// Menü durumları
#define MENU_MAIN 0          // Ana menü
#define MENU_SETTINGS 1      // Ayarlar menüsü
#define MENU_MOTOR 2         // Motor ayarları menüsü
#define MENU_SENSORS 3       // Sensör bilgileri menüsü
#define MENU_CALIBRATION 4   // Kalibrasyon menüsü

// Kontrol parametreleri
#define TEMP_HYSTERESIS 0.3  // Sıcaklık kontrolü için histerezis (0.3°C)
#define HUM_HYSTERESIS 2.0   // Nem kontrolü için histerezis (%2)
#define DEBOUNCE_DELAY 250   // Tuş kontrolü için debounce süresi (250ms)

// Zaman sabitleri
const unsigned long MOTOR_INTERVAL_DEFAULT = 7200000; // Motor dönüş aralığı (2 saat)
const unsigned long MOTOR_DURATION_DEFAULT = 3000;    // Motor çalışma süresi (3 saniye)
const unsigned long BACKLIGHT_TIMEOUT = 10000;        // Arka ışık kapanma süresi (10 saniye)
const unsigned long MESSAGE_DURATION = 2000;          // Mesaj gösterim süresi (2 saniye)
const unsigned long EEPROM_WRITE_INTERVAL = 300000;   // EEPROM yazma aralığı (5 dakika)

// Hata yönetimi için sabitler
#define MAX_ERRORS 3          // Maksimum ardışık hata sayısı
#define SENSOR_TIMEOUT 5000   // Sensör okuma zaman aşımı (ms)

// Veri yapıları
struct SensorData {
    float temp;         // Sıcaklık değeri
    float hum;          // Nem değeri
    bool isValid;       // Sensör verisi geçerli mi?
};

struct MotorSettings {
    unsigned long duration;  // Motor çalışma süresi
    unsigned long interval;  // Motor çalışma aralığı
};

struct IncubatorSettings {
    int type;               // Kuluçka tipi (0:Tavuk, 1:Kaz, 2:Bıldırcın, 3:Manuel, 4:Sıfırlama)
    float targetTemp;       // Hedef sıcaklık
    float targetHum;        // Hedef nem
    int totalDays;          // Toplam kuluçka süresi
    uint32_t startTime;     // Başlangıç zamanı (time_t yerine uint32_t kullanıyoruz)
    bool motorActive;       // Motor aktif mi?
    bool heaterState;       // Isıtıcı durumu
    bool humidifierState;   // Nemlendirici durumu
    float tempOffset;       // Sıcaklık kalibrasyon offseti
    float humOffset;        // Nem kalibrasyon offseti
};

struct ErrorManager {
    int tempErrors;         // Sıcaklık sensörü hata sayacı
    int humErrors;          // Nem sensörü hata sayacı
    int rtcErrors;          // RTC hata sayacı
    unsigned long lastSensorRead;   // Son sensör okuma zamanı
    unsigned long lastEEPROMWrite;  // Son EEPROM yazma zamanı
    bool safeMode;          // Güvenli mod aktif mi?
    
    ErrorManager() {
        tempErrors = 0;
        humErrors = 0;
        rtcErrors = 0;
        lastSensorRead = 0;
        lastEEPROMWrite = 0;
        safeMode = false;
    }
    
    void resetErrors() {
        tempErrors = 0;
        humErrors = 0;
        rtcErrors = 0;
    }
    
    bool checkSensor(float value, float min, float max) {
        if (isnan(value) || value < min || value > max) {
            return false;
        }
        return true;
    }
};

// Donanım nesneleri
Adafruit_PCD8544 lcd(A0, A1, A2, A3, A4);  // LCD ekran
Adafruit_SHT31 sht31_1 = Adafruit_SHT31();  // İlk SHT31 sensörü
Adafruit_SHT31 sht31_2 = Adafruit_SHT31();  // İkinci SHT31 sensörü
RTC_DS3231 rtc;                             // RTC modülü

// Global değişkenler
IncubatorSettings settings;           // Kuluçka ayarları
MotorSettings motorSettings;          // Motor ayarları
ErrorManager errorMgr;                // Hata yöneticisi
int currentMenu = MENU_MAIN;          // Mevcut menü durumu
bool inSubMenu = false;               // Alt menüde miyiz?
unsigned long lastKeyPressTime = 0;   // Son tuş basma zamanı
unsigned long lastDebounceTime = 0;   // Son debounce zamanı
bool backlightState = false;          // Arka ışık durumu
unsigned long previousMillis = 0;     // Önceki millis değeri
char lastKey = 0;                     // Son basılan tuş
float tempOffset = 0.0;               // Sıcaklık kalibrasyon offseti
float humOffset = 0.0;                // Nem kalibrasyon offseti

// Kuluçka tipi isimleri
const char* typeNames[] = {"Tavuk", "Kaz", "Bildircin", "Manuel"};

// Fonksiyon prototipleri
void handleMainMenu(char key);
void handleSettingsMenu(char key);
void handleMotorMenu(char key);
void handleCalibrationMenu(char key);
void handleNormalOperation(char key);
void showMainMenu();
void showSettingsMenu();
void showMotorMenu();
void showSensorInfo();
void showCalibrationMenu();
void showMessage(const char* message);
void showError(const char* message);
void setupChicken();
void setupGoose();
void setupQuail();
void setupManual();
void resetSystem();
void askForReset();
void saveState();
void savePersistentState();
void loadState();
void loadMotorSettings();
uint8_t calculateChecksum();
void updateSensorsAndControl();
void updateMainDisplay(float temp, float hum, int currentDay);
void updateBacklight();
void testMotor();
void controlMotor(uint32_t currentTime);
void controlTemperature(float currentTemp);
void controlHumidity(float currentHum);
void checkAndUpdateSettings(int currentDay);
void getAverageReadings(float &avgTemp, float &avgHum);
char getKey();
float getNumberInput();
void enterSafeMode(const char* errorMsg);
void calibrateTemperature();
void calibrateHumidity();
SensorData readSHT31_1();
SensorData readSHT31_2();
uint32_t getTimeFromRTC();
int getMotorCountdown();
void setMotorDuration();
void setMotorInterval();

// Saat çevirimi için yardımcı fonksiyon - time_t yerine uint32_t kullanıyoruz
uint32_t getTimeFromRTC() {
    DateTime now = rtc.now();
    return now.unixtime();  // .get() yerine .unixtime() kullanıyoruz
}

void setup() {
    Serial.begin(9600);
    Wire.begin();
    
    // Pin modlarını ayarla
    pinMode(RELAY1, OUTPUT);
    pinMode(RELAY2, OUTPUT);
    pinMode(RELAY3, OUTPUT);
    pinMode(RELAY4, OUTPUT);
    pinMode(ROW1, INPUT_PULLUP);
    pinMode(ROW2, INPUT_PULLUP);
    pinMode(ROW3, INPUT_PULLUP);
    pinMode(ROW4, INPUT_PULLUP);
    pinMode(COL1, OUTPUT);
    pinMode(COL2, OUTPUT);
    pinMode(COL3, OUTPUT);
    pinMode(COL4, OUTPUT);
    pinMode(BACKLIGHT_PIN, OUTPUT);

    // Başlangıç durumları
    digitalWrite(RELAY1, LOW);  // Isıtıcı kapalı
    digitalWrite(RELAY2, LOW);  // Nemlendirici kapalı
    digitalWrite(RELAY3, HIGH); // Fanlar sürekli çalışacak
    digitalWrite(RELAY4, LOW);  // Motor kapalı
    digitalWrite(BACKLIGHT_PIN, LOW); // Arka ışık kapalı

    // Röle durumlarını sıfırla
    settings.heaterState = false;
    settings.humidifierState = false;

    // LCD başlatma
    lcd.begin();
    lcd.setContrast(50);
    lcd.clearDisplay();
    lcd.setTextSize(1);
    lcd.setCursor(0,0);
    lcd.println("Kulucka");
    lcd.println("Makinesi v2.0");
    lcd.println("Baslatiliyor...");
    lcd.display();
    delay(2000);
    
    // Sensörleri başlat
    if (!sht31_1.begin(SHT31_1_ADDR)) {
        showError("Sensor 1 Hata!");
        delay(2000);
    }
    
    if (!sht31_2.begin(SHT31_2_ADDR)) {
        showError("Sensor 2 Hata!");
        delay(2000);
    }
    
    // Sensör heater'larını kapat
    sht31_1.heater(false);
    sht31_2.heater(false);
    
    // RTC başlatma - düzeltilmiş
    if (!rtc.begin()) {
        showError("RTC Hatasi!");
        delay(2000);
    }

    // RTC pil kontrolü
    if (rtc.lostPower()) {
        showError("RTC Pil Zayif!");
        delay(2000);
        rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
    }

    // EEPROM'dan ayarları yükle
    loadState();
    
    // Motor ayarlarını yükle
    loadMotorSettings();
    
    // İlk açılışta menüyü göster
    if (settings.type == 4 || settings.type == 255) {
        settings.type = 4;
        showMainMenu();
        currentMenu = MENU_MAIN;
    } else {
        // Normal çalışma modunda, ilk ekranı güncelle
        float avgTemp = 0.0, avgHum = 0.0;
        SensorData sensor1 = readSHT31_1();
        SensorData sensor2 = readSHT31_2();
        
        if (sensor1.isValid && sensor2.isValid) {
            avgTemp = (sensor1.temp + sensor2.temp) / 2.0;
            avgHum = (sensor1.hum + sensor2.hum) / 2.0;
        } else if (sensor1.isValid) {
            avgTemp = sensor1.temp;
            avgHum = sensor1.hum;
        } else if (sensor2.isValid) {
            avgTemp = sensor2.temp;
            avgHum = sensor2.hum;
        }
        
        uint32_t currentTime = getTimeFromRTC();
        int currentDay = 1; // Varsayılan olarak 1. gün
        
        if (settings.startTime > 0 && currentTime > settings.startTime) {
            currentDay = (currentTime - settings.startTime) / 86400 + 1;
            if (currentDay > settings.totalDays) {
                currentDay = settings.totalDays;
            }
        }
        
        updateMainDisplay(avgTemp, avgHum, currentDay);
        currentMenu = -1; // Normal çalışma modu
    }
    
    // Watchdog timer başlat - 8 saniye
    wdt_enable(WDTO_8S);
}

void loop() {
    // Watchdog timer'ı sıfırla
    wdt_reset();
    
    // Arka ışık kontrolü
    updateBacklight();
    
    // Tuş kontrolü
    char key = getKey();
    
    // Menü durumunu kontrol et
    if (currentMenu == MENU_SETTINGS) {
        if(key) {
            handleSettingsMenu(key);
        }
    }
    else if (currentMenu == MENU_MOTOR) {
        if(key) {
            handleMotorMenu(key);
        }
    }
    else if (currentMenu == MENU_CALIBRATION) {
        if(key) {
            handleCalibrationMenu(key);
        }
    }
    // Ana menü modu
    else if (settings.type == 4 || currentMenu == MENU_MAIN) {
        if(key) {
            handleMainMenu(key);
        }
    }
    // Normal çalışma modu
    else {
        // Sensör değerlerini oku ve kontrolleri yap
        updateSensorsAndControl();
        
        // Tuş işlemlerini yönet
        if(key) {
            handleNormalOperation(key);
        }
        
        // EEPROM'a periyodik kayıt
        savePersistentState();
    }
    
    // Gecikme - ana döngüyü yavaşlat
    delay(100);
}

void updateSensorsAndControl() {
    // Sensör değerlerini oku
    float avgTemp, avgHum;
    getAverageReadings(avgTemp, avgHum);
    
    uint32_t currentTime = getTimeFromRTC();
    int currentDay = 0;
    
    // Gün hesaplama güvenliği ekle
    if (settings.startTime > 0 && settings.startTime <= currentTime) {
        currentDay = (currentTime - settings.startTime) / 86400 + 1;
        
        // Geçersiz gün değerlerini düzelt
        if (currentDay <= 0 || currentDay > settings.totalDays) {
            currentDay = 1;
        }
    } else {
        currentDay = 1;
    }
    
    // Son günlerde özel ayarları kontrol et
    checkAndUpdateSettings(currentDay);
    
    // Sıcaklık kontrolü
    controlTemperature(avgTemp);
    
    // Nem kontrolü
    controlHumidity(avgHum);
    
    // Motor kontrolü
    controlMotor(currentTime);
    
    // Ekranı güncelle
    updateMainDisplay(avgTemp, avgHum, currentDay);
}

void handleMainMenu(char key) {
    switch(key) {
        case '1':
            setupChicken();
            showMessage("Tavuk secildi\n21 gun");
            currentMenu = -1; // Normal çalışma moduna geç
            break;
        case '2':
            setupGoose();
            showMessage("Kaz secildi\n30 gun");
            currentMenu = -1; // Normal çalışma moduna geç
            break;
        case '3':
            setupQuail();
            showMessage("Bildircin secildi\n18 gun");
            currentMenu = -1; // Normal çalışma moduna geç
            break;
        case '4':
            setupManual();
            currentMenu = -1; // Normal çalışma moduna geç
            break;
        case '5':
            showSettingsMenu();
            currentMenu = MENU_SETTINGS;
            break;
    }
}

void handleNormalOperation(char key) {
    switch(key) {
        case 'A': // Sıcaklık artır
            settings.targetTemp += 0.1;
            if(settings.targetTemp > 39.0) settings.targetTemp = 39.0;
            saveState();
            break;
        case 'B': // Sıcaklık azalt
            settings.targetTemp -= 0.1;
            if(settings.targetTemp < 35.0) settings.targetTemp = 35.0;
            saveState();
            break;
        case 'C': // Nem artır
            settings.targetHum += 1.0;
            if(settings.targetHum > 85) settings.targetHum = 85;
            saveState();
            break;
        case 'D': // Nem azalt
            settings.targetHum -= 1.0;
            if(settings.targetHum < 30) settings.targetHum = 30;
            saveState();
            break;
        case '5': // Ayarlar menüsüne git
            showSettingsMenu();
            currentMenu = MENU_SETTINGS;
            break;
        case '6': // Manuel motor kontrolü
            testMotor();
            break;
    }
}

void handleSettingsMenu(char key) {
    switch(key) {
        case '1': // Sıcaklık
            lcd.clearDisplay();
            lcd.setCursor(0,0);
            lcd.println("Sicaklik (C):");
            lcd.setCursor(0,8);
            lcd.print("Mevcut: ");
            lcd.println(settings.targetTemp, 1);
            lcd.setCursor(0,16);
            lcd.println("Yeni Deger:");
            lcd.display();
            
            settings.targetTemp = getNumberInput();
            if(settings.targetTemp < 35.0) settings.targetTemp = 35.0;
            if(settings.targetTemp > 39.0) settings.targetTemp = 39.0;
            saveState();
            showSettingsMenu();
            break;
            
        case '2': // Nem
            lcd.clearDisplay();
            lcd.setCursor(0,0);
            lcd.println("Nem (%):");
            lcd.setCursor(0,8);
            lcd.print("Mevcut: ");
            lcd.println(settings.targetHum, 1);
            lcd.setCursor(0,16);
            lcd.println("Yeni Deger:");
            lcd.display();
            
            settings.targetHum = getNumberInput();
            if(settings.targetHum < 30) settings.targetHum = 30;
            if(settings.targetHum > 85) settings.targetHum = 85;
            saveState();
            showSettingsMenu();
            break;
            
        case '3': // Motor
            showMotorMenu();
            currentMenu = MENU_MOTOR;
            break;
            
        case '4': // Kalibrasyon
            showCalibrationMenu();
            currentMenu = MENU_CALIBRATION;
            break;
            
        case '5': // Sensör bilgileri
            showSensorInfo();
            break;
            
        case '6': // Resetleme seçeneği (Ayarlar menüsünde güvenli)
            askForReset();
            break;
            
        case '*': // Geri
            if (settings.type == 4) {
                showMainMenu();
                currentMenu = MENU_MAIN;
            } else {
                currentMenu = -1; // Normal çalışma moduna dön
                // Geri dönerken ekranı güncelle
                float avgTemp, avgHum;
                getAverageReadings(avgTemp, avgHum);
                uint32_t currentTime = getTimeFromRTC();
                int currentDay = (currentTime - settings.startTime) / 86400 + 1;
                if (currentDay <= 0 || currentDay > settings.totalDays) currentDay = 1;
                updateMainDisplay(avgTemp, avgHum, currentDay);
            }
            break;
    }
}

void handleMotorMenu(char key) {
    // Loglama ekle
    Serial.print("Motor Menu Key: ");
    Serial.println(key);
    
    switch(key) {
        case '1': // Aralık değiştir
            setMotorInterval();
            break;
            
        case '2': // Süre değiştir
            setMotorDuration();
            break;
            
        case '*': // Geri tuşu
            showSettingsMenu();
            currentMenu = MENU_SETTINGS;
            break;
    }
}

void handleCalibrationMenu(char key) {
    switch(key) {
        case '1': // Sıcaklık kalibrasyonu
            calibrateTemperature();
            break;
            
        case '2': // Nem kalibrasyonu
            calibrateHumidity();
            break;
            
        case '*': // Geri tuşu
            showSettingsMenu();
            currentMenu = MENU_SETTINGS;
            break;
    }
}

/* Motor ayar fonksiyonları */
void setMotorDuration() {
    lcd.clearDisplay();
    lcd.setCursor(0,0);
    lcd.println("Sure (sn):");
    lcd.setCursor(0,8);
    lcd.print("Mevcut: ");
    lcd.println(motorSettings.duration / 1000);
    lcd.setCursor(0,16);
    lcd.println("Yeni Deger:");
    lcd.display();
    
    float seconds = getNumberInput();
    if(seconds < 1) seconds = 1;
    if(seconds > 30) seconds = 30;
    
    motorSettings.duration = seconds * 1000;
    EEPROM.put(EEPROM_MOTOR_DURATION, motorSettings.duration);
    
    showMotorMenu();
}

void setMotorInterval() {
    lcd.clearDisplay();
    lcd.setCursor(0,0);
    lcd.println("Aralik (dk):");
    lcd.setCursor(0,8);
    lcd.print("Mevcut: ");
    lcd.println(motorSettings.interval / 60000);
    lcd.setCursor(0,16);
    lcd.println("Yeni Deger:");
    lcd.display();
    
    float minutes = getNumberInput();
    if(minutes < 60) minutes = 60;
    if(minutes > 480) minutes = 480;
    
    motorSettings.interval = minutes * 60000;
    EEPROM.put(EEPROM_MOTOR_INTERVAL, motorSettings.interval);
    
    showMotorMenu();
}

void setupChicken() {
    settings.type = 0;
    settings.targetTemp = 37.8;  // Başlangıç sıcaklığı 37.8°C
    settings.targetHum = 65;     // Başlangıç nemi %65
    settings.totalDays = 21;
    settings.startTime = getTimeFromRTC();
    settings.motorActive = true;
    settings.heaterState = false;
    settings.humidifierState = false;
    saveState();
}

void setupGoose() {
    settings.type = 1;
    settings.targetTemp = 37.7;  // Başlangıç sıcaklığı 37.7°C
    settings.targetHum = 60;     // Başlangıç nemi %60
    settings.totalDays = 30;
    settings.startTime = getTimeFromRTC();
    settings.motorActive = true;
    settings.heaterState = false;
    settings.humidifierState = false;
    saveState();
}

void setupQuail() {
    settings.type = 2;
    settings.targetTemp = 37.7;  // Başlangıç sıcaklığı 37.7°C
    settings.targetHum = 65;     // Başlangıç nemi %65
    settings.totalDays = 18;
    settings.startTime = getTimeFromRTC();
    settings.motorActive = true;
    settings.heaterState = false;
    settings.humidifierState = false;
    saveState();
}

void setupManual() {
    settings.type = 3;
    
    lcd.clearDisplay();
    lcd.setCursor(0,0);
    lcd.println("Manuel Ayar");
    lcd.setCursor(0,8);
    lcd.println("Sicaklik (C):");
    lcd.display();
    
    float temp = getNumberInput();
    if(temp < 35.0) temp = 35.0;
    if(temp > 39.0) temp = 39.0;
    settings.targetTemp = temp;
    
    lcd.clearDisplay();
    lcd.setCursor(0,0);
    lcd.println("Nem (%):");
    lcd.display();
    float hum = getNumberInput();
    if(hum < 30) hum = 30;
    if(hum > 85) hum = 85;
    settings.targetHum = hum;
    
    lcd.clearDisplay();
    lcd.setCursor(0,0);
    lcd.println("Gun Sayisi:");
    lcd.display();
    int days = (int)getNumberInput();
    if(days < 1) days = 1;
    if(days > 60) days = 60;
    settings.totalDays = days;
    
    settings.startTime = getTimeFromRTC();
    settings.motorActive = true;
    settings.heaterState = false;
    settings.humidifierState = false;
    saveState();
}

void resetSystem() {
    settings.type = 4;
    saveState();
    showMainMenu();
}

void askForReset() {
    lcd.clearDisplay();
    lcd.setTextSize(1);
    lcd.setCursor(0,0);
    lcd.println("Sifirlama?");
    lcd.println("#-Evet *-Hayir");
    lcd.display();
    
    while(true) {
        char key = getKey();
        if(key == '#') {
            settings.type = 4;
            saveState();
            showMainMenu();
            currentMenu = MENU_MAIN;
            break;
        }
        else if(key == '*') {
            showSettingsMenu();
            currentMenu = MENU_SETTINGS;
            break;
        }
        
        // Watchdog resetleme
        wdt_reset();
    }
}

void checkAndUpdateSettings(int currentDay) {
    switch(settings.type) {
        case 0: // Tavuk
            if (currentDay >= 19) {
                settings.targetTemp = 37.5;  // Son 3 gün sıcaklık 37.5°C
                settings.targetHum = 75;     // Son 3 gün nem %75
                settings.motorActive = false;
            }
            break;
        case 1: // Kaz
            if (currentDay >= 27) {
                settings.targetTemp = 37.5;  // Son 4 gün sıcaklık 37.5°C
                settings.targetHum = 80;     // Son 4 gün nem %80
                settings.motorActive = false;
            }
            break;
        case 2: // Bıldırcın
            if (currentDay >= 16) {
                settings.targetTemp = 37.5;  // Son 3 gün sıcaklık 37.5°C
                settings.targetHum = 75;     // Son 3 gün nem %75
                settings.motorActive = false;
            }
            break;
    }
}

void controlTemperature(float currentTemp) {
    if(!errorMgr.safeMode) {
        if(currentTemp < (settings.targetTemp - TEMP_HYSTERESIS)) {
            digitalWrite(RELAY1, HIGH);
            settings.heaterState = true;
        }
        else if(currentTemp > (settings.targetTemp + TEMP_HYSTERESIS)) {
            digitalWrite(RELAY1, LOW);
            settings.heaterState = false;
        }
        // Histerezis aralığında durumu değiştirme
    }
}

void controlHumidity(float currentHum) {
    if(!errorMgr.safeMode) {
        if(currentHum < (settings.targetHum - HUM_HYSTERESIS)) {
            digitalWrite(RELAY2, HIGH);
            settings.humidifierState = true;
        }
        else if(currentHum > (settings.targetHum + HUM_HYSTERESIS)) {
            digitalWrite(RELAY2, LOW);
            settings.humidifierState = false;
        }
        // Histerezis aralığında durumu değiştirme
    }
}

void controlMotor(uint32_t currentTime) {
    if (!settings.motorActive || errorMgr.safeMode) return;
    
    unsigned long currentMillis = millis();
    if (currentMillis - previousMillis >= motorSettings.interval) {
        digitalWrite(RELAY4, HIGH);
        
        // Motor çalışma süresi
        lcd.clearDisplay();
        lcd.setCursor(0,0);
        lcd.println("Motor");
        lcd.println("Donduruluyor...");
        lcd.display();
        
        delay(motorSettings.duration);
        
        digitalWrite(RELAY4, LOW);
        previousMillis = currentMillis;
    }
}

void testMotor() {
    if(errorMgr.safeMode) {
        showMessage("Guvenli Mod!\nMotor Pasif");
        return;
    }
    
    lcd.clearDisplay();
    lcd.setCursor(0,0);
    lcd.println("Motor Test");
    lcd.println("Calistiriliyor...");
    lcd.display();
    
    digitalWrite(RELAY4, HIGH);
    delay(1000);
    digitalWrite(RELAY4, LOW);
    
    showMessage("Motor Testi\nTamamlandi");
}

SensorData readSHT31_1() {
    SensorData data;
    data.temp = sht31_1.readTemperature() + settings.tempOffset;
    data.hum = sht31_1.readHumidity() + settings.humOffset;
    data.isValid = (!isnan(data.temp) && !isnan(data.hum) &&
                     data.temp > -10 && data.temp < 60 &&
                     data.hum >= 0 && data.hum <= 100);
    return data;
}

SensorData readSHT31_2() {
    SensorData data;
    data.temp = sht31_2.readTemperature() + settings.tempOffset;
    data.hum = sht31_2.readHumidity() + settings.humOffset;
    data.isValid = (!isnan(data.temp) && !isnan(data.hum) &&
                     data.temp > -10 && data.temp < 60 &&
                     data.hum >= 0 && data.hum <= 100);
    return data;
}

void getAverageReadings(float &avgTemp, float &avgHum) {
    SensorData sensor1 = readSHT31_1();
    SensorData sensor2 = readSHT31_2();
    
    if(sensor1.isValid && sensor2.isValid) {
        avgTemp = (sensor1.temp + sensor2.temp) / 2.0;
        avgHum = (sensor1.hum + sensor2.hum) / 2.0;
        
        // Sensörlerin farkı çok fazlaysa uyarı - fark eşiğini 15 dereceye yükselttik
        if(abs(sensor1.temp - sensor2.temp) > 15.0) {
            errorMgr.tempErrors++;
            if(errorMgr.tempErrors > MAX_ERRORS) {
                enterSafeMode("Sicaklik Fark!\nCok Fazla!");
            }
        } else {
            errorMgr.tempErrors = 0;
        }
    }
    else if(sensor1.isValid) {
        // Tek sensör çalışıyorsa hata sayacını artırma, normal çalışmaya devam et
        avgTemp = sensor1.temp;
        avgHum = sensor1.hum;
        // errorMgr.tempErrors++ satırını kaldırdık
    }
    else if(sensor2.isValid) {
        // Tek sensör çalışıyorsa hata sayacını artırma, normal çalışmaya devam et
        avgTemp = sensor2.temp;
        avgHum = sensor2.hum;
        // errorMgr.tempErrors++ satırını kaldırdık
    }
    else {
        // Tüm sensörler arızalıysa güvenli moda geç
        errorMgr.tempErrors++;
        if(errorMgr.tempErrors > MAX_ERRORS) {
            enterSafeMode("Tum Sensorler\nHatali!");
        }
        
        // Geçersiz değerler
        avgTemp = 0;
        avgHum = 0;
    }
}

int getMotorCountdown() {
    unsigned long timeSinceLastMotor = millis() - previousMillis;
    if(timeSinceLastMotor >= motorSettings.interval) return 0;
    
    return (motorSettings.interval - timeSinceLastMotor) / 60000;
}

void loadState() {
    // EEPROM'dan veri oku
    uint8_t storedType;
    EEPROM.get(EEPROM_TYPE, storedType); // Önce bir byte olarak oku
    
    // EEPROM ilk kez kullanılıyorsa veya geçersiz değer varsa
    if (storedType == 255 || storedType < 0 || storedType > 4) {
        settings.type = 4; // Sıfırlama durumu - kuluçka tipi seçimi
        settings.targetTemp = 37.5; // Varsayılan sıcaklık
        settings.targetHum = 65.0;  // Varsayılan nem
        settings.totalDays = 0;
        settings.startTime = 0;     // Başlangıç zamanı 0 olarak ayarla
        settings.motorActive = false;
        settings.heaterState = false;
        settings.humidifierState = false;
        settings.tempOffset = 0;
        settings.humOffset = 0;
        
        // Varsayılanları EEPROM'a kaydet
        EEPROM.put(EEPROM_TYPE, settings.type);
        EEPROM.put(EEPROM_START_TIME, settings.startTime);
        EEPROM.put(EEPROM_TEMP, settings.targetTemp);
        EEPROM.put(EEPROM_HUM, settings.targetHum);
        EEPROM.put(EEPROM_TEMP_OFFSET, settings.tempOffset);
        EEPROM.put(EEPROM_HUM_OFFSET, settings.humOffset);
        
        return;
    }
    
    // Geçerli bir kuluçka tipi varsa diğer ayarları oku
    settings.type = storedType;
    EEPROM.get(EEPROM_START_TIME, settings.startTime);
    EEPROM.get(EEPROM_TEMP, settings.targetTemp);
    EEPROM.get(EEPROM_HUM, settings.targetHum);
    EEPROM.get(EEPROM_TEMP_OFFSET, tempOffset);
    EEPROM.get(EEPROM_HUM_OFFSET, humOffset);
    settings.tempOffset = tempOffset;
    settings.humOffset = humOffset;
    
    // Tutarlılık kontrolü - değerler mantıklı aralıkta değilse düzelt
    if (settings.targetTemp < 30.0 || settings.targetTemp > 40.0) {
        settings.targetTemp = 37.5; // Varsayılan sıcaklık
    }
    
    if (settings.targetHum < 0.0 || settings.targetHum > 100.0) {
        settings.targetHum = 65.0; // Varsayılan nem
    }
    
    // RTC kontrolü - startTime çok eski veya gelecekte ise düzelt
    uint32_t currentTime = getTimeFromRTC();
    if (settings.startTime > currentTime || (currentTime - settings.startTime) > 86400 * 60) { // 60 günden eski ise
        // RTC ile ayarla
        settings.startTime = currentTime;
        EEPROM.put(EEPROM_START_TIME, settings.startTime);
    }
}

void loadMotorSettings() {
    EEPROM.get(EEPROM_MOTOR_DURATION, motorSettings.duration);
    EEPROM.get(EEPROM_MOTOR_INTERVAL, motorSettings.interval);
    
    // Geçersiz değerler için varsayılanları kullan
    if (motorSettings.duration < 1000 || motorSettings.duration > 30000) {
        motorSettings.duration = MOTOR_DURATION_DEFAULT;
    }
    if (motorSettings.interval < 3600000 || motorSettings.interval > 28800000) {
        motorSettings.interval = MOTOR_INTERVAL_DEFAULT;
    }
}

void saveState() {
    EEPROM.put(EEPROM_TYPE, settings.type);
    EEPROM.put(EEPROM_START_TIME, settings.startTime);
    EEPROM.put(EEPROM_TEMP, settings.targetTemp);
    EEPROM.put(EEPROM_HUM, settings.targetHum);
    EEPROM.put(EEPROM_TEMP_OFFSET, settings.tempOffset);
    EEPROM.put(EEPROM_HUM_OFFSET, settings.humOffset);
    
    // Checksum hesapla ve kaydet
    uint8_t checksum = calculateChecksum();
    EEPROM.put(EEPROM_CHECKSUM, checksum);
}

// Kalıcı durum kaydetme - sadece değişen verileri kaydet
void savePersistentState() {
    static uint8_t lastType = 255;
    static float lastTargetTemp = 0;
    static float lastTargetHum = 0;
    static unsigned long lastSaveTime = 0;
    
    // EEPROM'a çok sık yazma yapmamak için - en fazla 5 dakika arayla
    if (millis() - lastSaveTime < EEPROM_WRITE_INTERVAL) {
        return;
    }
    
    // Sadece değişen değerleri kaydet - EEPROM ömrünü uzatır
    if (settings.type != lastType) {
        EEPROM.put(EEPROM_TYPE, settings.type);
        lastType = settings.type;
    }
    
    if (abs(settings.targetTemp - lastTargetTemp) > 0.1) {
        EEPROM.put(EEPROM_TEMP, settings.targetTemp);
        lastTargetTemp = settings.targetTemp;
    }
    
    if (abs(settings.targetHum - lastTargetHum) > 0.1) {
        EEPROM.put(EEPROM_HUM, settings.targetHum);
        lastTargetHum = settings.targetHum;
    }
    
    // Sadece 6 saatte bir startTime güncelle (çok sık yazma yapma)
    static unsigned long lastTimeUpdate = 0;
    if (millis() - lastTimeUpdate > 21600000) { // 6 saat
        EEPROM.put(EEPROM_START_TIME, settings.startTime);
        lastTimeUpdate = millis();
    }
    
    lastSaveTime = millis();
}

// Checksum hesaplama
uint8_t calculateChecksum() {
    uint8_t checksum = 0;
    
    // settings içindeki kritik değerleri kullanarak basit bir checksum oluştur
    checksum += settings.type;
    checksum += (uint8_t)(settings.targetTemp * 10);
    checksum += (uint8_t)(settings.targetHum * 10);
    checksum += (uint8_t)(settings.totalDays);
    
    // Başlangıç zamanından da bir değer al
    checksum += (uint8_t)(settings.startTime & 0xFF);
    
    return checksum;
}

void showMainMenu() {
    lcd.clearDisplay();
    lcd.setTextSize(1);
    lcd.setCursor(0,0);
    lcd.println("Kulucka Tipi:");
    lcd.setCursor(0,8);
    lcd.println("1-Tavuk");
    lcd.setCursor(0,16);
    lcd.println("2-Kaz");
    lcd.setCursor(0,24);
    lcd.println("3-Bildircin");
    lcd.setCursor(0,32);
    lcd.println("4-Manuel");
    lcd.setCursor(0,40);
    lcd.println("5-Ayarlar");
    lcd.display();
}

void showSettingsMenu() {
    lcd.clearDisplay();
    lcd.setTextSize(1);
    lcd.setCursor(0,0);
    lcd.println("Ayarlar:");
    lcd.setCursor(0,8);
    lcd.println("1-Sicaklik");
    lcd.setCursor(0,16);
    lcd.println("2-Nem");
    lcd.setCursor(0,24);
    lcd.println("3-Motor");
    lcd.setCursor(0,32);
    lcd.println("4-Kalibrasyon");
    lcd.setCursor(0,40);
    lcd.println("5-Sens  6-Reset");
    lcd.display();
}

void showMotorMenu() {
    lcd.clearDisplay();
    lcd.setTextSize(1);
    lcd.setCursor(0,0);
    lcd.println("Motor Ayarlari:");
    lcd.setCursor(0,8);
    lcd.print("Aralik: ");
    lcd.print(motorSettings.interval / 60000);
    lcd.println(" dk");
    lcd.setCursor(0,16);
    lcd.print("Sure: ");
    lcd.print(motorSettings.duration / 1000);
    lcd.println(" sn");
    lcd.setCursor(0,24);
    lcd.println("1-Aralik D.");
    lcd.setCursor(0,32);
    lcd.println("2-Sure D.");
    lcd.display();
}

void showSensorInfo() {
    lcd.clearDisplay();
    lcd.setTextSize(1);
    lcd.setCursor(0,0);
    lcd.println("Sensor Bilgileri:");
    
    SensorData sensor1 = readSHT31_1();
    SensorData sensor2 = readSHT31_2();
    
    lcd.setCursor(0,8);
    lcd.print("S1: ");
    if (sensor1.isValid) {
        lcd.print(sensor1.temp, 1);
        lcd.print("C ");
        lcd.print(sensor1.hum, 1);
        lcd.print("%");
    } else {
        lcd.print("Hata!");
    }
    
    lcd.setCursor(0,16);
    lcd.print("S2: ");
    if (sensor2.isValid) {
        lcd.print(sensor2.temp, 1);
        lcd.print("C ");
        lcd.print(sensor2.hum, 1);
        lcd.print("%");
    } else {
        lcd.print("Hata!");
    }
    
    lcd.setCursor(0,24);
    lcd.print("Fark: ");
    if (sensor1.isValid && sensor2.isValid) {
        lcd.print(abs(sensor1.temp - sensor2.temp), 1);
        lcd.print("C ");
        lcd.print(abs(sensor1.hum - sensor2.hum), 1);
        lcd.print("%");
    } else {
        lcd.print("--");
    }
    
    lcd.display();
    
    // Tuş bekle
    while(true) {
        char key = getKey();
        if(key == '*') {
            showSettingsMenu();
            currentMenu = MENU_SETTINGS;
            break;
        }
        wdt_reset(); // Watchdog'u resetle
    }
}

void showCalibrationMenu() {
    lcd.clearDisplay();
    lcd.setTextSize(1);
    lcd.setCursor(0,0);
    lcd.println("Kalibrasyon:");
    
    lcd.setCursor(0,12);
    lcd.print("Sicaklik: ");
    lcd.print(settings.tempOffset, 1);
    lcd.println("C");
    
    lcd.setCursor(0,24);
    lcd.print("Nem: ");
    lcd.print(settings.humOffset, 1);
    lcd.println("%");
    
    lcd.setCursor(0,36);
    lcd.println("1-Sicak. 2-Nem Kal.");
    
    lcd.display();
}

void showMessage(const char* message) {
    lcd.clearDisplay();
    lcd.setTextSize(1);
    lcd.setCursor(0,16);
    lcd.println(message);
    lcd.display();
    delay(MESSAGE_DURATION);
}

void showError(const char* message) {
    lcd.clearDisplay();
    lcd.setTextSize(1);
    lcd.setCursor(0,0);
    lcd.println("HATA!");
    lcd.setCursor(0,16);
    lcd.println(message);
    lcd.display();
}

void updateMainDisplay(float temp, float hum, int currentDay) {
    lcd.clearDisplay();
    lcd.setTextSize(1);
    
    // Sıcaklık gösterimi
    lcd.setCursor(0,0);
    lcd.print("S:");
    if (temp < 100 && temp > -40) {
        lcd.print(temp, 1);
        lcd.print(settings.heaterState ? "+" : " ");
    } else {
        lcd.print("--.-");
    }
    lcd.print("/");
    lcd.print(settings.targetTemp, 1);
    lcd.print("C");
    
    // Nem gösterimi
    lcd.setCursor(0,8);
    lcd.print("N:");
    if (hum < 100 && hum >= 0) {
        lcd.print(hum, 1);
        lcd.print(settings.humidifierState ? "+" : " ");
    } else {
        lcd.print("--.-");
    }
    lcd.print("/");
    lcd.print(settings.targetHum, 1);
    lcd.print("%");
    
    // Gün ve tür gösterimi
    lcd.setCursor(0,16);
    lcd.print("G:");
    if (currentDay > 0 && currentDay <= settings.totalDays) {
        lcd.print(currentDay);
        lcd.print("/");
        lcd.print(settings.totalDays);
    } else {
        lcd.print("--/--");
    }
    
    lcd.setCursor(0,24);
    if (settings.type >= 0 && settings.type <= 3) {
        lcd.print(typeNames[settings.type]);
        
        // Motor zamanını göster
        if (settings.motorActive) {
            lcd.print(" M:");
            lcd.print(getMotorCountdown());
            lcd.print("dk");
        }
    }
    
    // Saat gösterimi
    DateTime now = rtc.now();
    lcd.setCursor(0,32);
    if (now.hour() < 10) lcd.print("0");
    lcd.print(now.hour());
    lcd.print(":");
    if (now.minute() < 10) lcd.print("0");
    lcd.print(now.minute());

    // Alt bilgi satırı - hangi sensörlerin aktif olduğunu göster
    lcd.setCursor(0,40);
    if (currentDay > 0 && currentDay <= settings.totalDays &&
        currentDay >= settings.totalDays - 2) {
        lcd.print("!SON GUNLER!");
    } else if (errorMgr.safeMode) {
        lcd.print("!GUVENLI MOD!");
    } else {
        // Aktif sensörleri göster
        SensorData sensor1 = readSHT31_1();
        SensorData sensor2 = readSHT31_2();
        lcd.print("S:");
        lcd.print(sensor1.isValid ? "1" : "-");
        lcd.print(sensor2.isValid ? "2" : "-");
        lcd.print(" 5-Menu 6-Motor");
    }
    
    lcd.display();
}

void updateBacklight() {
    unsigned long currentTime = millis();
    if (backlightState && (currentTime - lastKeyPressTime >= BACKLIGHT_TIMEOUT)) {
        digitalWrite(BACKLIGHT_PIN, LOW);
        backlightState = false;
    }
}

char getKey() {
    static unsigned long lastDebounceTime = 0;
    static char lastKey = 0;
    const unsigned long debounceDelay = 250; // Tuş sıçraması için daha kısa bekleme süresi
    
    char keys[4][4] = {
        {'1','2','3','A'},
        {'4','5','6','B'},
        {'7','8','9','C'},
        {'*','0','#','D'}
    };
    
    // Geçen son tuş basma süresini kontrol et
    unsigned long currentTime = millis();
    if (currentTime - lastDebounceTime < debounceDelay) {
        return 0; // Debounce süresi dolmadan yeni tuş algılamayı reddet
    }
    
    for(int i = 0; i < 4; i++) {
        digitalWrite(COL1 + i*2, LOW);
        for(int j = 0; j < 4; j++) {
            if(digitalRead(ROW1 + j*2) == LOW) {
                // Tuş basıldığında arka ışığı aç
                lastKeyPressTime = currentTime;
                if (!backlightState) {
                    digitalWrite(BACKLIGHT_PIN, HIGH);
                    backlightState = true;
                }
                
                digitalWrite(COL1 + i*2, HIGH);
                lastDebounceTime = currentTime; // Debounce zamanını güncelle
                return keys[j][i];
            }
        }
        digitalWrite(COL1 + i*2, HIGH);
    }
    return 0;
}

float getNumberInput() {
    String input = "";
    bool hasDecimal = false;
    
    while(true) {
        char key = getKey();
        if(key) {
            if(key >= '0' && key <= '9') {
                if(input.length() < 5) { // Maksimum 5 karakter
                    input += key;
                    lcd.print(key);
                    lcd.display();
                }
            }
            else if(key == '*' && !hasDecimal) {
                if(!input.length()) input = "0";
                input += '.';
                hasDecimal = true;
                lcd.print('.');
                lcd.display();
            }
            else if(key == '#' && input.length() > 0) {
                return input.toFloat();
            }
        }
        
        // Watchdog resetleme
        wdt_reset();
    }
}

void calibrateTemperature() {
    lcd.clearDisplay();
    lcd.setCursor(0,0);
    lcd.println("Sicaklik Kalibr.:");
    lcd.setCursor(0,8);
    lcd.println("Referans olcum:");
    lcd.display();
    
    float refTemp = getNumberInput();
    
    // Sensör değerlerini oku
    float avgTemp, avgHum;
    getAverageReadings(avgTemp, avgHum);
    
    // Offset hesapla
    float newOffset = refTemp - (avgTemp - settings.tempOffset);
    settings.tempOffset = newOffset;
    tempOffset = newOffset;
    
    EEPROM.put(EEPROM_TEMP_OFFSET, tempOffset);
    
    lcd.clearDisplay();
    lcd.setCursor(0,0);
    lcd.println("Kalibrasyon");
    lcd.println("Tamamlandi");
    lcd.setCursor(0,16);
    lcd.print("Yeni Offset: ");
    lcd.print(settings.tempOffset, 1);
    lcd.display();
    delay(2000);
    
    showCalibrationMenu();
}

void calibrateHumidity() {
    lcd.clearDisplay();
    lcd.setCursor(0,0);
    lcd.println("Nem Kalibr.:");
    lcd.setCursor(0,8);
    lcd.println("Referans olcum:");
    lcd.display();
    
    float refHum = getNumberInput();
    
    // Sensör değerlerini oku
    float avgTemp, avgHum;
    getAverageReadings(avgTemp, avgHum);
    
    // Offset hesapla
    float newOffset = refHum - (avgHum - settings.humOffset);
    settings.humOffset = newOffset;
    humOffset = newOffset;
    
    EEPROM.put(EEPROM_HUM_OFFSET, humOffset);
    
    lcd.clearDisplay();
    lcd.setCursor(0,0);
    lcd.println("Kalibrasyon");
    lcd.println("Tamamlandi");
    lcd.setCursor(0,16);
    lcd.print("Yeni Offset: ");
    lcd.print(settings.humOffset, 1);
    lcd.display();
    delay(2000);
    
    showCalibrationMenu();
}

void enterSafeMode(const char* errorMsg) {
    if (!errorMgr.safeMode) {
        errorMgr.safeMode = true;
        
        // Tüm çıkışları güvenli duruma al
        digitalWrite(RELAY1, LOW);  // Isıtıcıyı kapat
        digitalWrite(RELAY2, LOW);  // Nemlenidiriciyi kapat
        digitalWrite(RELAY4, LOW);  // Motoru kapat
        digitalWrite(RELAY3, HIGH); // Fanı çalıştır
        
        // Durumları güncelle
        settings.heaterState = false;
        settings.humidifierState = false;
        
        showError(errorMsg);
        
        // Hata durumunu EEPROM'a kaydet
        EEPROM.write(EEPROM_ERROR_FLAG, 1);
    }
}

Kod güncellemesiyle uğraştım biraz. Herhangi bir elektrik kesintisi veya sistem resetlenmesi/donması halinde kendini resetleyip kaldığı yerden devam edecek şekilde revize edildi.
Donanımdan kaynaklanabilecek sorunu bu şekilde biraz aşabileceğimi düşündüm.
Kablo düzenlemesi, röle beslemesini ayırmayı da yaptığımda daha stabil çalışır diye umuyorum.

Kodlama bilgim de yok, tamamen yapay zekaya yazdırıp proteusta simülasyon yaparak buraya kadar getirdim
 
role-karti-devre-semasi.png
Harici besleme için biraz kafam karıştı.
Gnd ler ortak olacak, burası tamam.
Vcc ve jd-vcc deki jumper i çıkarıp, harici 5v jd-vcc pinine bağlanacak. Vcc arduinodan gelen 5v ile bağlı kalacak mı?
Buradaki şemada böyle göstermiş.

Başka kaynaklarda iki pine de harici 5v verin diyen de var.

hangisi doğru bağlantı şekli olur?
 
41079 eklentisine bak
Harici besleme için biraz kafam karıştı.
Gnd ler ortak olacak, burası tamam.
Vcc ve jd-vcc deki jumper i çıkarıp, harici 5v jd-vcc pinine bağlanacak. Vcc arduinodan gelen 5v ile bağlı kalacak mı?
Buradaki şemada böyle göstermiş.

Başka kaynaklarda iki pine de harici 5v verin diyen de var.

hangisi doğru bağlantı şekli olur?
Kullandığınız röle kartının devre şemasına bakmak lazım. Ama bağlantı girişlerinin isimlerini görünecek şekilde fotoğraflasanız da anlaşılabilir. Ayrı beslemeye ihtiyaç kalmayabilir. Arduinoyu USB girişinden 5V ile beslediğinizde üzerindeki regülatör devre dışı kalır ve ısınma derdi olmaz, voltaj düşmez.

Eğer bu durumda da çalışmaz ise röleler açılır-kapanırken arduinonun resetleniyor olduğunu varsayarak röle kartının beslemesini ayrırsınız. Bununla beraber @triyak 'ın önerdiği gibi röle kartı bağlı değilken açık bekletmeyi deneyin, kodda bir hata olup da sorun çıkıyor da olabilir. Yani elinizdeki imkanlarla test ekipmanları kullanmadan bunları denemek çözüme götürebilir.

Röle kartını bir görmek lazım
1743099710888.png

jumper çıkarıldığında ve röle kartı harici besleme ile beslendiğinde GND'ler birleştirilmemeli.

@mkara Aslında Fotoğraftaki açıklama teknik olarak doğru değil. Jumper takılıyken optokuplör devre dışı değil, hala çalışıyor fakat izolasyon işlevini yerine getirmiyor. Jumper çıkarıldığındaki devre şemasında optokuplör aynı şekilde çalışıyor fakat bu sefer izolasyon da sağlanmış oluyor. Tabii bunun için röle kartı ve arduinonun 5V ve GND'leri birbirinden ayrıolmalı, yani izole kaynaklarla beslenmeli
 
Son düzenleme:
images (1).jpeg
Kullandığım röle kartı birebir olarak bu.
Arduinoyu 9v 1a adaptör ile besliyorum. Yaklaşık 15 saat rölesiz çalıştırdım resetleme yapmadı.
Röleleri beslemek için 5v 2a bir adaptör daha aldım şimdi.
Sinyallerin doğru gitmesi için gnd ler ortak bağlanmalı denmiş birkaç eğitim videosunda.

Yapay zekaya şöyle bir soru sordum;

"Jumper zaten aradaki bağlantıyı sağlamıyor mu? Neden jumper ı çıkartıp iki yerden besleme yapılıyor? Sadece vcc pinine harici 5v verip jumper takılı olduğu durumda jd-vcc pini de beslenmiş olmazmı"

Kod:
Bu soru çok iyi bir nokta. Aslında röle kartlarındaki jumper'ın işlevi tam olarak bu. Biraz daha açıklama gerekiyor.

Röle kartında:

1. VCC: Optokuplörler ve kontrol mantığı için güç girişi
2. JD-VCC: Röle bobinleri için güç girişi

Jumper'ın durumları:

1. Jumper TAKILI iken:
   - VCC'ye verilen güç, jumper üzerinden JD-VCC'ye de aktarılır
   - Yani sadece VCC'ye güç vermek yeterlidir
   - Bu durumda röle bobinleri ve kontrol mantığı aynı güç kaynağını paylaşır

2. Jumper ÇIKARILDIĞINDA:
   - VCC ve JD-VCC arasında bağlantı kesilir
   - Her ikisine de ayrı ayrı güç verilmesi gerekir
   - Bu durumda tam izolasyon sağlanır

Kullanıcının sorusu tamamen haklı. Eğer harici beslemeyi sadece VCC'ye bağlayıp jumper'ı takılı bırakırsak, hem kontrol mantığı hem de röle bobinleri beslenmiş olur.

Ancak jumper'ı çıkarmamız ve iki beslemeden bahsetmemizin nedeni, genel olarak bu tür röle kartlarıyla çalışırken iki farklı güç seviyesine ihtiyaç duyulabilmesidir:

1. Mantık seviyesi: 3.3V veya 5V (VCC'ye bağlanır)
2. Röle bobinleri: Genellikle 5V veya 12V (JD-VCC'ye bağlanır)

Bazı durumlarda, mantık girişi için Arduino'nun 3.3V'unu kullanırken, röle bobinleri için 5V veya 12V kullanmak isteyebilirsiniz. Bu durumda jumper'ı çıkarıp farklı besleme yapmak gerekir.

Ancak bu kullanıcının durumunda, tüm sistem 5V seviyesinde çalışacağı için, kullanıcının dediği tamamen doğru:

> Sadece VCC pinine harici 5V verip jumper takılı olduğu durumda JD-VCC pini de beslenmiş olur.

Bu şekilde de bağlantı çalışır ve daha basittir. Tek dezavantajı, bu yapılandırmada Arduino ve röle bobinleri arasında tam izolasyon olmayacak olmasıdır, ama her şey aynı harici güç kaynağından beslendiği için bu genellikle sorun olmaz.

# Röle Kartı Jumper ve Besleme Bağlantısı Açıklaması

Haklısınız! Bu önemli bir noktayı açıklığa kavuşturmuş oldunuz.

## Jumper'ın İşlevi ve Besleme Seçenekleri

Röle kartındaki jumper tam olarak bu amaçla var - VCC ve JD-VCC arasında bağlantı sağlamak için.

### Seçenek 1: Jumper TAKILI (Basit Bağlantı)
- Sadece VCC pinine harici 5V bağlanır
- Jumper, VCC'den JD-VCC'ye güç aktarır
- **Tek besleme noktası** yeterlidir
- Bu durumda röle kontrol mantığı ve bobinleri aynı kaynaktan beslenir

### Seçenek 2: Jumper ÇIKARILMIŞ (Tam İzolasyon)
- VCC ve JD-VCC arasında bağlantı kesilir
- Her ikisine de ayrı ayrı güç verilmesi gerekir
- Bu genellikle farklı voltaj seviyeleri gerektiren durumlarda kullanılır:
  * VCC: 3.3V (düşük güç mantık devreleri için)
  * JD-VCC: 5V veya 12V (röle bobinleri için)

## Sizin Durumunuzda En İyi Çözüm

Eğer tüm sisteminiz 5V seviyesinde çalışacaksa (Arduino ve röle bobinleri aynı voltaj), o zaman **sizin önerdiğiniz şekilde** bağlantı yapmak tamamen doğru ve daha basittir:

1. VCC pinine harici 5V bağlayın
2. Jumper'ı TAKILI bırakın
3. GND pinini Arduino GND ve harici besleme GND ile bağlayın

Bu yapılandırma:
- Daha az kablo gerektirir
- Kurulumu basitleştirir
- Aynı güç seviyesi (5V) kullanıldığı için sorun oluşturmaz

## Neden Bazen Jumper Çıkarılır?

Jumper genellikle şu durumlarda çıkarılır:
- Farklı voltaj seviyeleri kullanılacaksa (3.3V mantık, 5V/12V röle)
- Yüksek elektromanyetik gürültü olan ortamlarda tam izolasyon gerekiyorsa
- Çok hassas analog ölçümler yapan sistemlerde gürültü azaltmak için

Kuluçka makineniz için, jumper takılı kalabilir ve sadece VCC'ye harici 5V bağlamanız yeterli olacaktır. Bu, daha basit ve tamamen uygun bir çözümdür.
 
Yapay zekayı boşver. Biraz ısrar etsen halanın erkek olduğunu kabul ettirebilirsin.

>>GND'ler izole kullanımda birleştirilmemeli<< aksi taktirde izolasyon olmamış oluyor, röleler yine çalışır orası ayrı.

Fotoğraflarda tarif edilen kullanım şekli doğru. Ama eğer kodlamadan kaynaklanmıyorsa. tek 5V besleme ile kullanabileceğini düşünüyorum.
 

Forum istatistikleri

Konular
7,528
Mesajlar
126,215
Üyeler
3,053
Son üye
xo88name

Son kaynaklar

Son profil mesajları

Python Geliştirmeye eklediğim yapay zeka sunucusu, yeni başlayanlar için roket etkisi
Bir insanın zeka seviyesinin en kolay tesbiti, sorduğu sorulardır.
yapay zeka interneti yedi bitirdi, arama motoru kullanan, forumlara yazan kaldı mı ?
Freemont2.0 herbokolog Freemont2.0 wrote on herbokolog's profile.
nick iniz yakıyor
:D
Freemont2.0 posta Freemont2.0 wrote on posta's profile.
Merhabalar :)
Back
Top