// Reflow BGA Rework Kontrolcüsü
// Sürüm: 2.5 (Geliştirilmiş)
// Tarih: 22-05-2025
// Şirket: ÖZTÜRK BİLİŞİM
// Yazar: Gökhan Öztürk
// Açıklama:
// Bu, Arduino uyumlu reflow BGA Rework kontrolcüsü için geliştirilmiş bir yazılımdır.
// Kurşunsuz lehimleme (BGA için optimize) profili için tasarlanmıştır. I2C 4x20 LCD,
// MAX6675 termokupl sensörü ve 4 buton (Ayar, Arttırma, Azaltma, Başlat) kullanılır.
// PID kontrolü 10 adımlıdır. Her adımda sıcaklık, Kp, Ki, Kd ve süre ayarlanabilir.
// Değerler EEPROM’a kaydedilir. Ekran yenileme optimize edilmiştir; sadece değişen
// değerler güncellenir. Ana ekranda 0,2’de hedef sıcaklık, 0,3’te adım ve süre gösterilir.
//
// Uyarı:
// Yüksek voltajla çalışmak tehlikelidir! Lütfen dikkatli olun ve uygun bilgiye sahip
// olmadan işlem yapmayın. Bu yazılım ve donanımın kullanımı tamamen kendi
// sorumluluğunuzdadır.
//
// Gerekli Kütüphaneler:
// - Arduino PID Library: https://github.com/br3ttb/Arduino-PID-Library
// - MAX6675 Library: https://github.com/adafruit/MAX6675-library
// - LiquidCrystal_I2C Library: https://github.com/johnrickman/LiquidCrystal_I2C
// - EEPROM Library: Arduino dahili EEPROM kütüphanesi
#include <Wire.h> // I2C haberleşmesi için
#include <LiquidCrystal_I2C.h> // 4x20 LCD için
#include <max6675.h> // MAX6675 termokupl sensörü için
#include <PID_v1.h> // PID kontrolü için
#include <EEPROM.h> // EEPROM işlemleri için
// **** TÜR TANIMLAMALARI ****
typedef enum REFLOW_STATE {
REFLOW_STATE_IDLE, // Boşta
REFLOW_STATE_STEP1, // Adım 1: İlk ısıtma
REFLOW_STATE_STEP2, // Adım 2
REFLOW_STATE_STEP3, // Adım 3
REFLOW_STATE_STEP4, // Adım 4
REFLOW_STATE_STEP5, // Adım 5: Isınma
REFLOW_STATE_STEP6, // Adım 6
REFLOW_STATE_STEP7, // Adım 7
REFLOW_STATE_STEP8, // Adım 8: Reflow
REFLOW_STATE_STEP9, // Adım 9: Soğuma başlangıcı
REFLOW_STATE_STEP10, // Adım 10: Soğuma
REFLOW_STATE_COMPLETE, // Tamamlandı
REFLOW_STATE_TOO_HOT, // Çok sıcak
REFLOW_STATE_ERROR, // Hata
REFLOW_STATE_SETTINGS // Ayar modu
} reflowState_t;
typedef enum REFLOW_STATUS {
REFLOW_STATUS_OFF, // Kapalı
REFLOW_STATUS_ON // Açık
} reflowStatus_t;
typedef enum SWITCH {
SWITCH_NONE, // Hiçbiri
SWITCH_SET, // Ayar butonu
SWITCH_UP, // Arttırma butonu
SWITCH_DOWN, // Azaltma butonu
SWITCH_START // Başlat butonu
} switch_t;
typedef enum DEBOUNCE_STATE {
DEBOUNCE_STATE_IDLE, // Boşta
DEBOUNCE_STATE_CHECK, // Kontrol
DEBOUNCE_STATE_RELEASE // Serbest bırakma
} debounceState_t;
typedef enum SETTING_PARAM {
SETTING_TEMP, // Sıcaklık ayarı
SETTING_KP, // Kp katsayısı ayarı
SETTING_KI, // Ki katsayısı ayarı
SETTING_KD, // Kd katsayısı ayarı
SETTING_DURATION // Süre ayarı
} settingParam_t;
// **** SABİTLER ****
#define TEMPERATURE_ROOM 50 // Oda sıcaklığı (°C)
#define SENSOR_SAMPLING_TIME 1000 // Sensör okuma periyodu (ms)
#define DEBOUNCE_PERIOD_MIN 100 // Debounce süresi (ms)
#define SETTINGS_TRANSITION_DELAY 100 // Ayar modunda geçiş gecikmesi (ms)
#define LCD_UPDATE_INTERVAL 500 // Ekran yenileme aralığı (ms)
#define EEPROM_BASE_ADDR 0 // EEPROM başlangıç adresi
// **** PID ve Sıcaklık Parametreleri (EEPROM'dan çekilecek) ****
float temperatureSteps[10] = {150, 175, 200, 210, 220, 230, 235, 245, 200, 100}; // BGA için optimize
float pidKpSteps[10] = {100, 120, 150, 180, 200, 250, 280, 300, 250, 200};
float pidKiSteps[10] = {0.025, 0.030, 0.035, 0.040, 0.045, 0.050, 0.050, 0.050, 0.040, 0.030};
float pidKdSteps[10] = {20, 25, 30, 40, 50, 100, 150, 200, 150, 100};
float stepDurations[10] = {60, 30, 30, 30, 20, 20, 20, 30, 30, 30}; // Saniye cinsinden
// LCD için durum mesajları (Türkçe)
const char* lcdMessagesReflowStatus[] = {
"Hazir", // Boşta
"Adim 1", // İlk ısıtma
"Adim 2", // Adım 2
"Adim 3", // Adım 3
"Adim 4", // Adım 4
"Adim 5", // Isınma
"Adim 6", // Adım 6
"Adim 7", // Adım 7
"Reflow", // Reflow
"Soguma", // Soğuma başlangıcı
"Soguma Son", // Soğuma
"Tamamlandi", // Tamamlandı
"Cok Sicak", // Çok sıcak
"Hata", // Hata
"Ayar Modu" // Ayar modu
};
// LCD için özel derece sembolü
unsigned char degree[8] = {
0b01100,
0b10010,
0b10010,
0b01100,
0b00000,
0b00000,
0b00000,
0b00000
};
// Pin tanımları
int ledRedPin = A1; // Kırmızı LED pini
int ledGreenPin = A0; // Yeşil LED pini
int buzzerPin = 6; // Buzzer pini
int switchSetPin = 2; // Ayar butonu pini
int switchUpPin = 3; // Arttırma butonu pini
int switchDownPin = 4; // Azaltma butonu pini
int switchStartPin = 7; // Başlat butonu pini
int ssrPin = 5; // SSR pini
int thermocoupleSOPin = 11; // Termokupl SO pini
int thermocoupleCSPin = 12; // Termokupl CS pini
int thermocoupleCLKPin = 13; // Termokupl CLK pini
// **** PID KONTROL DEĞİŞKENLERİ ****
double setpoint;
double input;
double output;
double kp;
double ki;
double kd;
int windowSize;
unsigned long windowStartTime;
unsigned long nextCheck;
unsigned long nextRead;
unsigned long timerStep;
unsigned long buzzerPeriod;
unsigned long lastSettingTransition; // Ayar modunda son geçiş zamanı
unsigned long lastLcdUpdate; // Son ekran yenileme zamanı
reflowState_t reflowState = REFLOW_STATE_IDLE;
reflowStatus_t reflowStatus = REFLOW_STATUS_OFF;
debounceState_t debounceStateSet = DEBOUNCE_STATE_IDLE;
debounceState_t debounceStateUp = DEBOUNCE_STATE_IDLE;
debounceState_t debounceStateDown = DEBOUNCE_STATE_IDLE;
debounceState_t debounceStateStart = DEBOUNCE_STATE_IDLE;
long lastDebounceTimeSet;
long lastDebounceTimeUp;
long lastDebounceTimeDown;
long lastDebounceTimeStart;
switch_t switchStatus = SWITCH_NONE;
int timerSeconds;
int currentStep = 0; // Geçerli PID adımı (ayar modu için)
settingParam_t currentParam = SETTING_TEMP; // Ayar yapılan parametre
reflowState_t lastReflowState = REFLOW_STATE_IDLE; // Son durum (ekran için)
float lastInput = -1; // Son sıcaklık değeri (ekran için)
float lastSettingValue = -1; // Son ayar değeri (ekran için)
float lastSetpoint = -1; // Son hedef sıcaklık (ekran için)
float lastDuration = -1; // Son süre değeri (ekran için)
// PID kontrol arayüzü
PID reflowOvenPID(&input, &output, &setpoint, kp, ki, kd, DIRECT);
// LCD arayüzü (I2C, 4x20)
LiquidCrystal_I2C lcd(0x27, 20, 4); // I2C adresi 0x27, donanıma göre ayarlayın
// MAX6675 termokupl arayüzü
MAX6675 thermocouple(thermocoupleCLKPin, thermocoupleCSPin, thermocoupleSOPin);
// EEPROM'dan parametreleri okuma
void readEEPROM() {
int addr = EEPROM_BASE_ADDR;
for (int i = 0; i < 10; i++) {
EEPROM.get(addr, temperatureSteps[i]);
addr += sizeof(float);
EEPROM.get(addr, pidKpSteps[i]);
addr += sizeof(float);
EEPROM.get(addr, pidKiSteps[i]);
addr += sizeof(float);
EEPROM.get(addr, pidKdSteps[i]);
addr += sizeof(float);
EEPROM.get(addr, stepDurations[i]);
addr += sizeof(float);
}
}
// EEPROM'a parametreleri kaydetme
void saveEEPROM() {
int addr = EEPROM_BASE_ADDR;
for (int i = 0; i < 10; i++) {
EEPROM.put(addr, temperatureSteps[i]);
addr += sizeof(float);
EEPROM.put(addr, pidKpSteps[i]);
addr += sizeof(float);
EEPROM.put(addr, pidKiSteps[i]);
addr += sizeof(float);
EEPROM.put(addr, pidKdSteps[i]);
addr += sizeof(float);
EEPROM.put(addr, stepDurations[i]);
addr += sizeof(float);
}
}
// LCD ekranı güncelleme (sadece değişen alanlar)
void updateLCD() {
if (millis() - lastLcdUpdate < LCD_UPDATE_INTERVAL) return; // Yenileme aralığını bekle
lastLcdUpdate = millis();
// Durum değiştiyse veya ilk yenilemeyse tam ekran güncelle
if (reflowState != lastReflowState) {
lcd.clear();
lastReflowState = reflowState;
lastInput = -1; // Sıcaklık yeniden yazılsın
lastSettingValue = -1; // Ayar değeri yeniden yazılsın
lastSetpoint = -1; // Hedef sıcaklık yeniden yazılsın
lastDuration = -1; // Süre yeniden yazılsın
}
if (reflowState == REFLOW_STATE_SETTINGS) {
// Ayar modu ekranı
lcd.setCursor(0, 0);
lcd.print("Adim ");
lcd.print(currentStep + 1);
lcd.print(": ");
switch (currentParam) {
case SETTING_TEMP:
lcd.print("Sicaklik "); // Boşluklarla eski veriyi sil
break;
case SETTING_KP:
lcd.print("Kp ");
break;
case SETTING_KI:
lcd.print("Ki ");
break;
case SETTING_KD:
lcd.print("Kd ");
break;
case SETTING_DURATION:
lcd.print("Sure ");
break;
}
// Değer değiştiyse sadece değeri güncelle
float currentValue;
switch (currentParam) {
case SETTING_TEMP:
currentValue = temperatureSteps[currentStep];
break;
case SETTING_KP:
currentValue = pidKpSteps[currentStep];
break;
case SETTING_KI:
currentValue = pidKiSteps[currentStep];
break;
case SETTING_KD:
currentValue = pidKdSteps[currentStep];
break;
case SETTING_DURATION:
currentValue = stepDurations[currentStep];
break;
}
if (currentValue != lastSettingValue) {
lcd.setCursor(0, 1);
lcd.print(" "); // Eski değeri sil
lcd.setCursor(0, 1);
lcd.print(currentValue);
if (currentParam == SETTING_TEMP) {
lcd.write((uint8_t)0);
lcd.print("C");
} else if (currentParam == SETTING_DURATION) {
lcd.print("s");
}
lastSettingValue = currentValue;
}
} else {
// Normal çalışma ekranı
// Mevcut sıcaklık (2. satır)
lcd.setCursor(0, 0);
lcd.print(lcdMessagesReflowStatus[reflowState]);
lcd.setCursor(0, 1);
if (reflowState == REFLOW_STATE_ERROR) {
lcd.print("Termokupl Hatasi! ");
lastInput = -1; // Sonraki yenilemede sıcaklık yazılsın
lastSetpoint = -1; // Hedef sıcaklık da yenilensin
} else if (input != lastInput) {
lcd.print("Sicaklik: "); // Eski veriyi sil
lcd.setCursor(10, 1);
lcd.print(input);
lcd.write((uint8_t)0);
lcd.print("C");
lastInput = input;
}
// Hedef sıcaklık (3. satır, 0,2)
if (reflowState != REFLOW_STATE_ERROR && setpoint != lastSetpoint) {
lcd.setCursor(0, 2);
lcd.print("Hedef: "); // Eski veriyi sil
lcd.setCursor(10, 2);
lcd.print(setpoint);
lcd.write((uint8_t)0);
lcd.print("C");
lastSetpoint = setpoint;
}
// Adım ve süre (4. satır, 0,3)
if (reflowState != REFLOW_STATE_ERROR && reflowState != REFLOW_STATE_SETTINGS) {
lcd.setCursor(0, 3);
lcd.print("Adim: ");
lcd.print(currentStep + 1);
lcd.print(" Sure: ");
lcd.print(timerSeconds);
lcd.print("s");
}
}
}
void setup() {
// SSR pini başlatma, fırının kapalı olduğundan emin olun
digitalWrite(ssrPin, LOW);
pinMode(ssrPin, OUTPUT);
// Buzzer pini başlatma, buzzer kapalı
digitalWrite(buzzerPin, LOW);
pinMode(buzzerPin, OUTPUT);
// LED pinleri başlatma ve başlangıçta yakma (aktif düşük)
digitalWrite(ledRedPin, LOW);
pinMode(ledRedPin, OUTPUT);
digitalWrite(ledGreenPin, LOW);
pinMode(ledGreenPin, OUTPUT);
// Anahtar pinleri başlatma
pinMode(switchSetPin, INPUT_PULLUP);
pinMode(switchUpPin, INPUT_PULLUP);
pinMode(switchDownPin, INPUT_PULLUP);
pinMode(switchStartPin, INPUT_PULLUP);
// EEPROM'dan parametreleri oku
readEEPROM();
// Başlangıç ekranı
lcd.init();
lcd.backlight();
lcd.createChar(0, degree);
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("BGA Rework Station");
lcd.setCursor(0, 1);
lcd.print("Surum 2.5");
digitalWrite(buzzerPin, HIGH);
delay(2500);
digitalWrite(buzzerPin, LOW);
lcd.clear();
// Seri haberleşme başlatma (57600 bps)
Serial.begin(57600);
// LED'leri kapatma (aktif düşük)
digitalWrite(ledRedPin, HIGH);
digitalWrite(ledGreenPin, HIGH);
// PID kontrol penceresi boyutunu ayarlama
windowSize = 2000;
// Zaman takip değişkenlerini başlatma
nextCheck = millis();
nextRead = millis();
lastSettingTransition = millis();
lastLcdUpdate = millis();
}
void loop() {
unsigned long now;
// Termokupl okuma zamanı mı?
if (millis() > nextRead) {
nextRead += SENSOR_SAMPLING_TIME;
input = thermocouple.readCelsius();
// Termokupl hatası kontrolü
if (isnan(input)) {
reflowState = REFLOW_STATE_ERROR;
reflowStatus = REFLOW_STATUS_OFF;
}
}
// Her saniye durum kontrolü
if (millis() > nextCheck) {
nextCheck += 1000;
if (reflowStatus == REFLOW_STATUS_ON) {
// Kırmızı LED'i kalp atışı olarak yanıp söndür
digitalWrite(ledRedPin, !digitalRead(ledRedPin));
timerSeconds++;
// Seri porta sıcaklık ve zaman bilgisi gönder
Serial.print(timerSeconds);
Serial.print(" ");
Serial.print(setpoint);
Serial.print(" ");
Serial.print(input);
Serial.print(" ");
Serial.println(output);
} else {
digitalWrite(ledRedPin, HIGH);
}
}
// LCD ekranı güncelle
updateLCD();
// Reflow fırın kontrol durum makinesi
switch (reflowState) {
case REFLOW_STATE_IDLE:
if (input >= TEMPERATURE_ROOM) {
reflowState = REFLOW_STATE_TOO_HOT;
} else if (switchStatus == SWITCH_SET && (millis() - lastSettingTransition) > SETTINGS_TRANSITION_DELAY) {
lastSettingTransition = millis();
reflowState = REFLOW_STATE_SETTINGS;
currentStep = 0;
currentParam = SETTING_TEMP;
} else if (switchStatus == SWITCH_START) {
Serial.println("Zaman Hedef Giris Cikis");
timerSeconds = 0;
windowStartTime = millis();
setpoint = temperatureSteps[0];
kp = pidKpSteps[0];
ki = pidKiSteps[0];
kd = pidKdSteps[0];
reflowOvenPID.SetTunings(kp, ki, kd);
reflowOvenPID.SetOutputLimits(0, windowSize);
reflowOvenPID.SetSampleTime(SENSOR_SAMPLING_TIME);
reflowOvenPID.SetMode(AUTOMATIC);
reflowState = REFLOW_STATE_STEP1;
currentStep = 0;
}
break;
case REFLOW_STATE_STEP1:
reflowStatus = REFLOW_STATUS_ON;
if (input >= temperatureSteps[0]) {
timerStep = millis() + (stepDurations[1] * 1000); // Saniyeyi ms’ye çevir
kp = pidKpSteps[1];
ki = pidKiSteps[1];
kd = pidKdSteps[1];
reflowOvenPID.SetTunings(kp, ki, kd);
setpoint = temperatureSteps[1];
reflowState = REFLOW_STATE_STEP2;
currentStep = 1;
}
break;
case REFLOW_STATE_STEP2:
if (millis() > timerStep) {
timerStep = millis() + (stepDurations[2] * 1000);
setpoint = temperatureSteps[1];
if (input >= temperatureSteps[1]) {
kp = pidKpSteps[2];
ki = pidKiSteps[2];
kd = pidKdSteps[2];
reflowOvenPID.SetTunings(kp, ki, kd);
setpoint = temperatureSteps[2];
reflowState = REFLOW_STATE_STEP3;
currentStep = 2;
}
}
break;
case REFLOW_STATE_STEP3:
if (millis() > timerStep) {
timerStep = millis() + (stepDurations[3] * 1000);
setpoint = temperatureSteps[2];
if (input >= temperatureSteps[2]) {
kp = pidKpSteps[3];
ki = pidKiSteps[3];
kd = pidKdSteps[3];
reflowOvenPID.SetTunings(kp, ki, kd);
setpoint = temperatureSteps[3];
reflowState = REFLOW_STATE_STEP4;
currentStep = 3;
}
}
break;
case REFLOW_STATE_STEP4:
if (millis() > timerStep) {
timerStep = millis() + (stepDurations[4] * 1000);
setpoint = temperatureSteps[3];
if (input >= temperatureSteps[3]) {
kp = pidKpSteps[4];
ki = pidKiSteps[4];
kd = pidKdSteps[4];
reflowOvenPID.SetTunings(kp, ki, kd);
setpoint = temperatureSteps[4];
reflowState = REFLOW_STATE_STEP5;
currentStep = 4;
}
}
break;
case REFLOW_STATE_STEP5:
if (millis() > timerStep) {
timerStep = millis() + (stepDurations[5] * 1000);
setpoint = temperatureSteps[4];
if (input >= temperatureSteps[4]) {
kp = pidKpSteps[5];
ki = pidKiSteps[5];
kd = pidKdSteps[5];
reflowOvenPID.SetTunings(kp, ki, kd);
setpoint = temperatureSteps[5];
reflowState = REFLOW_STATE_STEP6;
currentStep = 5;
}
}
break;
case REFLOW_STATE_STEP6:
if (millis() > timerStep) {
timerStep = millis() + (stepDurations[6] * 1000);
setpoint = temperatureSteps[5];
if (input >= temperatureSteps[5]) {
kp = pidKpSteps[6];
ki = pidKiSteps[6];
kd = pidKdSteps[6];
reflowOvenPID.SetTunings(kp, ki, kd);
setpoint = temperatureSteps[6];
reflowState = REFLOW_STATE_STEP7;
currentStep = 6;
}
}
break;
case REFLOW_STATE_STEP7:
if (millis() > timerStep) {
timerStep = millis() + (stepDurations[7] * 1000);
setpoint = temperatureSteps[6];
if (input >= temperatureSteps[6]) {
kp = pidKpSteps[7];
ki = pidKiSteps[7];
kd = pidKdSteps[7];
reflowOvenPID.SetTunings(kp, ki, kd);
setpoint = temperatureSteps[7];
reflowState = REFLOW_STATE_STEP8;
currentStep = 7;
}
}
break;
case REFLOW_STATE_STEP8:
if (input >= (temperatureSteps[7] - 5)) {
timerStep = millis() + (stepDurations[8] * 1000);
kp = pidKpSteps[8];
ki = pidKiSteps[8];
kd = pidKdSteps[8];
reflowOvenPID.SetTunings(kp, ki, kd);
setpoint = temperatureSteps[8];
reflowState = REFLOW_STATE_STEP9;
currentStep = 8;
}
break;
case REFLOW_STATE_STEP9:
if (input <= temperatureSteps[8]) {
timerStep = millis() + (stepDurations[9] * 1000);
kp = pidKpSteps[9];
ki = pidKiSteps[9];
kd = pidKdSteps[9];
reflowOvenPID.SetTunings(kp, ki, kd);
setpoint = temperatureSteps[9];
reflowState = REFLOW_STATE_STEP10;
currentStep = 9;
}
break;
case REFLOW_STATE_STEP10:
if (input <= temperatureSteps[9]) {
buzzerPeriod = millis() + 1000;
digitalWrite(ledGreenPin, LOW);
digitalWrite(buzzerPin, HIGH);
reflowStatus = REFLOW_STATUS_OFF;
reflowState = REFLOW_STATE_COMPLETE;
saveEEPROM(); // Parametreleri EEPROM'a kaydet
currentStep = 0;
}
break;
case REFLOW_STATE_COMPLETE:
if (millis() > buzzerPeriod) {
digitalWrite(buzzerPin, LOW);
digitalWrite(ledGreenPin, HIGH);
reflowState = REFLOW_STATE_IDLE;
}
break;
case REFLOW_STATE_TOO_HOT:
if (input < TEMPERATURE_ROOM) {
reflowState = REFLOW_STATE_IDLE;
}
break;
case REFLOW_STATE_ERROR:
if (isnan(input)) {
reflowState = REFLOW_STATE_ERROR;
} else {
reflowState = REFLOW_STATE_IDLE;
}
break;
case REFLOW_STATE_SETTINGS:
// Ayar butonu ile parametreler arasında geçiş
if (switchStatus == SWITCH_SET && (millis() - lastSettingTransition) > SETTINGS_TRANSITION_DELAY) {
lastSettingTransition = millis();
currentParam = (settingParam_t)((currentParam + 1) % 5); // TEMP, KP, KI, KD, DURATION
}
// Uzun basış veya son parametre sonrası bir sonraki adıma geç
if (switchStatus == SWITCH_SET && digitalRead(switchSetPin) == LOW && (millis() - lastDebounceTimeSet) > 1000) { // 1 saniye uzun basış
lastSettingTransition = millis();
currentStep = (currentStep + 1) % 10; // Bir sonraki adıma geç
currentParam = SETTING_TEMP; // Yeni adımda sıcaklıktan başla
if (currentStep == 0) {
reflowState = REFLOW_STATE_IDLE; // Tüm adımlar tamamlandı, çık
saveEEPROM(); // Parametreleri kaydet
}
}
// Arttırma butonu
if (switchStatus == SWITCH_UP && (millis() - lastSettingTransition) > SETTINGS_TRANSITION_DELAY) {
lastSettingTransition = millis();
switch (currentParam) {
case SETTING_TEMP:
temperatureSteps[currentStep] += 5.0; // 5°C artır
if (temperatureSteps[currentStep] > 300) temperatureSteps[currentStep] = 300;
break;
case SETTING_KP:
pidKpSteps[currentStep] += 10.0; // 10 birim artır
if (pidKpSteps[currentStep] > 500) pidKpSteps[currentStep] = 500;
break;
case SETTING_KI:
pidKiSteps[currentStep] += 0.01; // 0.01 artır
if (pidKiSteps[currentStep] > 0.1) pidKiSteps[currentStep] = 0.1;
break;
case SETTING_KD:
pidKdSteps[currentStep] += 10.0; // 10 birim artır
if (pidKdSteps[currentStep] > 500) pidKdSteps[currentStep] = 500;
break;
case SETTING_DURATION:
stepDurations[currentStep] += 5.0; // 5 saniye artır
if (stepDurations[currentStep] > 120) stepDurations[currentStep] = 120;
break;
}
saveEEPROM(); // Her değişiklikte EEPROM’a kaydet
}
// Azaltma butonu
if (switchStatus == SWITCH_DOWN && (millis() - lastSettingTransition) > SETTINGS_TRANSITION_DELAY) {
lastSettingTransition = millis();
switch (currentParam) {
case SETTING_TEMP:
temperatureSteps[currentStep] -= 5.0; // 5°C azalt
if (temperatureSteps[currentStep] < 50) temperatureSteps[currentStep] = 50;
break;
case SETTING_KP:
pidKpSteps[currentStep] -= 10.0; // 10 birim azalt
if (pidKpSteps[currentStep] < 0) pidKpSteps[currentStep] = 0;
break;
case SETTING_KI:
pidKiSteps[currentStep] -= 0.01; // 0.01 azalt
if (pidKiSteps[currentStep] < 0) pidKiSteps[currentStep] = 0;
break;
case SETTING_KD:
pidKdSteps[currentStep] -= 10.0; // 10 birim azalt
if (pidKdSteps[currentStep] < 0) pidKdSteps[currentStep] = 0;
break;
case SETTING_DURATION:
stepDurations[currentStep] -= 5.0; // 5 saniye azalt
if (stepDurations[currentStep] < 10) stepDurations[currentStep] = 10;
break;
}
saveEEPROM(); // Her değişiklikte EEPROM’a kaydet
}
break;
}
// Ayar butonu için debounce
if (digitalRead(switchSetPin) == LOW) {
if (debounceStateSet == DEBOUNCE_STATE_IDLE) {
lastDebounceTimeSet = millis();
debounceStateSet = DEBOUNCE_STATE_CHECK;
} else if (debounceStateSet == DEBOUNCE_STATE_CHECK && (millis() - lastDebounceTimeSet) > DEBOUNCE_PERIOD_MIN) {
debounceStateSet = DEBOUNCE_STATE_RELEASE;
}
} else if (debounceStateSet == DEBOUNCE_STATE_RELEASE) {
switchStatus = SWITCH_SET;
debounceStateSet = DEBOUNCE_STATE_IDLE;
} else {
debounceStateSet = DEBOUNCE_STATE_IDLE;
switchStatus = SWITCH_NONE;
}
// Arttırma butonu için debounce
if (digitalRead(switchUpPin) == LOW) {
if (debounceStateUp == DEBOUNCE_STATE_IDLE) {
lastDebounceTimeUp = millis();
debounceStateUp = DEBOUNCE_STATE_CHECK;
} else if (debounceStateUp == DEBOUNCE_STATE_CHECK && (millis() - lastDebounceTimeUp) > DEBOUNCE_PERIOD_MIN) {
debounceStateUp = DEBOUNCE_STATE_RELEASE;
}
} else if (debounceStateUp == DEBOUNCE_STATE_RELEASE) {
switchStatus = SWITCH_UP;
debounceStateUp = DEBOUNCE_STATE_IDLE;
} else {
debounceStateUp = DEBOUNCE_STATE_IDLE;
if (switchStatus == SWITCH_UP) switchStatus = SWITCH_NONE;
}
// Azaltma butonu için debounce
if (digitalRead(switchDownPin) == LOW) {
if (debounceStateDown == DEBOUNCE_STATE_IDLE) {
lastDebounceTimeDown = millis();
debounceStateDown = DEBOUNCE_STATE_CHECK;
} else if (debounceStateDown == DEBOUNCE_STATE_CHECK && (millis() - lastDebounceTimeDown) > DEBOUNCE_PERIOD_MIN) {
debounceStateDown = DEBOUNCE_STATE_RELEASE;
}
} else if (debounceStateDown == DEBOUNCE_STATE_RELEASE) {
switchStatus = SWITCH_DOWN;
debounceStateDown = DEBOUNCE_STATE_IDLE;
} else {
debounceStateDown = DEBOUNCE_STATE_IDLE;
if (switchStatus == SWITCH_DOWN) switchStatus = SWITCH_NONE;
}
// Başlat butonu için debounce
if (digitalRead(switchStartPin) == LOW) {
if (debounceStateStart == DEBOUNCE_STATE_IDLE) {
lastDebounceTimeStart = millis();
debounceStateStart = DEBOUNCE_STATE_CHECK;
} else if (debounceStateStart == DEBOUNCE_STATE_CHECK && (millis() - lastDebounceTimeStart) > DEBOUNCE_PERIOD_MIN) {
debounceStateStart = DEBOUNCE_STATE_RELEASE;
}
} else if (debounceStateStart == DEBOUNCE_STATE_RELEASE) {
switchStatus = SWITCH_START;
debounceStateStart = DEBOUNCE_STATE_IDLE;
} else {
debounceStateStart == DEBOUNCE_STATE_IDLE;
if (switchStatus == SWITCH_START) switchStatus == SWITCH_NONE;
}
// PID hesaplama ve SSR kontrolü
if (reflowStatus == REFLOW_STATUS_ON) {
now = millis();
reflowOvenPID.Compute();
Serial.println("PID Output: ");
Serial.println(output);
if ((now - windowStartTime) > windowSize) {
windowStartTime += windowSize;
}
if (output > 0) {
digitalWrite(ssrPin, HIGH);
} else {
digitalWrite(ssrPin, LOW);
}
} else {
digitalWrite(ssrPin, LOW);
}
}