From d52e559ef4c3a2a6c42076c934594a353d28d4bf Mon Sep 17 00:00:00 2001 From: Aleksander Belov Date: Thu, 29 Aug 2024 12:37:31 +0700 Subject: [PATCH] initial --- .gitignore | 1 + hot_fermentation.ino | 127 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 128 insertions(+) create mode 100644 .gitignore create mode 100644 hot_fermentation.ino diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1377554 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +*.swp diff --git a/hot_fermentation.ino b/hot_fermentation.ino new file mode 100644 index 0000000..e1a70b6 --- /dev/null +++ b/hot_fermentation.ino @@ -0,0 +1,127 @@ +#include +#include +#include +#include + +// MAX6675 configuration +int max_SO = 12; +int max_CS = 10; +int max_SCK = 13; +MAX6675 thermocouple(max_SCK, max_CS, max_SO); + +// LCD configuration via I2C +LiquidCrystal_I2C lcd(0x27, 16, 2); // Set the LCD I2C address + +// 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); + lcd.init(); + lcd.backlight(); + lcd.print("Starting..."); + delay(2000); + + // 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) { + lcd.clear(); + lcd.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 LCD + lcd.clear(); + lcd.setCursor(0, 0); + lcd.print(formatTime(totalElapsedTime)); + lcd.print(" ("); + lcd.print(formatTime(totalProcessTime)); + lcd.print(")"); + + lcd.setCursor(0, 1); + lcd.print(currentPhase + 1); + lcd.print(". "); + lcd.print((int)Input); + lcd.print("C "); + lcd.print((int)Setpoint); + lcd.print("C "); + lcd.print(formatTime((phaseDurations[currentPhase] * 60) - ((currentTime - phaseStartTime) / 1000))); + + 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); +} \ No newline at end of file