#include #include #define useEEPROM 1 // #define TempSensorMax #define TempSensorDallas // #define PlotValues // #include #include #include "GyverEncoder.h" #if useEEPROM #include #endif #ifdef TempSensorMax #include // MAX6675 configuration int max_SO = 12; int max_CS = 10; int max_SCK = 13; MAX6675 thermocouple(max_SCK, max_CS, max_SO); #endif #ifdef TempSensorDallas #include #include #define ONE_WIRE_BUS 9 OneWire oneWire(ONE_WIRE_BUS); // Pass our oneWire reference to Dallas Temperature. DallasTemperature sensors(&oneWire); #endif // OLED configuration // GyverOLED oled; GyverOLED oled; // Encoder configuration #define CLK 5 #define DT 6 #define SW 7 Encoder enc1(CLK, DT, SW, TYPE2); // SSR pin configuration const int ssrPin = 2; const int triacPwm = 10; const int activeBuzzerPin = 8; // Profile structure definition struct Phase { int temperature; int duration; // in minutes }; struct Profile { const char* name; int transitionMinutesPerDegree; Phase phases[6]; // Maximum of 6 phases per profile int numPhases; }; // Profiles definition Profile profiles[] = { {"Chickpeas", 1, {{46, 120}, {55, 60}, {65, 150}, {70, 60}, {90, 105}}, 5}, {"Chickpeas long", 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}, {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}, // {"Amazake", 1, {{51, 480}}, 1}, {"37, 3 days", 1, {{37, 1440}, {37, 1440}, {37, 1440}}, 3}, // {"SV", 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 int activeProfileIndex = 100; // 100 indicates no profile selected yet int selectedProfileIndex = 0; // Index of the currently selected profile in the selection mode Profile activeProfile; // The active profile once selected // Global variables for current phase, setpoint, and transition state int currentPhase; bool isInTransition = false; bool inSelectionMode = true; // PID Control variables // double Kp = 0.5, Ki = 1, Kd = 0.05; // PID myPID(&Input, &Output, &Setpoint, Kp, Ki, Kd, DIRECT); // #include "GyverPID.h" #include "pid.h" double Setpoint, Input, Output; GyverPID regulator(10, 2, 10, 1000); bool temperatureSensorError = false; // Timing variables long phaseStartTime; long totalStartTime; long ssrLastSwitchTime; long totalElapsedTime; long totalProcessTime; long finishTime = 0; long currentTime = 0; long lastEEPROMWriteTime = 0; bool isClick = false; bool isLeft = false; bool isRight = false; bool isComplete = false; const int ssrSwitchInterval = 1000; // SSR switching interval in milliseconds // Buffer for formatted time strings char timeBuffer[10]; bool boolLastCompletedState = false; float failedReadingLastValue = 0; int failedReadingCount = 0; #define PARTS 8 void setup() { pinMode(ssrPin, OUTPUT); pinMode(activeBuzzerPin, OUTPUT); Serial.begin(9600); oled.init(); // Initialize the OLED oled.clear(); // Clear the display readEEPROM(); regulator.setDirection(NORMAL); // направление регулирования (NORMAL/REVERSE). ПО УМОЛЧАНИЮ СТОИТ NORMAL regulator.setLimits(0, 100); // пределы (ставим для 8 битного ШИМ). ПО УМОЛЧАНИЮ СТОЯТ 0 И 255 regulator.setpoint = 0; pinMode(triacPwm, OUTPUT); configureTimer1(1000); setPWMDutyCycle(0); #ifdef TempSensorDallas sensors.begin(); DeviceAddress tempDeviceAddress; sensors.getAddress(tempDeviceAddress, 0); sensors.setResolution(tempDeviceAddress, 12); sensors.setWaitForConversion(false); #endif } void loop() { Looper.loop(); } // Function to configure Timer1 for PWM with the specified window duration void configureTimer1(unsigned long windowMillis) { // Disable interrupts while configuring the timer noInterrupts(); // Reset Timer/Counter1 Control Registers TCCR1A = 0; TCCR1B = 0; TCNT1 = 0; // Set the prescaler to 256 TCCR1B |= (1 << CS12); // Set prescaler to 256 // Calculate the top value for Timer1 based on the window duration unsigned long ticks = (62500 * windowMillis) / 1000 / 2; // Set the top value for Timer1 (ICR1) based on the calculated ticks ICR1 = ticks - 1; // Subtract 1 because the counter starts at 0 // Configure Timer1 for Phase Correct PWM with ICR1 as TOP // Enable non-inverted PWM on OC1B (Pin 10) TCCR1A = (1 << WGM11) | (1 << COM1B1); // Only configure OC1B for PWM // Set Phase Correct PWM mode with ICR1 as TOP TCCR1B |= (1 << WGM13); // No WGM12 // Enable interrupts again interrupts(); } void setPWMDutyCycle(uint8_t duty) { OCR1B = (unsigned long)duty * ICR1 / 255; // Set the duty cycle for Pin 10 (OC1B) }