LP_TIMER(1000, HandleExecution); void HandleExecution() { currentTime = millis(); if (inSelectionMode) { return; } totalElapsedTime = (currentTime - totalStartTime) / 1000; // Total elapsed time in seconds getPhaseAndTemperature(); if (Input > 20 && Input < 95) { regulator.input = (float)Input; regulator.setpoint = Setpoint; regulator.getResultNow(); Output = regulator.output; } else { Setpoint = 0; } if (isComplete && currentPhase >= activeProfile.numPhases && !finishTime) { finishTime = currentTime; } // Display all phases and highlight the current one printPhases(); } void getPhaseAndTemperature() { long accumulatedTime = 0; for (int i = 0; i < activeProfile.numPhases; i++) { long phaseDuration = activeProfile.phases[i].duration * 60; // Check for transition if (i > 0) { int previousTemp = activeProfile.phases[i - 1].temperature; int targetTemp = activeProfile.phases[i].temperature; int tempDiff = abs(targetTemp - previousTemp); long transitionDuration = tempDiff * 60 * activeProfile.transitionMinutesPerDegree; if (totalElapsedTime < accumulatedTime + transitionDuration) { isInTransition = true; currentPhase = i - 1; // Keep currentPhase as the previous phase long timeInTransition = totalElapsedTime - accumulatedTime; Setpoint = previousTemp + (double)timeInTransition / (60 * activeProfile.transitionMinutesPerDegree) * (targetTemp > previousTemp ? 1 : -1); phaseStartTime = totalStartTime + accumulatedTime * 1000; // Set phase start time return; } accumulatedTime += transitionDuration; } // Check if we're within the current phase if (totalElapsedTime < (long) (accumulatedTime + phaseDuration)) { isInTransition = false; currentPhase = i; Setpoint = activeProfile.phases[i].temperature; phaseStartTime = totalStartTime + accumulatedTime * 1000; // Set phase start time return; } accumulatedTime += phaseDuration; } // If the elapsed time exceeds the total duration, indicate completion currentPhase = activeProfile.numPhases; // Indicate completion Setpoint = 45; // Default to 45°C after completion isInTransition = false; isComplete = true; // Mark the process as complete phaseStartTime = totalStartTime + accumulatedTime * 1000; // Set phase start time to the end } void calculateTotalTime() { // Calculate total process time, including transitions activeProfile = profiles[activeProfileIndex]; totalProcessTime = 0; for (int i = 0; i < activeProfile.numPhases; i++) { totalProcessTime += (long) activeProfile.phases[i].duration * 60; if (i < activeProfile.numPhases - 1) { long tempDiff = abs(activeProfile.phases[i + 1].temperature - activeProfile.phases[i].temperature); totalProcessTime += (long) tempDiff * 60 * activeProfile.transitionMinutesPerDegree; } } } void startExecution() { activeProfile = profiles[activeProfileIndex]; inSelectionMode = false; // Switch to execution mode phaseStartTime = totalStartTime = millis(); // Start the timer totalElapsedTime = 0; regulator.setpoint = 0; // digitalWrite(ssrPin, HIGH); // Start with heater on ssrLastSwitchTime = millis(); calculateTotalTime(); getPhaseAndTemperature(); writeEEPROM(); oled.clear(); boolLastCompletedState = isComplete = false; }