hot-fermentation/hot_fermentation.ino

132 lines
4.1 KiB
Arduino
Raw Normal View History

2024-08-29 12:37:31 +07:00
#include <max6675.h>
#include <Wire.h>
#include <PID_v1.h>
2024-08-29 23:01:32 +07:00
#include <GyverOLED.h> // Include the GyverOLED library
2024-08-29 12:37:31 +07:00
// MAX6675 configuration
int max_SO = 12;
int max_CS = 10;
int max_SCK = 13;
MAX6675 thermocouple(max_SCK, max_CS, max_SO);
2024-08-29 23:01:32 +07:00
// OLED configuration
GyverOLED<SSD1306_128x64, OLED_BUFFER> oled;
2024-08-29 12:37:31 +07:00
// 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);
2024-08-29 23:01:32 +07:00
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();
2024-08-29 12:37:31 +07:00
delay(2000);
2024-08-29 23:01:32 +07:00
oled.setScale(0); // Set text scale to 2 for better visibility
2024-08-29 12:37:31 +07:00
// 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) {
2024-08-29 23:01:32 +07:00
oled.clear();
oled.print("Complete");
2024-08-29 12:37:31 +07:00
digitalWrite(ssrPin, LOW); // Turn off the heater
return; // Stop further execution
}
phaseStartTime = currentTime; // Reset the start time for the new phase
Setpoint = temperatures[currentPhase];
}
2024-08-29 23:01:32 +07:00
// 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();
2024-08-29 12:37:31 +07:00
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);
2024-08-29 23:01:32 +07:00
}