diff --git a/eeprom.ino b/eeprom.ino new file mode 100644 index 0000000..7dbe360 --- /dev/null +++ b/eeprom.ino @@ -0,0 +1,36 @@ +LP_TIMER((long)10*60*1000, writeEEPROM); + +void writeEEPROM() { + #if useEEPROM + lastEEPROMWriteTime = millis(); + EEPROM.put(0, activeProfileIndex); // Store the active profile index + EEPROM.put(4, totalElapsedTime); // Store the total elapsed time + + Serial.print("EEPROM written: "); + Serial.print(activeProfileIndex); + Serial.print(" "); + Serial.println(totalElapsedTime); + #endif +} + +void readEEPROM() { + #if useEEPROM + long time = 0; + EEPROM.get(0, activeProfileIndex); // Store the active profile index + EEPROM.get(4, time); // Store the total elapsed time + if (activeProfileIndex != 100) { + totalStartTime = millis() - time*1000; + calculateTotalTime(); + getPhaseAndTemperature(); + inSelectionMode = false; + } + else { + oled.clear(); + displaySelection(); + } + Serial.print("EEPROM read: "); + Serial.print(activeProfileIndex); + Serial.print(" "); + Serial.println(time); + #endif +} diff --git a/hot_fermentation.ino b/hot_fermentation.ino index 44dc9a2..235f675 100644 --- a/hot_fermentation.ino +++ b/hot_fermentation.ino @@ -1,9 +1,12 @@ +#include +#include + #define useEEPROM 1 // #define TempSensorMax #define TempSensorDallas // #define PlotValues -#include +// #include #include #include "GyverEncoder.h" @@ -64,12 +67,13 @@ Profile profiles[] = { {"Chickpeas", 1, {{46, 120}, {55, 60}, {65, 150}, {70, 60}, {90, 105}}, 5}, {"Chickpeas v2", 1, {{46, 120}, {55, 120}, {65, 120}, {72, 240}, {85, 300}}, 5}, {"Lentils", 3, {{46, 120}, {53, 120}, {65, 180}, {72, 90}, {90, 15}}, 5}, - {"Gradual", 10, {{46, 120}, {80, 60}}, 2}, - {"Long gradual", 10, {{46, 120}, {80, 60}, {90, 15}}, 3}, + {"Gradual", 10, {{46, 120}, {90, 30}}, 2}, + {"Long gradual", 15, {{46, 120}, {80, 60}, {90, 15}}, 3}, {"Wheat", 1, {{46, 120}, {53, 40}, {65, 40}, {72, 40}, {85, 40}}, 5}, {"SV1", 1, {{55, 30}, {85, 120}}, 2}, {"SV2", 0, {{46, 45}}, 1}, // {"Yoghurt maker", 0, {{40, 300}, {40, 300}, {30, 300}}, 3}, + // {"TEST", 0, {{46, 1}}, 1}, }; // Global variables for profile selection and execution @@ -110,15 +114,6 @@ const int ssrSwitchInterval = 1000; // SSR switching interval in milliseconds // Buffer for formatted time strings char timeBuffer[10]; -uint32_t timerExecution = 0; -#define T_PERIOD_EXEC 1000 // period of Execution processing -uint32_t timerSSR = 0; -#define T_PERIOD_SSR 500 // period of heater handling -uint32_t timerTemp = 0; -#define T_PERIOD_TEMP 1000 // period of dallas sensor requesting -uint32_t timerChecks= 0; -#define T_PERIOD_Checks 1000 // period of additional checks - bool boolLastCompletedState = false; float failedReadingLastValue = 0; @@ -148,469 +143,6 @@ void setup() { } void loop() { - enc1.tick(); - isLeft = enc1.isLeft(); - isRight = enc1.isRight(); - isClick = enc1.isClick(); - if (isLeft || isRight || isClick) { - handleEncoder(); - } - handleTemperatureSensor(); - handleExecution(); - handleHeaterAdv(); - handleAdditionalChecks(); + Looper.loop(); } -void handleAdditionalChecks() { - long time = millis(); - - if (time - timerChecks < T_PERIOD_Checks) { - return; - } - timerChecks = time; - - if (isComplete && !boolLastCompletedState) { - boolLastCompletedState = true; - for(int i=0; i<10; i++) { - digitalWrite(activeBuzzerPin, HIGH); - delay(100); - digitalWrite(activeBuzzerPin, LOW); - delay(100); - } - } -} - -void handleTemperatureSensor() { - long time = millis(); - static int currentPart = 0; - - if (time - timerTemp < T_PERIOD_TEMP) { - return; - } - timerTemp = time; - -#ifdef TempSensorDallas - Input = (double) sensors.getTempCByIndex(0); - - sensors.requestTemperatures(); // Send the command to get temperatures -#endif -#ifdef TempSensorMax // to go into the read temp function, rename from dallas temp - Input = thermocouple.readCelsius(); -#endif - - if (isnan(Input) || Input < 20 || Input > 95) { - failedReadingLastValue = (float) Input; - failedReadingCount++; - temperatureSensorError = true; - } - else { - temperatureSensorError = false; - } - -} - -void handleHeaterSimple() { - long time = millis(); - static int currentPart = 0; - - if (time - timerSSR < T_PERIOD_SSR) { - return; - } - if (inSelectionMode) { - digitalWrite(ssrPin, LOW); - return; - } - timerSSR = time; - - int current = Output * PARTS; - - oled.setCursor(104, 7); - char symbol; - for (int i = 0; i < PARTS; i++) { - symbol = current > i ? '=' : '-'; - if (currentPart == i) { - oled.invertText(true); - } - oled.print(symbol); - oled.invertText(false); - } - - digitalWrite(ssrPin, currentPart < current ? HIGH : LOW); - currentPart++; - if (currentPart >= PARTS) { - currentPart = 0; - } -} - -void handleHeaterAdv() { - long time = millis(); - static int currentPart = 0; - static bool states[PARTS]; - - if (time - timerSSR < T_PERIOD_SSR) { - return; - } - if (inSelectionMode) { - digitalWrite(ssrPin, LOW); - return; - } - timerSSR = time; - - int current = Output/100 * PARTS; - - int last = 0; - for (int i = 1; i < PARTS; i++) { - last += states[i] ? 1 : 0; - if (i) { - states[i-1] = states[i]; - } - } - bool next = current >= last ? true : false; - if (Output < 1) next = false; - states[PARTS-1] = next; - - oled.setCursor(128-6*PARTS, 7); - sprintf(timeBuffer, "%3d", (int)(Output)); - char symbol; - for (int i = 0; i < PARTS; i++) { - int index = i - (PARTS - 3); - symbol = index < 0 ? ' ' : timeBuffer[index]; - oled.invertText(states[i]); - oled.print(symbol); - oled.invertText(false); - } - - if (temperatureSensorError) { - next = 0; - } - - digitalWrite(ssrPin, next); - currentPart++; - if (currentPart >= PARTS) { - currentPart = 0; - } - -#ifdef PlotValues - Serial.print(Setpoint); - Serial.print(","); - Serial.print(Input); - Serial.print(","); - Serial.print(Output); - Serial.println(",0,100"); -#endif - -} - -void handleEncoder() { - if (inSelectionMode) { - handleProfileSelection(); - } - else { - handleExecutionSelection(); - } -} - -void handleExecutionSelection() { - if (isClick) { - activeProfileIndex = 100; - activeProfile = profiles[activeProfileIndex]; - inSelectionMode = true; - writeEEPROM(); - oled.clear(); - displaySelection(); - return; - } - -} - -void handleExecution() { - currentTime = millis(); - - if (inSelectionMode || (currentTime - timerExecution < T_PERIOD_EXEC)) { // таймер на millis() - return; - } - timerExecution = currentTime; - - totalElapsedTime = (currentTime - totalStartTime) / 1000; // Total elapsed time in seconds - - if ((currentTime - lastEEPROMWriteTime) >= (long)10*60*1000) { - writeEEPROM(); - } - - getPhaseAndTemperature(); - - regulator.input = (float)Input; - regulator.setpoint = Setpoint; - regulator.getResultNow(); - Output = regulator.output; - - if (isComplete && currentPhase >= activeProfile.numPhases && !finishTime) { - finishTime = currentTime; - } - - // Display all phases and highlight the current one - printPhases(); -} - -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; -} - -void handleProfileSelection() { - if (!isClick && !isLeft && !isRight) { - return; - } - - // Handle encoder input for selecting the profile - if (isRight) { - selectedProfileIndex = (selectedProfileIndex + 1) % (sizeof(profiles) / sizeof(profiles[0])); - } else if (isLeft) { - selectedProfileIndex = (selectedProfileIndex - 1 + (sizeof(profiles) / sizeof(profiles[0]))) % (sizeof(profiles) / sizeof(profiles[0])); - } - - displaySelection(); - - // Start the selected profile on button press - if (isClick) { - activeProfileIndex = selectedProfileIndex; - startExecution(); - } -} - -void displaySelection() { - // oled.clear(); - // Display all profiles with the selected one highlighted - for (int i = 0; i < (int) (sizeof(profiles) / sizeof(profiles[0])); i++) { - if (i == selectedProfileIndex) { - oled.invertText(true); // Highlight the selected profile - } - - oled.setCursor(0, i); // Set cursor to the correct row - oled.print(profiles[i].name); - - oled.invertText(false); // Reset text inversion for other profiles - } - oled.update(); -} - -void calculateTotalTime() { - // Calculate total process time, including transitions - activeProfile = profiles[activeProfileIndex]; - totalProcessTime = 0; - for (int i = 0; i < activeProfile.numPhases; i++) { - totalProcessTime += activeProfile.phases[i].duration * 60; - if (i < activeProfile.numPhases - 1) { - int tempDiff = abs(activeProfile.phases[i + 1].temperature - activeProfile.phases[i].temperature); - totalProcessTime += tempDiff * 60 * activeProfile.transitionMinutesPerDegree; - } - } -} - -void getPhaseAndTemperature() { - long accumulatedTime = 0; - - for (int i = 0; i < activeProfile.numPhases; i++) { - int 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); - int transitionDuration = tempDiff * 60 * activeProfile.transitionMinutesPerDegree; - - if (totalElapsedTime < accumulatedTime + transitionDuration) { - isInTransition = true; - currentPhase = i - 1; // Keep currentPhase as the previous phase - int 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 < 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 printPhases() { - // oled.clear(); - - if (isComplete) { - // Show completion time and current temperature instead of the title - oled.setCursor(0, 0); - oled.invertText(true); - oled.print("Done!"); - oled.invertText(false); - oled.print(" "); - formatTime((currentTime - finishTime) / 1000, timeBuffer); // Time since completion - oled.print(timeBuffer); - oled.print(" "); - oled.print(Input,0); - oled.print("c"); - oled.print("->"); - oled.print((int)Setpoint); - oled.print("c "); - } else { - oled.setCursor(0, 0); - oled.print(activeProfile.name); - oled.print(" "); - } - - // Display the totals and current state on the OLED - oled.setCursor(0, 1); - oled.print(" "); - oled.setCursor(18, 1); - formatTime(totalElapsedTime, timeBuffer); - oled.print(timeBuffer); - oled.print(" / "); - formatTime(totalProcessTime, timeBuffer); - oled.print(timeBuffer); - oled.print(" "); - - for (int i = 0; i < activeProfile.numPhases; i++) { - if (i == currentPhase) { - oled.invertText(true); // Invert text for the current phase - - oled.setCursor(0, i + 2); // Set cursor to the row corresponding to the phase - long timeRemaining = (activeProfile.phases[i].duration * 60) - ((currentTime - phaseStartTime) / 1000); - formatTime(timeRemaining, timeBuffer); - oled.print(i + 1); - oled.print(". "); - oled.print(Input, 1); - oled.print("c "); - if (fabs(Setpoint - round(Setpoint)) < 0.05) { - oled.print(Setpoint, 0); // Print without decimals - } else { - oled.print(Setpoint, 1); // Print with 1 decimal place - } - oled.print("c "); - if (!isInTransition) { - oled.print(timeBuffer); - } - oled.print(" "); - } else { - oled.invertText(false); // Normal text for other phases - - oled.setCursor(0, i + 2); // Set cursor to the row corresponding to the phase - formatTime(activeProfile.phases[i].duration * 60, timeBuffer); - oled.print(i + 1); - oled.print(". "); - oled.print(activeProfile.phases[i].temperature); - oled.print("c "); - oled.print(timeBuffer); - oled.print(" "); - } - } - - if (temperatureSensorError) { - oled.invertText(true); - oled.setCursor(0, 0); - oled.setScale(2); - oled.print("T = "); - oled.print(Input); - oled.print(" "); - oled.setScale(1); - digitalWrite(activeBuzzerPin, HIGH); - delay(5); - digitalWrite(activeBuzzerPin, LOW); - } - - if (failedReadingCount) { - oled.setCursor(0, 7); - oled.print(failedReadingCount); - oled.print(" ("); - oled.print(failedReadingLastValue); - oled.print(") "); - } - - oled.invertText(false); // Ensure text inversion is off after the loop - - // oled.setCursor(110,7); - // sprintf(timeBuffer, "%3d", (int)(Output*100)); - // oled.print(timeBuffer); - // oled.update(); -} - -void formatTime(long seconds, char* buffer) { - long hours = seconds / 3600; - long mins = (seconds % 3600) / 60; - int secs = seconds % 60; - - buffer[0] = '\0'; // Ensure the buffer is empty - - if (hours > 0) { - sprintf(buffer + strlen(buffer), "%ldh", hours); - } - if (mins > 0) { - sprintf(buffer + strlen(buffer), "%ldm", mins); - } - if (secs > 0) { - sprintf(buffer + strlen(buffer), "%ds", secs); - } -} - -void writeEEPROM() { - #if useEEPROM - lastEEPROMWriteTime = millis(); - EEPROM.put(0, activeProfileIndex); // Store the active profile index - EEPROM.put(4, totalElapsedTime); // Store the total elapsed time - - Serial.print("EEPROM written: "); - Serial.print(activeProfileIndex); - Serial.print(" "); - Serial.println(totalElapsedTime); - #endif -} - -void readEEPROM() { - #if useEEPROM - long time = 0; - EEPROM.get(0, activeProfileIndex); // Store the active profile index - EEPROM.get(4, time); // Store the total elapsed time - if (activeProfileIndex != 100) { - totalStartTime = millis() - time*1000; - calculateTotalTime(); - getPhaseAndTemperature(); - inSelectionMode = false; - } - else { - oled.clear(); - displaySelection(); - } - Serial.print("EEPROM read: "); - Serial.print(activeProfileIndex); - Serial.print(" "); - Serial.println(time); - #endif -} diff --git a/output.ino b/output.ino new file mode 100644 index 0000000..aaa48b1 --- /dev/null +++ b/output.ino @@ -0,0 +1,132 @@ +void printPhases() { + // oled.clear(); + + if (isComplete) { + // Show completion time and current temperature instead of the title + oled.setCursor(0, 0); + oled.invertText(true); + oled.print("Done!"); + oled.invertText(false); + oled.print(" "); + formatTime((currentTime - finishTime) / 1000, timeBuffer); // Time since completion + oled.print(timeBuffer); + oled.print(" "); + oled.print(Input,0); + oled.print("c"); + oled.print("->"); + oled.print((int)Setpoint); + oled.print("c "); + } else { + oled.setCursor(0, 0); + oled.print(activeProfile.name); + oled.print(" "); + } + + // Display the totals and current state on the OLED + oled.setCursor(0, 1); + oled.print(" "); + oled.setCursor(18, 1); + formatTime(totalElapsedTime, timeBuffer); + oled.print(timeBuffer); + oled.print(" / "); + formatTime(totalProcessTime, timeBuffer); + oled.print(timeBuffer); + oled.print(" "); + + for (int i = 0; i < activeProfile.numPhases; i++) { + if (i == currentPhase) { + oled.invertText(true); // Invert text for the current phase + + oled.setCursor(0, i + 2); // Set cursor to the row corresponding to the phase + long timeRemaining = (activeProfile.phases[i].duration * 60) - ((currentTime - phaseStartTime) / 1000); + formatTime(timeRemaining, timeBuffer); + oled.print(i + 1); + oled.print(". "); + oled.print(Input, 1); + oled.print("c "); + if (fabs(Setpoint - round(Setpoint)) < 0.05) { + oled.print(Setpoint, 0); // Print without decimals + } else { + oled.print(Setpoint, 1); // Print with 1 decimal place + } + oled.print("c "); + if (!isInTransition) { + oled.print(timeBuffer); + } + oled.print(" "); + } else { + oled.invertText(false); // Normal text for other phases + + oled.setCursor(0, i + 2); // Set cursor to the row corresponding to the phase + formatTime(activeProfile.phases[i].duration * 60, timeBuffer); + oled.print(i + 1); + oled.print(". "); + oled.print(activeProfile.phases[i].temperature); + oled.print("c "); + oled.print(timeBuffer); + oled.print(" "); + } + } + + if (temperatureSensorError) { + oled.invertText(true); + oled.setCursor(0, 0); + oled.setScale(2); + oled.print("T = "); + oled.print(Input); + oled.print(" "); + oled.setScale(1); + digitalWrite(activeBuzzerPin, HIGH); + delay(5); + digitalWrite(activeBuzzerPin, LOW); + } + + if (failedReadingCount) { + oled.setCursor(0, 7); + oled.print(failedReadingCount); + oled.print(" ("); + oled.print(failedReadingLastValue); + oled.print(") "); + } + + oled.invertText(false); // Ensure text inversion is off after the loop + + // oled.setCursor(110,7); + // sprintf(timeBuffer, "%3d", (int)(Output*100)); + // oled.print(timeBuffer); + // oled.update(); +} + +void displaySelection() { + // oled.clear(); + // Display all profiles with the selected one highlighted + for (int i = 0; i < (int) (sizeof(profiles) / sizeof(profiles[0])); i++) { + if (i == selectedProfileIndex) { + oled.invertText(true); // Highlight the selected profile + } + + oled.setCursor(0, i); // Set cursor to the correct row + oled.print(profiles[i].name); + + oled.invertText(false); // Reset text inversion for other profiles + } + oled.update(); +} + +void formatTime(long seconds, char* buffer) { + long hours = seconds / 3600; + long mins = (seconds % 3600) / 60; + int secs = seconds % 60; + + buffer[0] = '\0'; // Ensure the buffer is empty + + if (hours > 0) { + sprintf(buffer + strlen(buffer), "%ldh", hours); + } + if (mins > 0) { + sprintf(buffer + strlen(buffer), "%ldm", mins); + } + if (secs > 0) { + sprintf(buffer + strlen(buffer), "%ds", secs); + } +} \ No newline at end of file diff --git a/t_additional_checks.ino b/t_additional_checks.ino new file mode 100644 index 0000000..33f9c74 --- /dev/null +++ b/t_additional_checks.ino @@ -0,0 +1,28 @@ +LP_THREAD({ + if (isComplete && !boolLastCompletedState) { + boolLastCompletedState = true; + for(int i=0; i<10; i++) { + digitalWrite(activeBuzzerPin, HIGH); + delay(100); + digitalWrite(activeBuzzerPin, LOW); + delay(200); + } + } + LP_DELAY(10); +}); + + +// LP_TIMER(1000, AdditionalChecks); + +// void AdditionalChecks() { +// if (isComplete && !boolLastCompletedState) { +// boolLastCompletedState = true; +// for(int i=0; i<5; i++) { +// digitalWrite(activeBuzzerPin, HIGH); +// delay(100); +// digitalWrite(activeBuzzerPin, LOW); +// delay(500); +// } +// } +// } + diff --git a/t_encoder.ino b/t_encoder.ino new file mode 100644 index 0000000..24ca636 --- /dev/null +++ b/t_encoder.ino @@ -0,0 +1,51 @@ +LP_THREAD({ + enc1.tick(); + isLeft = enc1.isLeft(); + isRight = enc1.isRight(); + isClick = enc1.isClick(); + if (!isLeft && !isRight && !isClick) { + return; + } + + if (inSelectionMode) { + handleProfileSelection(); + } + else { + handleExecutionSelection(); + } + LP_DELAY(10); +}); + +void handleExecutionSelection() { + if (isClick) { + activeProfileIndex = 100; + activeProfile = profiles[activeProfileIndex]; + inSelectionMode = true; + writeEEPROM(); + oled.clear(); + displaySelection(); + return; + } + +} + +void handleProfileSelection() { + if (!isClick && !isLeft && !isRight) { + return; + } + + // Handle encoder input for selecting the profile + if (isRight) { + selectedProfileIndex = (selectedProfileIndex + 1) % (sizeof(profiles) / sizeof(profiles[0])); + } else if (isLeft) { + selectedProfileIndex = (selectedProfileIndex - 1 + (sizeof(profiles) / sizeof(profiles[0]))) % (sizeof(profiles) / sizeof(profiles[0])); + } + + displaySelection(); + + // Start the selected profile on button press + if (isClick) { + activeProfileIndex = selectedProfileIndex; + startExecution(); + } +} \ No newline at end of file diff --git a/t_heater.ino b/t_heater.ino new file mode 100644 index 0000000..40a8a91 --- /dev/null +++ b/t_heater.ino @@ -0,0 +1,54 @@ +LP_TIMER(500, HandleHeater); +void HandleHeater() { + static int currentPart = 0; + static bool states[PARTS]; + + if (inSelectionMode) { + digitalWrite(ssrPin, LOW); + return; + } + + int current = Output/100 * PARTS; + + int last = 0; + for (int i = 1; i < PARTS; i++) { + last += states[i] ? 1 : 0; + if (i) { + states[i-1] = states[i]; + } + } + bool next = current >= last ? true : false; + if (Output < 1) next = false; + states[PARTS-1] = next; + + oled.setCursor(128-6*PARTS, 7); + sprintf(timeBuffer, "%3d", (int)(Output)); + char symbol; + for (int i = 0; i < PARTS; i++) { + int index = i - (PARTS - 3); + symbol = index < 0 ? ' ' : timeBuffer[index]; + oled.invertText(states[i]); + oled.print(symbol); + oled.invertText(false); + } + + if (temperatureSensorError) { + next = 0; + } + + digitalWrite(ssrPin, next); + currentPart++; + if (currentPart >= PARTS) { + currentPart = 0; + } + +#ifdef PlotValues + Serial.print(Setpoint); + Serial.print(","); + Serial.print(Input); + Serial.print(","); + Serial.print(Output); + Serial.println(",0,100"); +#endif + +} diff --git a/t_main.ino b/t_main.ino new file mode 100644 index 0000000..be6e812 --- /dev/null +++ b/t_main.ino @@ -0,0 +1,95 @@ +LP_TIMER(1000, HandleExecution); +void HandleExecution() { + currentTime = millis(); + if (inSelectionMode) { + return; + } + totalElapsedTime = (currentTime - totalStartTime) / 1000; // Total elapsed time in seconds + + getPhaseAndTemperature(); + + regulator.input = (float)Input; + regulator.setpoint = Setpoint; + regulator.getResultNow(); + Output = regulator.output; + + 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++) { + int 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); + int transitionDuration = tempDiff * 60 * activeProfile.transitionMinutesPerDegree; + + if (totalElapsedTime < accumulatedTime + transitionDuration) { + isInTransition = true; + currentPhase = i - 1; // Keep currentPhase as the previous phase + int 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 < 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 += activeProfile.phases[i].duration * 60; + if (i < activeProfile.numPhases - 1) { + int tempDiff = abs(activeProfile.phases[i + 1].temperature - activeProfile.phases[i].temperature); + totalProcessTime += 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; +} \ No newline at end of file diff --git a/t_temperature_sensor.ino b/t_temperature_sensor.ino new file mode 100644 index 0000000..2797143 --- /dev/null +++ b/t_temperature_sensor.ino @@ -0,0 +1,20 @@ +LP_TIMER(1000, HandleTemperatureSensor); +void HandleTemperatureSensor() { +#ifdef TempSensorDallas + Input = (double) sensors.getTempCByIndex(0); + + sensors.requestTemperatures(); // Send the command to get temperatures +#endif +#ifdef TempSensorMax // to go into the read temp function, rename from dallas temp + Input = thermocouple.readCelsius(); +#endif + + if (isnan(Input) || Input < 20 || Input > 95) { + failedReadingLastValue = (float) Input; + failedReadingCount++; + temperatureSensorError = true; + } + else { + temperatureSensorError = false; + } +}