#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <DHT.h>
#include <RTClib.h> // RTC için doğru kütüphane
// --- Donanım Ayarları ---
#define DHTPIN 2
#define DHTTYPE DHT22
#define RELAY_HEAT 3
#define RELAY_HUMIDITY 4
#define RELAY_FAN 5
#define RELAY_TURNER 6
#define BUZZER_PIN 7
#define JOY_X A0
#define JOY_Y A1
#define JOY_BTN 8
DHT dht(DHTPIN, DHTTYPE);
LiquidCrystal_I2C lcd(0x27, 16, 2);
RTC_DS3231 rtc; // RTC nesnesi
// --- Sistem Değişkenleri ---
enum Mode { NORMAL, HATCH };
Mode currentMode = NORMAL;
struct EggProfile {
String name;
int incubationDays;
float tempMinNormal;
float tempMaxNormal;
int humMinNormal;
int humMaxNormal;
float tempMinHatch;
float tempMaxHatch;
int humMinHatch;
int humMaxHatch;
};
EggProfile profiles[] = {
{"Tavuk", 21, 37.3, 37.7, 55, 60, 37.0, 37.3, 70, 75},
{"Kaz", 30, 37.2, 37.6, 55, 60, 36.8, 37.0, 80, 90},
{"Hindi", 28, 37.3, 37.7, 55, 60, 37.0, 37.3, 70, 75},
{"Bildircin", 17, 37.3, 37.7, 45, 55, 37.0, 37.2, 65, 75}
};
int selectedProfile = 0;
int hatchDaysBefore = 3;
float temperature;
float humidity;
DateTime startTime; // RTC tarih ve saat
bool incubating = false;
bool turningEnabled = true;
// Viyol döndürme zamanlayıcıları
unsigned long lastTurnTime = 0; // Son viyol çevirme zamanı
unsigned long turnInterval = 60000; // 1 dakika (60000 milisaniye)
unsigned long turnDuration = 60000; // 10 saniye süreyle viyol döndürme
unsigned long remainingTime = 0; // Kalan süre milisaniye cinsinden
unsigned long lastTimeChecked = 0;
// LCD Özel Karakterler
byte eggIcon[8] = { B00000, B00100, B01110, B10101, B01110, B00100, B00000, B00000 }; // Yumurta simgesi
byte checkIcon[8] = { B11111, B10001, B10101, B11011, B10101, B10001, B11111, B00000 }; // Onay simgesi
byte hatchIcon[8] = { B00100, B01010, B01010, B00100, B01010, B01010, B00100, B00000 }; // Çıkım simgesi
byte heatSymbol[8] = { B00100, B01010, B01010, B00100, B00100, B01010, B10001, B01110 }; // Isıtıcı simgesi
byte humiditySymbol[8] = { B00100, B00100, B01010, B10001, B10001, B10001, B01110, B00000 }; // Nemlendirici simgesi
byte fanSymbol[8] = { B00100, B10101, B01110, B11111, B01110, B10101, B00100, B00000 }; // Fan simgesi
byte turnerSymbol[8] = { B00100, B01110, B11111, B00100, B11111, B01110, B00100, B00000 }; // Viyol döndürme simgesi
// --- Setup ---
void setup() {
Serial.begin(9600);
dht.begin();
lcd.init();
lcd.backlight();
if (!rtc.begin()) { // RTC başlatma kontrolü
lcd.clear();
lcd.print("RTC bulunamadi");
while (1);
}
pinMode(RELAY_HEAT, OUTPUT);
pinMode(RELAY_HUMIDITY, OUTPUT);
pinMode(RELAY_FAN, OUTPUT);
pinMode(RELAY_TURNER, OUTPUT);
pinMode(BUZZER_PIN, OUTPUT);
pinMode(JOY_BTN, INPUT_PULLUP);
lcd.createChar(0, heatSymbol);
lcd.createChar(1, humiditySymbol);
lcd.createChar(2, fanSymbol);
lcd.createChar(3, turnerSymbol);
lcd.createChar(4, eggIcon);
lcd.createChar(5, checkIcon);
lcd.createChar(6, hatchIcon);
lcd.setCursor(0, 0);
lcd.print("Kulucka Makinesi");
delay(2000);
selectEggType();
startTime = rtc.now();
incubating = true;
}
// --- Ana Döngü ---
void loop() {
unsigned long currentMillis = millis(); // Şu anki zamanı alıyoruz
// Viyol döndürme işlemi: her 1 dakikada bir 10 saniye boyunca döndürme yapılacak
if (currentMillis - lastTurnTime >= turnInterval) {
digitalWrite(RELAY_TURNER, HIGH); // Viyol döndürme aktif
delay(turnDuration); // 10 saniye bekleyin
digitalWrite(RELAY_TURNER, LOW); // Viyol döndürme durduruldu
lastTurnTime = currentMillis; // Son döndürme zamanını güncelle
}
// Kalan süreyi her döngüde güncelleyin
remainingTime = turnInterval - (currentMillis - lastTurnTime); // Kalan süreyi hesapla
unsigned long remainingMinutes = remainingTime / 60000; // Milisaniyeyi dakikaya çevir
readSensors();
controlRelays();
displayStatus(0, remainingMinutes); // Test amacıyla geçen gün sayısı sıfır
delay(2000); // 2 saniyelik gecikme
}
// --- Menü Fonksiyonu ---
void showMainMenu() {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Ana Menu");
lcd.setCursor(0, 1);
lcd.print("> Secim Yap");
delay(1000);
selectEggType(); // Menüde yumurta türü seçimi
}
// --- Fonksiyonlar ---
void selectEggType() {
static bool selecting = true; // Bu değişken menünün bir kez gösterilip gösterilmeyeceğini kontrol eder
if (selecting) {
lcd.clear(); // Menü seçimi başında ekranı temizle
int menuPos = 0;
while (selecting) {
lcd.setCursor(0, 0);
lcd.print("Secim Yapiniz: ");
lcd.setCursor(0, 1);
lcd.print("> ");
lcd.print(profiles[menuPos].name);
lcd.print(" ");
lcd.write(4); // Yumurta simgesi
int joyY = analogRead(JOY_Y);
if (joyY < 400) {
menuPos--;
if (menuPos < 0) menuPos = 3;
delay(300);
} else if (joyY > 600) {
menuPos++;
if (menuPos > 3) menuPos = 0;
delay(300);
}
if (digitalRead(JOY_BTN) == LOW) {
selectedProfile = menuPos;
selecting = false; // Menü bir kez gösterildikten sonra seçim yapıldığında çıkıyoruz
delay(500);
}
}
lcd.clear(); // Ekranı temizle
lcd.setCursor(0, 0);
lcd.print("Seciminiz tamam!");
lcd.setCursor(0, 1);
lcd.print("Cikim: " + String(hatchDaysBefore) + " gun");
delay(1000);
lcd.clear(); // Son olarak ekranı temizle
}
}
void readSensors() {
temperature = dht.readTemperature();
humidity = dht.readHumidity();
}
void controlRelays() {
EggProfile profile = profiles[selectedProfile];
float tMin, tMax;
int hMin, hMax;
if (currentMode == NORMAL) {
tMin = profile.tempMinNormal;
tMax = profile.tempMaxNormal;
hMin = profile.humMinNormal;
hMax = profile.humMaxNormal;
} else {
tMin = profile.tempMinHatch;
tMax = profile.tempMaxHatch;
hMin = profile.humMinHatch;
hMax = profile.humMaxHatch;
}
// Isıtıcı kontrolü
if (temperature < tMin) {
digitalWrite(RELAY_HEAT, HIGH);
} else if (temperature > tMax) {
digitalWrite(RELAY_HEAT, LOW);
}
// Nemlendirici kontrolü
if (humidity < hMin) {
digitalWrite(RELAY_HUMIDITY, HIGH);
} else if (humidity > hMax) {
digitalWrite(RELAY_HUMIDITY, LOW);
}
// Fan kontrolü
if (temperature > tMax + 1.5 || humidity > hMax + 10) {
digitalWrite(RELAY_FAN, HIGH);
} else {
digitalWrite(RELAY_FAN, LOW);
}
// Alarm kontrolü
if (temperature < tMin - 1 || temperature > tMax + 1 || humidity < hMin - 10 || humidity > hMax + 10) {
digitalWrite(BUZZER_PIN, HIGH);
} else {
digitalWrite(BUZZER_PIN, LOW);
}
}
void displayStatus(int passedDays, unsigned long remainingMinutes) {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(profiles[selectedProfile].name);
// Normal veya Cikim modunu LCD'ye yazıyoruz
if (currentMode == NORMAL) {
lcd.print(" N");
} else {
lcd.print(" C");
}
lcd.setCursor(0, 1);
lcd.print((int)temperature); // Sıcaklık
lcd.write(0); // Isıtıcı simgesi
lcd.print(" ");
lcd.print((int)humidity); // Nem oranı
lcd.write(1); // Nemlendirici simgesi
lcd.print(" G:");
lcd.print(passedDays); // Geçen gün sayısı
lcd.setCursor(10, 0);
lcd.print(remainingMinutes); // Kalan dakikayı yazdır
lcd.print(" dk");
}