185 lines
4.9 KiB
C++
185 lines
4.9 KiB
C++
#include <Arduino.h>
|
|
#include <Looper.h>
|
|
|
|
#define useEEPROM 1
|
|
// #define TempSensorMax
|
|
#define TempSensorDallas
|
|
// #define PlotValues
|
|
|
|
// #include <Wire.h>
|
|
#include <GyverOLED.h>
|
|
#include "GyverEncoder.h"
|
|
|
|
#if useEEPROM
|
|
#include <EEPROM.h>
|
|
#endif
|
|
|
|
#ifdef TempSensorMax
|
|
#include <max6675.h>
|
|
// 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 <OneWire.h>
|
|
#include <DallasTemperature.h>
|
|
#define ONE_WIRE_BUS 9
|
|
OneWire oneWire(ONE_WIRE_BUS);
|
|
|
|
// Pass our oneWire reference to Dallas Temperature.
|
|
DallasTemperature sensors(&oneWire);
|
|
#endif
|
|
|
|
// OLED configuration
|
|
// GyverOLED<SSD1306_128x64> oled;
|
|
GyverOLED<SSD1306_128x64, OLED_NO_BUFFER> 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},
|
|
{"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"
|
|
double Setpoint, Input, Output;
|
|
GyverPID regulator(50, 1, 5, 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)
|
|
}
|