diff --git a/README.md b/README.md index 1a6dd8b..362eb45 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,5 @@ ## TODO -* eeprom saving every 5 minutes and resuming +* output temp control is not ideal (on/off does not represent values between 0 and 100) +* experiment with p,i,d diff --git a/hot_fermentation.ino b/hot_fermentation.ino index 62d380f..ca41c6e 100644 --- a/hot_fermentation.ino +++ b/hot_fermentation.ino @@ -1,9 +1,15 @@ +#define useEEPROM 1 + #include #include #include #include -#include "GyverEncoder.h" // Include the GyverEncoder library +#include "GyverEncoder.h" + +#if useEEPROM #include +#endif + // MAX6675 configuration int max_SO = 12; @@ -22,7 +28,7 @@ GyverOLED oled; Encoder enc1(CLK, DT, SW, TYPE2); // SSR pin configuration -const int ssrPin = 7; +const int ssrPin = 2; // Profile structure definition struct Phase { @@ -39,10 +45,11 @@ struct Profile { // Profiles definition Profile profiles[] = { - {"Test", 0, {{49, 1}, {51, 1}}, 2}, - {"Пшеница", 1, {{47, 40}, {55, 40}, {65, 20}, {72, 20}, {85, 20}}, 5}, - {"Veggies Sous Vide", 0, {{85, 120}}, 1}, - {"Фитаза/Протеаза", 2, {{47, 120}, {53, 120}, {65, 150}, {72, 60}, {90, 105}, {50, 60}}, 6}, + {"Chickpeas", 3, {{47, 120}, {53, 120}, {65, 180}, {72, 90}, {90, 90}}, 5}, + {"Lentils", 3, {{47, 120}, {53, 120}, {65, 180}, {72, 90}, {90, 15}}, 5}, + {"Wheat", 3, {{47, 60}, {53, 60}, {65, 20}, {72, 20}, {85, 20}}, 5}, + {"Veggies Sous Vide", 2, {{55, 30}, {85, 120}}, 2}, + {"Test", 1, {{49, 1}, {51, 1}}, 2}, }; // Global variables for profile selection and execution @@ -57,7 +64,7 @@ bool inSelectionMode = true; // PID Control variables double Setpoint, Input, Output; -double Kp = 2, Ki = 0.5, Kd = 0.25; +double Kp = 1, Ki = 2, Kd = 0.25; PID myPID(&Input, &Output, &Setpoint, Kp, Ki, Kd, DIRECT); // Timing variables @@ -80,7 +87,9 @@ void setup() { Serial.begin(9600); oled.init(); // Initialize the OLED oled.clear(); // Clear the display - displaySelection(); + readEEPROM(); + myPID.SetMode(AUTOMATIC); + myPID.SetOutputLimits(0, 1); } void loop() { @@ -88,7 +97,8 @@ void loop() { if (inSelectionMode) { handleProfileSelection(); - } else { + } + else { handleExecution(); } } @@ -97,7 +107,7 @@ void handleExecution() { currentTime = millis(); totalElapsedTime = (currentTime - totalStartTime) / 1000; // Total elapsed time in seconds - if ((currentTime - lastEEPROMWriteTime) >= (unsigned int) 10*60*1000) { + if ((currentTime - lastEEPROMWriteTime) >= (long)10*60*1000) { writeEEPROM(); } @@ -109,6 +119,11 @@ void handleExecution() { } myPID.Compute(); + // Serial.print(Input); + // Serial.print(" "); + // Serial.print(Output); + // Serial.print(" "); + // Serial.println(Setpoint); // Switch SSR based on PID output and interval control if (currentTime - ssrLastSwitchTime > ssrSwitchInterval) { digitalWrite(ssrPin, Output > 0.5 ? HIGH : LOW); @@ -122,7 +137,16 @@ void handleExecution() { // Display all phases and highlight the current one printPhases(); - oled.update(); + if (enc1.isClick()) { + Serial.println("clicked! resetting..."); + activeProfileIndex = 100; + activeProfile = profiles[activeProfileIndex]; + inSelectionMode = true; + writeEEPROM(); + oled.clear(); + displaySelection(); + return; + } delay(1000); // Update every second } @@ -148,7 +172,6 @@ void handleProfileSelection() { if (click) { activeProfileIndex = selectedProfileIndex; activeProfile = profiles[activeProfileIndex]; - calculateTotalTime(); inSelectionMode = false; // Switch to execution mode phaseStartTime = totalStartTime = millis(); // Start the timer totalElapsedTime = 0; @@ -156,7 +179,10 @@ void handleProfileSelection() { myPID.SetOutputLimits(0, 1); // SSR is either ON or OFF // digitalWrite(ssrPin, HIGH); // Start with heater on ssrLastSwitchTime = millis(); + calculateTotalTime(); + getPhaseAndTemperature(); writeEEPROM(); + oled.clear(); } } @@ -178,6 +204,7 @@ void displaySelection() { 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; @@ -271,7 +298,7 @@ void printPhases() { for (int i = 0; i < activeProfile.numPhases; i++) { - if (i == currentPhase && !isComplete) { + 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 @@ -282,12 +309,14 @@ void printPhases() { oled.print(Input, 1); oled.print("c "); if (fabs(Setpoint - round(Setpoint)) < 0.05) { - oled.print((int)Setpoint); // Print without decimals + oled.print(Setpoint, 0); // Print without decimals } else { - oled.print(Setpoint, 1); // Print with 1 decimal place + oled.print(Setpoint, 1); // Print with 1 decimal place } oled.print("c "); - oled.print(timeBuffer); + if (!isInTransition) { + oled.print(timeBuffer); + } oled.print(" "); } else { oled.invertText(false); // Normal text for other phases @@ -304,6 +333,11 @@ void printPhases() { } oled.invertText(false); // Ensure text inversion is off after the loop + + oled.setCursor(110,7); + oled.print(Output*100,0); + oled.print(" "); + oled.update(); } void formatTime(long seconds, char* buffer) { @@ -325,6 +359,7 @@ void formatTime(long seconds, char* buffer) { } void writeEEPROM() { + #if useEEPROM lastEEPROMWriteTime = millis(); EEPROM.put(0, activeProfileIndex); // Store the active profile index EEPROM.put(4, totalElapsedTime); // Store the total elapsed time @@ -332,4 +367,27 @@ void writeEEPROM() { 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 } \ No newline at end of file