Compare commits

...

3 Commits

Author SHA1 Message Date
c402c63f3d time format 2024-08-30 00:07:12 +07:00
24b1986dec phases displayed across whole screen 2024-08-29 23:58:25 +07:00
12f478271f oled changed 2024-08-29 23:01:32 +07:00
2 changed files with 110 additions and 58 deletions

1
.gitignore vendored
View File

@ -1 +1,2 @@
*.swp *.swp
.idea*

View File

@ -1,7 +1,7 @@
#include <LiquidCrystal_I2C.h>
#include <max6675.h> #include <max6675.h>
#include <Wire.h> #include <Wire.h>
#include <PID_v1.h> #include <PID_v1.h>
#include <GyverOLED.h> // Include the GyverOLED library
// MAX6675 configuration // MAX6675 configuration
int max_SO = 12; int max_SO = 12;
@ -9,35 +9,35 @@ int max_CS = 10;
int max_SCK = 13; int max_SCK = 13;
MAX6675 thermocouple(max_SCK, max_CS, max_SO); MAX6675 thermocouple(max_SCK, max_CS, max_SO);
// LCD configuration via I2C // OLED configuration
LiquidCrystal_I2C lcd(0x27, 16, 2); // Set the LCD I2C address GyverOLED<SSD1306_128x64, OLED_BUFFER> oled;
// SSR pin configuration // SSR pin configuration
const int ssrPin = 7; const int ssrPin = 7;
// Process phases (temperatures in Celsius and duration in minutes) // Profile structure definition
struct Phase {
int temperature;
int duration; // in minutes
};
// const int temperatures[] = {49, 51, 55, 45}; struct Profile {
// const int phaseDurations[] = {30, 30, 30, 30}; // Individual durations for each phase in minutes const char* name;
// const int numPhases = 3; Phase phases[6]; // Maximum of 6 phases per profile
int numPhases;
};
// Profiles definition
Profile profiles[] = {
{"Test", {{49, 1}, {51, 1}, {55, 1}, {45, 1}}, 4},
{"Пшеница", {{47, 40}, {55, 40}, {65, 20}, {72, 20}, {85, 20}}, 5},
{"Veggies Sous Vide", {{85, 120}}, 1},
{"Фитаза/Протеаза", {{47, 120}, {53, 120}, {65, 150}, {72, 60}, {90, 105}, {50, 60}}, 6},
};
// const int temperatures[] = {47, 55, 65, 72, 85, 0}; // Select active profile (constant at this point)
// const int phaseDurations[] = {20, 20, 20, 20, 20, 5}; // Individual durations for each phase in minutes const int activeProfileIndex = 0; // Index of the active profile, starting from 0
// const int numPhases = 5; Profile activeProfile = profiles[activeProfileIndex];
// 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 // PID Control variables
double Setpoint, Input, Output; double Setpoint, Input, Output;
@ -48,19 +48,26 @@ PID myPID(&Input, &Output, &Setpoint, Kp, Ki, Kd, DIRECT);
unsigned long phaseStartTime; unsigned long phaseStartTime;
unsigned long totalStartTime; unsigned long totalStartTime;
unsigned long ssrLastSwitchTime; unsigned long ssrLastSwitchTime;
unsigned long totalElapsedTime;
unsigned long totalProcessTime;
const int ssrSwitchInterval = 1000; // SSR switching interval in milliseconds const int ssrSwitchInterval = 1000; // SSR switching interval in milliseconds
// Buffer for formatted time strings
char timeBuffer[10];
void setup() { void setup() {
pinMode(ssrPin, OUTPUT); pinMode(ssrPin, OUTPUT);
Serial.begin(9600); Serial.begin(9600);
lcd.init(); oled.init(); // Initialize the OLED
lcd.backlight(); oled.clear(); // Clear the display
lcd.print("Starting..."); oled.setScale(2); // Set text scale to 2 for better visibility
delay(2000); oled.print("Starting...");
oled.update();
oled.setScale(1); // Set text scale back to 1 for more detailed information
// Begin the first phase // Begin the first phase
phaseStartTime = totalStartTime = millis(); phaseStartTime = totalStartTime = millis();
Setpoint = temperatures[0]; Setpoint = activeProfile.phases[0].temperature;
myPID.SetMode(AUTOMATIC); myPID.SetMode(AUTOMATIC);
myPID.SetOutputLimits(0, 1); // SSR is either ON or OFF myPID.SetOutputLimits(0, 1); // SSR is either ON or OFF
digitalWrite(ssrPin, HIGH); // Start with heater on digitalWrite(ssrPin, HIGH); // Start with heater on
@ -81,47 +88,91 @@ void loop() {
} }
// Display time calculations // Display time calculations
unsigned long totalElapsedTime = (currentTime - totalStartTime) / 1000; // Total elapsed time in seconds totalElapsedTime = (currentTime - totalStartTime) / 1000; // Total elapsed time in seconds
unsigned long totalProcessTime = 0; totalProcessTime = 0;
for (int i = 0; i < numPhases; i++) { for (int i = 0; i < activeProfile.numPhases; i++) {
totalProcessTime += phaseDurations[i] * 60; totalProcessTime += activeProfile.phases[i].duration * 60;
} }
// Check if the phase duration is complete // Check if the phase duration is complete
if ((currentTime - phaseStartTime) / 1000 >= phaseDurations[currentPhase] * 60) { if ((currentTime - phaseStartTime) / 1000 >= activeProfile.phases[currentPhase].duration * 60) {
currentPhase++; currentPhase++;
if (currentPhase >= numPhases) { if (currentPhase >= activeProfile.numPhases) {
lcd.clear(); oled.clear();
lcd.print("Complete"); oled.print("Complete");
digitalWrite(ssrPin, LOW); // Turn off the heater digitalWrite(ssrPin, LOW); // Turn off the heater
return; // Stop further execution return; // Stop further execution
} }
phaseStartTime = currentTime; // Reset the start time for the new phase phaseStartTime = currentTime; // Reset the start time for the new phase
Setpoint = temperatures[currentPhase]; Setpoint = activeProfile.phases[currentPhase].temperature;
} }
// 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); // Display all phases and highlight the current one
lcd.print(currentPhase + 1); printPhases(currentPhase, currentTime - phaseStartTime);
lcd.print(". ");
lcd.print((int)Input); oled.update();
lcd.print("C ");
lcd.print((int)Setpoint);
lcd.print("C ");
lcd.print(formatTime((phaseDurations[currentPhase] * 60) - ((currentTime - phaseStartTime) / 1000)));
delay(1000); // Update every second delay(1000); // Update every second
} }
String formatTime(long seconds) { void printPhases(int currentPhase, unsigned long phaseElapsedTime) {
long mins = seconds / 60; oled.clear();
int secs = seconds % 60;
return (mins < 10 ? "0" : "") + String(mins) + ":" + (secs < 10 ? "0" : "") + String(secs); oled.setCursor(0, 0);
oled.print(activeProfile.name);
// Display the totals and current state on the OLED
oled.setCursor(18, 1);
formatTime(totalElapsedTime, timeBuffer);
oled.print(timeBuffer);
oled.print(" / ");
formatTime(totalProcessTime, timeBuffer);
oled.print(timeBuffer);
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
unsigned long timeRemaining = (activeProfile.phases[i].duration * 60) - (phaseElapsedTime / 1000);
formatTime(timeRemaining, timeBuffer);
oled.print(i + 1);
oled.print(". ");
oled.print((int)Input);
oled.print("c ");
oled.print((int)Setpoint);
oled.print("c ");
oled.print(timeBuffer);
} 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.invertText(false); // Ensure text inversion is off after the loop
}
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);
}
} }