#include #include #include #include // Include the GyverOLED library // MAX6675 configuration int max_SO = 12; int max_CS = 10; int max_SCK = 13; MAX6675 thermocouple(max_SCK, max_CS, max_SO); // OLED configuration GyverOLED oled; // SSR pin configuration const int ssrPin = 7; // Process phases (temperatures in Celsius and duration in minutes) // const int temperatures[] = {49, 51, 55, 45}; // const int phaseDurations[] = {30, 30, 30, 30}; // Individual durations for each phase in minutes // const int numPhases = 3; // const int temperatures[] = {47, 55, 65, 72, 85, 0}; // const int phaseDurations[] = {20, 20, 20, 20, 20, 5}; // Individual durations for each phase in minutes // const int numPhases = 5; // const int temperatures[] = {85, 50}; // const int phaseDurations[] = {120, 120}; // Individual durations for each phase in minutes // const int numPhases = 1; const int temperatures[] = {47, 53, 65, 72, 90, 50}; const int phaseDurations[] = {120, 120, 150, 60, 105, 60}; // Individual durations for each phase in minutes const int numPhases = 5; // const int temperatures[] = {55, 65, 72, 80, 90, 10}; // const int phaseDurations[] = {60, 120, 120, 120, 30, 100}; // Individual durations for each phase in minutes // const int numPhases = 5; // PID Control variables double Setpoint, Input, Output; double Kp = 2, Ki = 0.5, Kd = 0.25; PID myPID(&Input, &Output, &Setpoint, Kp, Ki, Kd, DIRECT); // Timing variables unsigned long phaseStartTime; unsigned long totalStartTime; unsigned long ssrLastSwitchTime; const int ssrSwitchInterval = 1000; // SSR switching interval in milliseconds void setup() { pinMode(ssrPin, OUTPUT); Serial.begin(9600); oled.init(); // Initialize the OLED oled.clear(); // Clear the display oled.setScale(2); // Set text scale to 2 for better visibility oled.print("Starting..."); oled.update(); delay(2000); oled.setScale(0); // Set text scale to 2 for better visibility // Begin the first phase phaseStartTime = totalStartTime = millis(); Setpoint = temperatures[0]; myPID.SetMode(AUTOMATIC); myPID.SetOutputLimits(0, 1); // SSR is either ON or OFF digitalWrite(ssrPin, HIGH); // Start with heater on ssrLastSwitchTime = millis(); } void loop() { static int currentPhase = 0; Input = (int) thermocouple.readCelsius(); // Cast to integer for display and control unsigned long currentTime = millis(); myPID.Compute(); // Switch SSR based on PID output and interval control if (currentTime - ssrLastSwitchTime > ssrSwitchInterval) { digitalWrite(ssrPin, Output > 0.5 ? HIGH : LOW); ssrLastSwitchTime = currentTime; } // Display time calculations unsigned long totalElapsedTime = (currentTime - totalStartTime) / 1000; // Total elapsed time in seconds unsigned long totalProcessTime = 0; for (int i = 0; i < numPhases; i++) { totalProcessTime += phaseDurations[i] * 60; } // Check if the phase duration is complete if ((currentTime - phaseStartTime) / 1000 >= phaseDurations[currentPhase] * 60) { currentPhase++; if (currentPhase >= numPhases) { oled.clear(); oled.print("Complete"); digitalWrite(ssrPin, LOW); // Turn off the heater return; // Stop further execution } phaseStartTime = currentTime; // Reset the start time for the new phase Setpoint = temperatures[currentPhase]; } // Display data on the OLED oled.clear(); oled.setCursor(0, 0); oled.print(formatTime(totalElapsedTime)); oled.print(" ("); oled.print(formatTime(totalProcessTime)); oled.print(")"); oled.setCursor(0, 1); oled.print(currentPhase + 1); oled.print(". "); oled.print((int)Input); oled.print("C "); oled.print((int)Setpoint); oled.print("C "); oled.print(formatTime((phaseDurations[currentPhase] * 60) - ((currentTime - phaseStartTime) / 1000))); oled.update(); delay(1000); // Update every second } String formatTime(long seconds) { long mins = seconds / 60; int secs = seconds % 60; return (mins < 10 ? "0" : "") + String(mins) + ":" + (secs < 10 ? "0" : "") + String(secs); }