From 6730f9f390dee2ac0f2cc55317072951bbf1278d Mon Sep 17 00:00:00 2001 From: Chris Giacofei Date: Fri, 26 Apr 2024 08:55:20 -0400 Subject: [PATCH] Latest boil kettle code. --- boil_kettle/boil_kettle.ino | 288 ++++++++++++++++++++++++++++-------- 1 file changed, 226 insertions(+), 62 deletions(-) diff --git a/boil_kettle/boil_kettle.ino b/boil_kettle/boil_kettle.ino index a268eb7..efe5278 100644 --- a/boil_kettle/boil_kettle.ino +++ b/boil_kettle/boil_kettle.ino @@ -1,92 +1,256 @@ + //Built-in #include #include -#include -#include +//#include // Additoinal Libraries -#include -#include +#include +//#include #include -#include // LiquidMenu_config.h needs to be modified to use I2C. +#include // LiquidMenu_config.h needs to be modified to use I2C. #include +#include +//#include // My Includes #include "config.h" -#include "globals.h" -#include "src/datatypes.h" -#include "src/button.h" -#include "src/slowPWM.h" -#include "src/thermoControl.h" -#include "src/mqtt.h" -#include "src/functions.h" +#include "src/button/button.h" +#include "src/slowPWM/slowPWM.h" +#include "src/thermoControl/thermoControl.h" +//#include "src/Arduino-PID-Library/PID_v1.h" -void setup() { - /** - * Any state information that needs to be kept between reboots - * will be stored in EEPROM. - * - * This will allow modifying these through MQTT communication - * later without needing to recompile the code. - */ - ConfigData config; - EEPROM.get(ConfAddress, config); +double KettleDuty = 0; +double KettleSetpoint = 70; +double CurrentTemp; +bool tuning = false; - unsigned long lastRun = millis() - UpdateInterval; - Serial.begin(9600); +//EEPROMStorage eepromKp(0, 2.0); // 9 bytes for doubles 8 + 1 for checksum +//EEPROMStorage eepromKi(9, 5.0); // Initialize at zero. +//EEPROMStorage eepromKd(18, 1.0); - Ethernet.begin(config.mac, config.ip); +// User I/O objects. +Button Enter; +slowPWM boilPWM; +MD_REncoder rotary = MD_REncoder(encoderDT, encoderCLK); +LiquidCrystal_I2C lcd(0x27, 20, 4); +Adafruit_MAX31865 thermoRTD = Adafruit_MAX31865(KettleRTD); +thermoControl Controller(&CurrentTemp, &KettleSetpoint, &KettleDuty, AUTOMATIC); - /** - * Setup pins and interrupts/ - */ - attachInterrupt(digitalPinToInterrupt(I_CLK), doEncoder, CHANGE); - attachInterrupt(digitalPinToInterrupt(I_DT), doEncoder, CHANGE); +//PID ControllerPID(&CurrentTemp, &KettleDuty, &KettleSetpoint, eepromKp, eepromKi, eepromKd, P_ON_M, DIRECT); - rotary.begin(); - Enter.begin(I_BTN); - boilPWM.begin(O_PWM, config.period); +unsigned long lastRun = 0; - /** - * Kettle temp control - */ - KettleController.begin(I_CS1); - KettleController.Hysteresis(config.hysteresis); - KettleController.ThreshPWR(config.threshold); +// Return a character array to represent the +// On/Off state of the kettle. +char* KettleState() { + switch (Controller.Mode()) { + case OFF: return (char*)"OFF"; + case AUTOMATIC: return (char*)"AUT"; + case MANUAL: return (char*)"MAN"; + } +} - /** - * No sense messing with MQTT if we're not on the network. - */ - if (Ethernet.linkStatus() == LinkON) { - mqtt_client.setServer(config.mqtt.broker, 1883); - mqtt_client.setClient(net); - mqtt_client.setCallback(MessageReceived); - ConnectMQTT(); +byte setpoint() { + return (byte)KettleSetpoint; +} + +byte duty() { + return (byte)KettleDuty; +} + +byte current() { + return (byte)CurrentTemp; +} + +// LCD menu setup. +LiquidLine KettleState_line(0, 0, "Boil Kettle ", KettleState); +LiquidLine kettle_temp_line(0, 1, "Setpoint (F) ", setpoint); +LiquidLine kettle_power_line(0, 2, "Power (%) ", duty); +LiquidLine kettle_currenttemp_line(0, 3, "Actual Temp (F) ", current); +LiquidScreen home_screen(KettleState_line, kettle_temp_line, kettle_power_line,kettle_currenttemp_line); +LiquidMenu menu(lcd); + +// Interrupt function to run when encoder is turned. +// +// Increases/decreases the kettle output to a max +// of 100% and minimum of 0%. +void doEncoder() { + uint8_t result = rotary.read(); + uint8_t inc = 1; + + if (result) { + uint8_t speed = rotary.speed(); + speed >= 10 ? inc = 5 : inc = 1; } - /** - * Fire up the LCD. - */ + if (Controller.Mode() == AUTOMATIC) { + if (result == DIR_CW) { + KettleSetpoint = (KettleSetpoint / inc) * inc + inc; + } else if (result == DIR_CCW) { + KettleSetpoint = (KettleSetpoint / inc) * inc - inc; + } + + KettleSetpoint = max(KettleSetpoint,0); + KettleSetpoint = min(KettleSetpoint,212); + + } else if (Controller.Mode() == MANUAL) { + if (result == DIR_CW) { + KettleDuty = (KettleDuty / inc) * inc + inc; + } else if (result == DIR_CCW) { + KettleDuty = (KettleDuty / inc) * inc - inc; + } + + KettleDuty = max(KettleDuty,0); + KettleDuty = min(KettleDuty,100); + + } + //menu.update(); +} + +void setup() { + + lastRun = millis() - UpdateInterval; + Serial.begin(115200); + rotary.begin(); + thermoRTD.begin(MAX31865_3WIRE); + + attachInterrupt(digitalPinToInterrupt(encoderCLK), doEncoder, CHANGE); + attachInterrupt(digitalPinToInterrupt(encoderDT), doEncoder, CHANGE); + + + pinMode(encoderCLK, INPUT_PULLUP); + pinMode(encoderDT, INPUT_PULLUP); + Enter.begin(encoderBTN); + boilPWM.begin(kettlePWM, PeriodPWM); + Controller.Mode(OFF); + lcd.init(); lcd.backlight(); menu.init(); menu.add_screen(home_screen); menu.update(); - }; -void loop() { - UpdateBoilKettle(); - - unsigned long elapsedTime = (millis() - lastRun); - - if (Ethernet.linkStatus() == LinkON && elapsedTime >= UpdateInterval) { - mqtt_client.loop(); - //if (!mqtt_client.connected()) ConnectMQTT(); - - SendSensorData(); - lastRun = millis(); +void run_kettle() { + if (Enter.pressed()) { + Serial.println("Enter Pressed"); + if (Controller.CycleMode() == OFF) { + KettleDuty = 0; + } + menu.update(); } + Controller.Compute(); + } +/* +void run_tuning() { + if (Enter.pressed()) { + stopAutoTune(); + } + int result = ControllerPID.ComputeTune(); + if (result!=0) + { + tuning = false; + } + if(!tuning) + { //we're done, set the tuning parameters + ControllerPID.SetTunings(ControllerPID.TunedKp(),ControllerPID.TunedKi(),ControllerPID.TunedKd()); + ControllerPID.Mode(OFF); + } +} +*/ +void loop() { + unsigned long now = millis(); + static unsigned long lastTime=now-2000; + unsigned long timeChange = (now - lastTime); + static byte lastoutput = LOW; + static double lastKettleDuty = 0; + static double lastKettleSetpoint = 0; + static byte lastTemperature; + + if(timeChange >= 2000) { + CurrentTemp = 32 + 1.8 * thermoRTD.temperature(RNOMINAL_KETTLE, RREF_KETTLE); + lastTime = now; + } + + if (!tuning) { + run_kettle(); + } else { + //run_tuning(); + } + + byte output = boilPWM.Compute(KettleDuty); + + if (output != lastoutput) { + digitalWrite(kettlePWM, output); + lastoutput = output; + } + + if (lastKettleDuty != KettleDuty || lastKettleSetpoint != KettleSetpoint || lastTemperature != (byte)CurrentTemp) { + menu.update(); + lastKettleDuty = KettleDuty; + lastKettleSetpoint = KettleSetpoint; + lastTemperature = (byte)CurrentTemp; + } + +} +/* +void startAutoTune() { + if(!tuning) { + //Set the output to the desired starting frequency. + KettleDuty=50; + ControllerPID.SetNoiseBand(1); + ControllerPID.SetOutputStep(30); + ControllerPID.SetLookbackSec(20); + ControllerPID.Mode(AUTOMATIC); + tuning=true; + } +} + +void stopAutoTune() { + if(tuning) { //cancel autotune + ControllerPID.Cancel(); + ControllerPID.Mode(OFF); + tuning=false; + } +} + +void SaveTunings() { + eepromKp = ControllerPID.GetKp(); + eepromKi = ControllerPID.GetKi(); + eepromKd = ControllerPID.GetKd(); +} + +void SerialSend() +{ + Serial.print("setpoint: ");Serial.print(KettleSetpoint); Serial.print(" "); + Serial.print("input: ");Serial.print(CurrentTemp); Serial.print(" "); + Serial.print("output: ");Serial.print(KettleDuty); Serial.print(" "); + if(tuning){ + Serial.println("tuning mode"); + } else { + Serial.print("kp: ");Serial.print(ControllerPID.GetKp());Serial.print(" "); + Serial.print("ki: ");Serial.print(ControllerPID.GetKi());Serial.print(" "); + Serial.print("kd: ");Serial.print(ControllerPID.GetKd());Serial.println(); + } +} + +void SerialReceive() +{ + if(Serial.available()) { + String myinput; + myinput = Serial.readString(); + myinput.trim(); + if(myinput=="start"){ + startAutoTune(); + } else if(myinput=="stop") { + stopAutoTune(); + } else if(myinput=="save") { + SaveTunings(); + } + } +} +*/ \ No newline at end of file