From 6eecd9b6096ca20a71d7c5437ab876dc7dfba8ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Lino?= Date: Tue, 11 Aug 2015 20:22:00 +0100 Subject: [PATCH] rough draft of the code for the new version. I'll call it 2.0.001 --- brew.ino | 2035 ++++++++++++++++++++++++++++++------------------------ 1 file changed, 1123 insertions(+), 912 deletions(-) diff --git a/brew.ino b/brew.ino index 08fce82..c79baf9 100644 --- a/brew.ino +++ b/brew.ino @@ -1,252 +1,321 @@ -// ######################### DECLARE ######################### -// ++++++++++++++++++++++++ ERROR ++++++++++++++++++++++++ -//#include "error.h" -// ++++++++++++++++++++++++ ERROR ++++++++++++++++++++++++ -// ++++++++++++++++++++++++ Library - DHT ++++++++++++++++++++++++ -//#include "DHT.h" //DHT humidity/temperature sensors -//#define DHTPIN 2 // What pin we're connected to -//#define DHTTYPE DHT11 // DHT 11 -#define ponto1 A4// -//#define ponto2 A5// -//#define R1 99.45 -//#define R2 100.2 -//#define R3 100.05 -//#define calibragem 12.709066573 - -//float amostra1;// -float temperatura, temperatura1;// -float tabela[] = {100.00, 100.39, 100.78, 101.17, 101.56, 101.95, 102.34, 102.73, 103.12, 103.51, 103.90, 104.29, 104.68, 105.07, 105.46, 105.85, 106.24, 106.63, 107.02, 107.40, 107.79, 108.18, 108.57, 108.96, 109.35, 109.73, 110.12, 110.51, 110.90, 111.29, 111.67, 112.06, 112.45, 112.83, 113.22, 113.61, 114.00, 114.38, 114.77, 115.15, 115.54, 115.93, 116.31, 116.70, 117.08, 117.47, 117.86, 118.24, 118.63, 119.01, 119.40, 119.78, 120.17, 120.55, 120.94, 121.32, 121.71, 122.09, 122.47, 122.86, 123.24, 123.63, 124.01, 124.39, 124.78, 125.16, 125.54, 125.93, 126.31, 126.69, 127.08, 127.46, 127.84, 128.22, 128.61, 128.99, 129.37, 129.75, 130.13, 130.52, 130.90, 131.28, 131.66, 132.04, 132.42, 132.80, 133.18, 133.57, 133.95, 134.33, 134.71, 135.09, 135.47, 135.85, 136.23, 136.61, 136.99, 137.37, 137.75, 138.13, 138.51, 138.88, 139.26, 139.64, 140.02, 140.40, 140.78, 141.16, 141.54, 141.91, 142.29, 142.67, 143.05, 143.43, 143.80, 144.18, 144.56, 144.94, 145.31, 145.69, 146.07, 146.44, 146.82, 147.20, 147.57, 147.95, 148.33, 148.70, 149.08, 149.46, 149.83, 150.21, 150.58, 150.96, 151.33, 151.71, 152.08, 152.46, 152.83, 153.21, 153.58, 153.96, 154.33, 154.71, 155.08, 155.46, 155.83, 156.20, 156.58, 156.95, 157.33, 157.70, 158.07, 158.45, 158.82, 159.19, 159.56, 159.94, 160.31, 160.68, 150.00, 160.00, 161.05, 161.43, 161.80, 162.17, 162.54, 162.91, 163.29, 163.66, 164.03, 164.40, 164.77, 165.14, 165.51, 165.89, 166.26, 166.63, 167.00, 167.37, 167.74, 168.11, 168.48, 168.85, 169.22, 169.59, 169.96, 170.33, 170.70, 171.07, 171.43, 171.80, 172.17, 172.54, 172.91, 173.28, 173.65, 174.02, 174.38, 174.75, 175.12, 175.49, 175.86, 176.22, 176.59, 176.96, 177.33, 177.69, 178.06, 178.43, 178.79, 179.16}; -//float amostras[] = {630.00,630.00,630.00}; //,630.00,630.00,630.00,630.00,630.00,630.00,630.00,630.00,630.00,630.00,630.00,630.00,630.00,630.00,630.00,630.00,630.00}; - -float Vout; -float Rx; +#define DEBUG -/* -float amostra2;// -float diferenca; - -float tensaoPorAmostra; -float Vg; -float Vs; -float a; -float Rx; -*/ -// ++++++++++++++++++++++++ Library - DHT ++++++++++++++++++++++++ -// ++++++++++++++++++++++++ Library - LiquidCrystal_I2C ++++++++++++++++++++++++ -#include -#include -#include -#define LCD_I2C_ADDR 0x27 // <<----- Add your address here. Find it from I2C Scanner -#define LCD_X 16 -#define LCD_Y 2 -#define BACKLIGHT_PIN 3 -#define En_pin 2 -#define Rw_pin 1 -#define Rs_pin 0 -#define D4_pin 4 -#define D5_pin 5 -#define D6_pin 6 -#define D7_pin 7 -// ++++++++++++++++++++++++ Library - LiquidCrystal_I2C ++++++++++++++++++++++++ -// ++++++++++++++++++++++++ Heating Element Relay ++++++++++++++++++++++++ -#include -#define HEATING_ELEMENT 24 +// ######################### CONSTANTS ######################### + +// ######################### SETTINGS ######################### // ++++++++++++++++++++++++ Heating Element Relay ++++++++++++++++++++++++ +#define HEATING_ELEMENT_DEFAULT_WINDOW_SIZE 1000 +#define HEATING_ELEMENT_OUTPUT_PIN 24 +#define HEATING_ELEMENT_MAX_HEAT_PWM_INTEGER 5 +#define HEATING_ELEMENT_MAX_HEAT_PWM_FLOAT 5.0 +#define HEATING_ELEMENT_MAX_WATTAGE 3000.0 // Minimum = 2000.0 +#define HEATING_ELEMENT_AC_FREQUENCY_HZ 50.0 + // ++++++++++++++++++++++++ Temperature ++++++++++++++++++++++++ -#define TEMPERATURE_SENSOR_PIN 30 -#define TEMPERATURE_MAX_POSITION 120 -// ++++++++++++++++++++++++ Temperature ++++++++++++++++++++++++ -// ++++++++++++++++++++++++ Mixer ++++++++++++++++++++++++ -#define MIXER_PIN 12 -#define MIXER_MAX_POSITION 255 +#define PT100_BASE_INPUT_PIN A4 +#define PT100_BASE_OUTPUT_PIN 30 +#define PT100_BASE_TIME_BETWEEN_READINGS 100 +#define PT100_UP_INPUT_PIN A5 +#define PT100_UP_OUTPUT_PIN 31 +#define PT100_UP_TIME_BETWEEN_READINGS 100 +#define PT100_DOWN_INPUT_PIN A6 +#define PT100_DOWN_OUTPUT_PIN 32 +#define PT100_DOWN_TIME_BETWEEN_READINGS 100 + +#define PT100_BASE_DEFAULT_ADC_VMAX 1.081 +#define PT100_BASE_DEFAULT_VS 4.87 +#define PT100_BASE_DEFAULT_R1_RESISTENCE 606.0 +#define PT100_BASE_DEFAULT_LINE_RESISTENCE 0.7 +#define PT100_BASE_DEFAULT_OPERATION_RESISTENCE 0.0 +#define PT100_UP_DEFAULT_ADC_VMAX 1.081 +#define PT100_UP_DEFAULT_VS 4.87 +#define PT100_UP_DEFAULT_R1_RESISTENCE 606.0 +#define PT100_UP_DEFAULT_LINE_RESISTENCE 0.7 +#define PT100_UP_DEFAULT_OPERATION_RESISTENCE 0.0 +#define PT100_DOWN_DEFAULT_ADC_VMAX 1.081 +#define PT100_DOWN_DEFAULT_VS 4.87 +#define PT100_DOWN_DEFAULT_R1_RESISTENCE 606.0 +#define PT100_DOWN_DEFAULT_LINE_RESISTENCE 0.7 +#define PT100_DOWN_DEFAULT_OPERATION_RESISTENCE 0.0 + // ++++++++++++++++++++++++ Mixer ++++++++++++++++++++++++ +//#define MIXER_PIN 12 +//#define MIXER_MAX_POSITION 255 + +// ++++++++++++++++++++++++ Rotary Encoder ++++++++++++++++++++++++ +#define ROTARY_ENCODER_INTERRUPT_NUMBER 1 // On Mega2560 boards, interrupt 1 is on pin 3 +#define ROTARY_ENCODER_CLK_PIN 3 // Used for generating interrupts using CLK signal +#define ROTARY_ENCODER_DT_PIN 22 // Used for reading DT signal +#define ROTARY_ENCODER_SW_PIN 23 // Used for the push button switch +#define ROTARY_ENCODER_DEBOUNCE_TIME 10 // Number of miliseconds to ignore new signals a signal is received + // ++++++++++++++++++++++++ State Machine ++++++++++++++++++++++++ -#define SETTING_WELCOME_TIMEOUT 2000 -#define MENU_MAX_DEPTH 10 -#define MENU_INIT_VALUES -1,-1,-1,-1,-1,-1,-1,-1,-1,-1 -// ++++++++++++++++++++++++ State Machine ++++++++++++++++++++++++ -// ######################### DECLARE ######################### +#define SETTING_WELCOME_TIMEOUT 100 +#define SETTING_MAX_INACTIVITY_TIME 3000 +#define MENU_MAX_DEPTH 10 +#define MENU_INIT_VALUES -1,-1,-1,-1,-1,-1,-1,-1,-1,-1 +#define MENU_SIZE_MAIN_MENU 16 +#define SETTING_SERIAL_MONITOR_BAUD_RATE 9600 +#define SETTING_SERIAL_MONITOR_WELCOME_MESSAGE "Let's start Brewing!" +// ######################### LIBRARIES ######################### +// ++++++++++++++++++++++++ LiquidCrystal_I2C ++++++++++++++++++++++++ +#include +#include +#include -// ######################### INITIALIZE ######################### -// ++++++++++++++++++++++++ Library - DHT ++++++++++++++++++++++++ -//DHT dht(DHTPIN, DHTTYPE); -// ++++++++++++++++++++++++ Library - DHT ++++++++++++++++++++++++ -// ++++++++++++++++++++++++ Library - LiquidCrystal_I2C ++++++++++++++++++++++++ -int n = 1; -LiquidCrystal_I2C lcd(LCD_I2C_ADDR,En_pin,Rw_pin,Rs_pin,D4_pin,D5_pin,D6_pin,D7_pin); -// ++++++++++++++++++++++++ Library - LiquidCrystal_I2C ++++++++++++++++++++++++ +#define LCD_I2C_ADDR 0x27 // <<----- Add your address here. Find it from I2C Scanner +#define LCD_HORIZONTAL_RESOLUTION 16 +#define LCD_VERTICAL_RESOLUTION 2 +#define LCD_BACKLIGHT_PIN 3 +#define LCD_EN_PIN 2 +#define LCD_RW_PIN 1 +#define LCD_RS_PIN 0 +#define LCD_D4_PIN 4 +#define LCD_D5_PIN 5 +#define LCD_D6_PIN 6 +#define LCD_D7_PIN 7 + +// ++++++++++++++++++++++++ PT100 +++++++++++++++++++++++++++++++++ +#include + +// ######################### VARIABLES ######################### // ++++++++++++++++++++++++ Rotary Encoder ++++++++++++++++++++++++ -volatile int rotaryEncoderVirtualPosition = 0; +volatile int rotaryEncoderVirtualPosition; volatile int rotaryEncoderMaxPosition; -volatile int menuSize = 2; -const int PinCLK = 3; // Used for generating interrupts using CLK signal -const int PinDT = 22; // Used for reading DT signal -const int PinSW = 23; // Used for the push button switch -// ++++++++++++++++++++++++ Rotary Encoder ++++++++++++++++++++++++ +volatile int rotaryEncoderMinPosition; +volatile int rotaryEncoderSingleStep; +volatile int rotaryEncoderMultiStep; + // ++++++++++++++++++++++++ Heating Element Relay ++++++++++++++++++++++++ -//Define Variables we'll be connecting to -double Setpoint, Input, Output; - -//Specify the links and initial tuning parameters -float Kp = 200; -float Ki = 50; -float Kd = 0; -//PID myPID(&Input, &Output, &Setpoint,Kp,Ki,Kd, DIRECT); -//PID myPID(&Input, &Output, &Setpoint,1000,50,0, DIRECT); -PID myPID(&Input, &Output, &Setpoint,200,50,0, DIRECT); - -int WindowSize = 1000; +int WindowSize; // Time frame to operate in unsigned long windowStartTime; -// ++++++++++++++++++++++++ Heating Element Relay ++++++++++++++++++++++++ -// ++++++++++++++++++++++++ Mixer ++++++++++++++++++++++++ -//const int mixerSpeed = 130; -// ++++++++++++++++++++++++ Mixer ++++++++++++++++++++++++ -// ++++++++++++++++++++++++ Error ++++++++++++++++++++++++ -enum sys_error { - no_error, - catastrofic_failure_sensor_temperature, - catastrofic_failure_program, - catastrofic_failure_logic_auto_manual -}; -sys_error error = no_error; -// ++++++++++++++++++++++++ Error ++++++++++++++++++++++++ -// ++++++++++++++++++++++++ State Machine ++++++++++++++++++++++++ +unsigned long dWattPerPulse; +// ++++++++++++++++++++++++ State Machine ++++++++++++++++++++++++ // global -enum state_machine { - state_welcome, - state_menu, - state_manual_time, - state_manual_temperature, - state_manual_mode, - state_manual_mixer, - state_error +enum TRotaryEncoderMode { + eRotaryEncoderMode_Menu, + eRotaryEncoderMode_Time, + eRotaryEncoderMode_Generic, + eRotaryEncoderMode_Disabled }; -state_machine state = state_welcome; +TRotaryEncoderMode rotaryEncoderMode; // menu -enum main_menu_list { - main_manual, - main_auto +enum eMainMenuOptions { + eMainMenu_GO, + eMainMenu_Presets, + eMainMenu_Malt, + eMainMenu_Startpoint, + eMainMenu_BetaGlucanase, + eMainMenu_Debranching, + eMainMenu_Proteolytic, + eMainMenu_BetaAmylase, + eMainMenu_AlphaAmylase, + eMainMenu_Mashout, + eMainMenu_Recirculation, + eMainMenu_Sparge, + eMainMenu_Boil, + eMainMenu_Hops, + eMainMenu_Cooling, + eMainMenu_Settings +}; +eMainMenuOptions mainMenuOption; + +enum ePresetsMenuOptions { + ePresetsMenu_Trigo, + ePresetsMenu_IPA, + ePresetsMenu_Belga, + ePresetsMenu_Red, + ePresetsMenu_APA, + ePresetsMenu_Back, }; -enum manual_menu_list { - manual_temperature, - manual_time, - manual_mode, - manual_mixer, - manual_start, - manual_back +ePresetsMenuOptions presetsMenuOption; + +enum eMaltMenuOptions { + eMaltMenu_CastleMalting_Chteau_Pilsen_2RS, + eMaltMenu_CastleMalting_Wheat_Blanc, + eMaltMenu_Back, }; -enum auto_menu_list { - auto_recipe, - auto_start, - auto_back +eMaltMenuOptions maltMenuOption; + +enum eSettingsMenuOptions { + eSettingsMenu_PT100_Element, + eSettingsMenu_PT100_Up, + eSettingsMenu_PT100_Down, + eSettingsMenu_Back, }; -int menu_position[MENU_MAX_DEPTH]= {MENU_INIT_VALUES}; +eSettingsMenuOptions settingsMenuOption; // cooking -enum cook_mode_list { - quick_start, - start_at_temperature +enum eCookingStages { + eCookingStage_Startpoint, + eCookingStage_BetaGlucanase, + eCookingStage_Debranching, + eCookingStage_Proteolytic, + eCookingStage_BetaAmylase, + eCookingStage_AlphaAmylase, + eCookingStage_Mashout, + eCookingStage_Recirculation, + eCookingStage_Sparge, + eCookingStage_Boil, + eCookingStage_Cooling, + eCookingStage_Done }; -int cookTime = 3600; -int cookTemperature = 36; -cook_mode_list cookMode = quick_start; -int cookMixerSpeed = 180; //0; //130; -// ++++++++++++++++++++++++ State Machine ++++++++++++++++++++++++ -// ++++++++++++++++++++++++ Global Variables ++++++++++++++++++++++++ -//float currentTemperatureCelsius; -//float targetTemperatureCelsius = -1; +eCookingStages cookingStage; // ++++++++++++++++++++++++ Global Variables ++++++++++++++++++++++++ +boolean cooking; + +int clockStartTime; +int clockCounter; +int clockIgnore; +boolean clockStart; +boolean clockEnd; + +int cookTime; +int cookTemperature; +//cook_mode_list cookMode; +//int cookMixerSpeed; +int cookHeatPWM; + +int startpointTime; +int betaGlucanaseTime; +int debranchingTime; +int proteolyticTime; +int betaAmylaseTime; +int alphaAmylaseTime; +int mashoutTime; +int recirculationTime; +int spargeTime; +int boilTime; +int coolingTime; + +int startpointTemperature; +int betaGlucanaseTemperature; +int debranchingTemperature; +int proteolyticTemperature; +int betaAmylaseTemperature; +int alphaAmylaseTemperature; +int mashoutTemperature; +int recirculationTemperature; +int spargeTemperature; +int boilTemperature; +int coolingTemperature; + +//int menuSize; +int menu_position[MENU_MAX_DEPTH] = {MENU_INIT_VALUES}; + +boolean refresh; +boolean repaint; + +// ++++++++++++++++++++++++ Interrupts ++++++++++++++++++++++++ +static unsigned long lastInterruptTime; + // ######################### INITIALIZE ######################### +// ++++++++++++++++++++++++ Library - LiquidCrystal_I2C ++++++++++++++++++++++++ +LiquidCrystal_I2C lcd(LCD_I2C_ADDR, LCD_EN_PIN, LCD_RW_PIN, LCD_RS_PIN, LCD_D4_PIN, LCD_D5_PIN, LCD_D6_PIN, LCD_D7_PIN); + +// +++++++++++++++++++++++ PT100 +++++++++++++++++++++++ +PT100 basePT100(PT100_BASE_OUTPUT_PIN, PT100_BASE_INPUT_PIN, PT100_BASE_TIME_BETWEEN_READINGS, PT100_BASE_DEFAULT_ADC_VMAX, PT100_BASE_DEFAULT_VS, PT100_BASE_DEFAULT_R1_RESISTENCE, PT100_BASE_DEFAULT_LINE_RESISTENCE, PT100_BASE_DEFAULT_OPERATION_RESISTENCE); +PT100 upPT100(PT100_UP_OUTPUT_PIN, PT100_UP_INPUT_PIN, PT100_UP_TIME_BETWEEN_READINGS, PT100_UP_DEFAULT_ADC_VMAX, PT100_UP_DEFAULT_VS, PT100_UP_DEFAULT_R1_RESISTENCE, PT100_UP_DEFAULT_LINE_RESISTENCE, PT100_UP_DEFAULT_OPERATION_RESISTENCE); +PT100 downPT100(PT100_DOWN_OUTPUT_PIN, PT100_DOWN_INPUT_PIN, PT100_DOWN_TIME_BETWEEN_READINGS, PT100_DOWN_DEFAULT_ADC_VMAX, PT100_DOWN_DEFAULT_VS, PT100_DOWN_DEFAULT_R1_RESISTENCE, PT100_DOWN_DEFAULT_LINE_RESISTENCE, PT100_DOWN_DEFAULT_OPERATION_RESISTENCE); // ######################### INTERRUPTS ######################### -static unsigned long lastInterruptTime = 0; -void isr () { // Interrupt service routine is executed when a HIGH to LOW transition is detected on CLK +void xSetupRotaryEncoder( TRotaryEncoderMode newMode, int newPosition, int newMaxPosition, int newMinPosition, int newSingleStep, int newMultiStep ) { + if( newMode >= 0 ) rotaryEncoderMode = newMode; + if( newPosition >= 0 ) rotaryEncoderVirtualPosition = newPosition; + if( newMaxPosition >= 0 ) rotaryEncoderMaxPosition = newMaxPosition; + if( newMinPosition >= 0 ) rotaryEncoderMinPosition = newMinPosition; + if( newSingleStep >= 0 ) rotaryEncoderSingleStep = newSingleStep; + if( newMultiStep >= 0 ) rotaryEncoderMultiStep = newMultiStep; +} + +void isr () { // Interrupt service routine is executed when a HIGH to LOW transition is detected on CLK + repaint = true; + refresh = true; + unsigned long interruptTime = millis(); - unsigned long interruptTime = millis(); + // If interrupts come faster than [ROTARY_ENCODER_DEBOUNCE_TIME]ms, assume it's a bounce and ignore + if ((interruptTime - lastInterruptTime) > ROTARY_ENCODER_DEBOUNCE_TIME) { + switch(rotaryEncoderMode) { - // If interrupts come faster than 5ms, assume it's a bounce and ignore - if ((interruptTime - lastInterruptTime) > 5) { - switch(state) { - - // Input of rotay encoder controling menus - case state_manual_mode: - case state_menu: { - if (!digitalRead(PinDT)) { - rotaryEncoderVirtualPosition = (rotaryEncoderVirtualPosition + 1); + // Input of rotary encoder controling menus + case eRotaryEncoderMode_Menu: { + if (!digitalRead(ROTARY_ENCODER_DT_PIN)) { + rotaryEncoderVirtualPosition = (rotaryEncoderVirtualPosition + rotaryEncoderSingleStep); } else { - rotaryEncoderVirtualPosition = rotaryEncoderVirtualPosition - 1; + rotaryEncoderVirtualPosition = rotaryEncoderVirtualPosition - rotaryEncoderSingleStep; } - if (rotaryEncoderVirtualPosition >= menuSize) { - rotaryEncoderVirtualPosition = 0; + if (rotaryEncoderVirtualPosition > rotaryEncoderMaxPosition) { + rotaryEncoderVirtualPosition = rotaryEncoderMinPosition; } - if (rotaryEncoderVirtualPosition < 0) { - rotaryEncoderVirtualPosition = menuSize -1; + if (rotaryEncoderVirtualPosition < rotaryEncoderMinPosition) { + rotaryEncoderVirtualPosition = rotaryEncoderMaxPosition; } break; } - // Input of rotay encoder controling time variables - case state_manual_time: { - if (!digitalRead(PinDT)) { + // Input of rotary encoder controling time variables + case eRotaryEncoderMode_Time: { + xDecodeRotaryEncoder(); + + if (!digitalRead(ROTARY_ENCODER_DT_PIN)) { if(rotaryEncoderVirtualPosition >= 60) { - rotaryEncoderVirtualPosition = (rotaryEncoderVirtualPosition + 30); + rotaryEncoderVirtualPosition = (rotaryEncoderVirtualPosition + rotaryEncoderMultiStep); } else { - rotaryEncoderVirtualPosition = (rotaryEncoderVirtualPosition + 1); + rotaryEncoderVirtualPosition = (rotaryEncoderVirtualPosition + rotaryEncoderSingleStep); } } else { - if(rotaryEncoderVirtualPosition == 0) { + if(rotaryEncoderVirtualPosition == rotaryEncoderMinPosition) { rotaryEncoderVirtualPosition = (rotaryEncoderVirtualPosition + 60); } else { - if(rotaryEncoderVirtualPosition >= 90) { - rotaryEncoderVirtualPosition = (rotaryEncoderVirtualPosition - 30); + if(rotaryEncoderVirtualPosition >= (60 + rotaryEncoderMultiStep)) { + rotaryEncoderVirtualPosition = (rotaryEncoderVirtualPosition - rotaryEncoderMultiStep); } else { - rotaryEncoderVirtualPosition = rotaryEncoderVirtualPosition - 1; + rotaryEncoderVirtualPosition = rotaryEncoderVirtualPosition - rotaryEncoderSingleStep; } } } - if (rotaryEncoderVirtualPosition > 7200) { - rotaryEncoderVirtualPosition = 7200; + if (rotaryEncoderVirtualPosition > rotaryEncoderMaxPosition) { + rotaryEncoderVirtualPosition = rotaryEncoderMaxPosition; } - if (rotaryEncoderVirtualPosition < 0) { - rotaryEncoderVirtualPosition = 0; + if (rotaryEncoderVirtualPosition < rotaryEncoderMinPosition) { + rotaryEncoderVirtualPosition = rotaryEncoderMinPosition; } break; } - // Input of rotay encoder controling integer variables within a range between 0 and rotaryEncoderMaxPosition - case state_manual_mixer: - case state_manual_temperature: { - if (!digitalRead(PinDT)) { - if ((interruptTime - lastInterruptTime) < 10) { - rotaryEncoderVirtualPosition = (rotaryEncoderVirtualPosition + 5); + // Input of rotary encoder controling generic integer variables within a range between rotaryEncoderMinPosition and rotaryEncoderMaxPosition + case eRotaryEncoderMode_Generic: { + if (!digitalRead(ROTARY_ENCODER_DT_PIN)) { + if ((interruptTime - lastInterruptTime) < ROTARY_ENCODER_DEBOUNCE_TIME) { + rotaryEncoderVirtualPosition = (rotaryEncoderVirtualPosition + rotaryEncoderMultiStep); } else { - rotaryEncoderVirtualPosition = (rotaryEncoderVirtualPosition + 1); + rotaryEncoderVirtualPosition = (rotaryEncoderVirtualPosition + rotaryEncoderSingleStep); } } else { - if ((interruptTime - lastInterruptTime) < 10) { - rotaryEncoderVirtualPosition = (rotaryEncoderVirtualPosition - 5); + if ((interruptTime - lastInterruptTime) < ROTARY_ENCODER_DEBOUNCE_TIME) { + rotaryEncoderVirtualPosition = (rotaryEncoderVirtualPosition - rotaryEncoderMultiStep); } else { - rotaryEncoderVirtualPosition = (rotaryEncoderVirtualPosition - 1); + rotaryEncoderVirtualPosition = (rotaryEncoderVirtualPosition - rotaryEncoderSingleStep); } } if (rotaryEncoderVirtualPosition > rotaryEncoderMaxPosition) { rotaryEncoderVirtualPosition = rotaryEncoderMaxPosition; } - if (rotaryEncoderVirtualPosition < 0) { - rotaryEncoderVirtualPosition = 0; + if (rotaryEncoderVirtualPosition < rotaryEncoderMinPosition) { + rotaryEncoderVirtualPosition = rotaryEncoderMinPosition; } break; @@ -259,372 +328,854 @@ void isr () { // Interrupt service routine is executed when lastInterruptTime = interruptTime; } -// ######################### INTERRUPTS ######################### // ######################### START ######################### +void xSafeHardwarePowerOff() { +// analogWrite(MIXER_PIN, 0); // Turn mixer OFF for safety + digitalWrite(HEATING_ELEMENT_OUTPUT_PIN, LOW); // Turn heading element OFF for safety + //basePT100.xSafeHardwarePowerOff(); // Turn temperature sensor OFF for safety +} + +void displayWelcome() { + lcdPrint(" Let's start", " Brewing!"); // Write welcome + delay(SETTING_WELCOME_TIMEOUT); // pause for effect +} + void setup() { -// ++++++++++++++++++++++++ Library - DHT ++++++++++++++++++++++++ - //dht.begin(); -// ++++++++++++++++++++++++ Library - DHT ++++++++++++++++++++++++ -// ++++++++++++++++++++++++ Library - LiquidCrystal_I2C ++++++++++++++++++++++++ - lcd.begin (LCD_X,LCD_Y); // <<----- My LCD was 16x2 - // Switch on the backlight - lcd.setBacklightPin(BACKLIGHT_PIN,POSITIVE); - lcd.setBacklight(HIGH); -// ++++++++++++++++++++++++ Library - LiquidCrystal_I2C ++++++++++++++++++++++++ -// ++++++++++++++++++++++++ Rotary Encoder ++++++++++++++++++++++++ - pinMode(PinCLK,INPUT); - pinMode(PinDT, INPUT); - pinMode(PinSW, INPUT); - attachInterrupt(1, isr, FALLING); // interrupt 0 is always connected to pin 2 on Arduino UNO -// ++++++++++++++++++++++++ Rotary Encoder ++++++++++++++++++++++++ -// ++++++++++++++++++++++++ Heating Element Relay ++++++++++++++++++++++++ - pinMode(HEATING_ELEMENT, OUTPUT); - digitalWrite(HEATING_ELEMENT,LOW); - - windowStartTime = millis(); + // ++++++++++++++++++++++++ Rotary Encoder ++++++++++++++++++++++++ + pinMode (ROTARY_ENCODER_CLK_PIN,INPUT); + pinMode (ROTARY_ENCODER_DT_PIN, INPUT); + pinMode (ROTARY_ENCODER_SW_PIN, INPUT); + attachInterrupt (ROTARY_ENCODER_INTERRUPT_NUMBER, isr, FALLING); - //initialize the variables we're linked to - Setpoint = 100; + // ++++++++++++++++++++++++ Heating Element Relay ++++++++++++++++++++++++ + pinMode (HEATING_ELEMENT_OUTPUT_PIN, OUTPUT); + digitalWrite (HEATING_ELEMENT_OUTPUT_PIN, LOW); + windowStartTime = millis(); + dWattPerPulse = HEATING_ELEMENT_MAX_WATTAGE / HEATING_ELEMENT_AC_FREQUENCY_HZ; - //tell the PID to range between 0 and the full window size - myPID.SetOutputLimits(0, WindowSize); + myPID.SetOutputLimits (0, WindowSize); // tell the PID to range between 0 and the full window size + myPID.SetMode (AUTOMATIC); // turn the PID on - //turn the PID on - myPID.SetMode(AUTOMATIC); -// ++++++++++++++++++++++++ Heating Element Relay ++++++++++++++++++++++++ -// ++++++++++++++++++++++++ Mixer ++++++++++++++++++++++++ - pinMode(MIXER_PIN, OUTPUT); - analogWrite(MIXER_PIN, 0); -// ++++++++++++++++++++++++ Mixer ++++++++++++++++++++++++ -// ++++++++++++++++++++++++ Temperature Sensor PT100 ++++++++++++++++++++++++ -// analogReference(EXTERNAL); - analogReference(INTERNAL1V1); -// analogReference(INTERNAL2V56); - - pinMode(TEMPERATURE_SENSOR_PIN, OUTPUT); - digitalWrite(TEMPERATURE_SENSOR_PIN, LOW); -// ++++++++++++++++++++++++ Temperature Sensor PT100 ++++++++++++++++++++++++ - Serial.begin(9600); - Serial.println("Let's start Brewing!"); + // ++++++++++++++++++++++++ Mixer ++++++++++++++++++++++++ + // pinMode (MIXER_PIN, OUTPUT); + // analogWrite (MIXER_PIN, 0); + + // ++++++++++++++++++++++++ Temperature Sensor PT100 ++++++++++++++++++++++++ + //basePT100.setup(); +/* + analogReference (INTERNAL1V1); // EXTERNAL && INTERNAL2V56 && INTERNAL1V1 + pinMode (PT100_OUTPUT_PIN, OUTPUT); // setup temperature sensor input pin + digitalWrite (PT100_OUTPUT_PIN, LOW); // initialize sensor off +*/ + // ++++++++++++++++++++++++ Serial Monitor ++++++++++++++++++++++++ + Serial.begin(SETTING_SERIAL_MONITOR_BAUD_RATE); // setup terminal baud rate + Serial.println(SETTING_SERIAL_MONITOR_WELCOME_MESSAGE); // print a start message to the terminal + + // ++++++++++++++++++++++++ Library - LiquidCrystal_I2C ++++++++++++++++++++++++ + lcd.begin (LCD_HORIZONTAL_RESOLUTION,LCD_VERTICAL_RESOLUTION); // <<----- My LCD was 16x2 + lcd.setBacklightPin(LCD_BACKLIGHT_PIN,POSITIVE); // Setup backlight pin + lcd.setBacklight(HIGH); // Switch on the backlight + + // ######################### INITIALIZE ######################### + // ++++++++++++++++++++++++ Rotary Encoder ++++++++++++++++++++++++ + // set operation state | INPUT : TRotaryEncoderMode newMode, int newPosition, int newMaxPosition, int newMinPosition, int newSingleStep, int newMultiStep + xSetupRotaryEncoder( eRotaryEncoderMode_Disabled, 0, 0, 0, 0, 0 ); + + // ++++++++++++++++++++++++ State Machine ++++++++++++++++++++++++ + presetsMenuOption = ePresetsMenu_Trigo; + maltMenuOption = eMaltMenu_CastleMalting_Chteau_Pilsen_2RS; + settingsMenuOption = eSettingsMenu_PT100_Element; + cookingStage = eCookingStage_Startpoint; + // ++++++++++++++++++++++++ Global Variables ++++++++++++++++++++++++ + cooking = false; + + clockStartTime = 0; + clockCounter = 0; + clockIgnore = 0; + clockStart = false; + clockEnd = false; + + cookTime = 3600; + cookTemperature = 25; + //cookMode = quick_start; + //cookMixerSpeed = 120; + cookHeatPWM = 5; + + startpointTime = 120; + betaGlucanaseTime = 0; + debranchingTime = 0; + proteolyticTime = 0; + betaAmylaseTime = 3600; + alphaAmylaseTime = 1800; + mashoutTime = 300; + recirculationTime = 1200; + spargeTime = 1200; + boilTime = 5400; + coolingTime = 120; + + startpointTemperature = 45; + betaGlucanaseTemperature = 40; + debranchingTemperature = 40; + proteolyticTemperature = 50; + betaAmylaseTemperature = 60; + alphaAmylaseTemperature = 70; + mashoutTemperature = 80; + recirculationTemperature = 80; + spargeTemperature = 80; + boilTemperature = 100; + coolingTemperature = 25; + + refresh = true; + repaint = true; + + // ++++++++++++++++++++++++ Interrupts ++++++++++++++++++++++++ + lastInterruptTime = 0; + + // ++++++++++++++++++++++++ PID ++++++++++++++++++++++++ + WindowSize = HEATING_ELEMENT_DEFAULT_WINDOW_SIZE; // Time frame to operate in + +// ######################### Code - Run Once ######################### + xSafeHardwarePowerOff(); + displayWelcome(); + + xSetupRotaryEncoder( eRotaryEncoderMode_Menu, eMainMenu_GO, MENU_SIZE_MAIN_MENU - 1, 0, 1, 1 ); } + // ######################### START ######################### void loop() { - switch(state) { - case state_welcome: { - runWelcome(); + unsigned long inactivityTime = millis() - lastInterruptTime; + + if(inactivityTime > SETTING_MAX_INACTIVITY_TIME) { // Inactivity check + if(refresh) { + repaint = true; + refresh = false; + } + displayStatus(); + } + else { + displayMainMenu(); + } + + operateMachine(); +} + +void xPaintStatusTemplate() { + // Clear LCD + lcd.clear(); + + // Position the cursor at the begining of where the temperature template goes onto the screen + lcd.home(); + + // Print the target and measured temperature template + if(cooking) { + lcd.print("ON : 000*C/000*C"); + } + else { + lcd.print("OFF: 000*C/000*C"); + } + + // Position the cursor at the begining of where the mode and time template goes onto the screen + lcd.setCursor (0,LCD_VERTICAL_RESOLUTION-1); + + lcd.print("**** 00:00"); +} + +void displayStatus() { + + // Check whether a template repaint is required + if(repaint) { + // Repaint the LCD template + xPaintStatusTemplate(); + + // Reset the repaint flag after the repaint has been done + repaint = false; + } + + // Print positions with no numbers, before the measured temperature value + lcd.setCursor (3,0); + if (basePT100.getCurrentTemperature() < 10) { + lcd.print(" "); + } + else { + if (basePT100.getCurrentTemperature() < 100) { + lcd.print(" "); + } + } + + // Print measured temperature value onto the LCD + lcd.print(basePT100.getCurrentTemperature(), 1); + + // Print positions with no numbers, before the target temperature value + lcd.setCursor (11,0); + if (cookTemperature < 10) { + lcd.print(" "); + } + else { + if (cookTemperature < 100) { + lcd.print(" "); + } + } + + // Print target temperature value onto the LCD + lcd.print(cookTemperature); + + // Calculate the numbers on the timer clock + int minutes = (clockCounter - clockIgnore) / 60; + int seconds = (clockCounter - clockIgnore) - minutes * 60; + + // Position the cursor at the begining of where the timer goes onto the screen + lcd.setCursor (10, 1); + + // Print the timer values onto the LCD + if (minutes < 10) { + lcd.print(" 0"); + } + else { + if (minutes < 100) { + lcd.print(" "); + } + } + lcd.print(minutes); + lcd.print(":"); + if(seconds<10) { + lcd.print("0"); + } + lcd.print(seconds); +} + +void displayMainMenu() { + switch(menu_position[0]) { + case eMainMenu_GO: { + MainMenu_GO(); + + menu_position[0] = -1; + + // reset operation state | INPUT : TRotaryEncoderMode newMode, int newPosition, int newMaxPosition, int newMinPosition, int newSingleStep, int newMultiStep + xSetupRotaryEncoder( eRotaryEncoderMode_Menu, eMainMenu_GO, MENU_SIZE_MAIN_MENU - 1, 0, 1, 1 ); break; } - case state_menu: { - runMenu(); + case eMainMenu_Presets: { + MainMenu_Presets(); + + menu_position[0] = -1; + + // reset operation state | INPUT : TRotaryEncoderMode newMode, int newPosition, int newMaxPosition, int newMinPosition, int newSingleStep, int newMultiStep + xSetupRotaryEncoder( eRotaryEncoderMode_Menu, eMainMenu_Presets, MENU_SIZE_MAIN_MENU - 1, 0, 1, 1 ); break; } - /*case state_manual_time: { - //runManualTime(); + case eMainMenu_Malt: { + MainMenu_Malt(); + + menu_position[0] = -1; + + // reset operation state | INPUT : TRotaryEncoderMode newMode, int newPosition, int newMaxPosition, int newMinPosition, int newSingleStep, int newMultiStep + xSetupRotaryEncoder( eRotaryEncoderMode_Menu, eMainMenu_Malt, MENU_SIZE_MAIN_MENU - 1, 0, 1, 1 ); break; } - case state_manual_temperature: { - //runManualTemp(); + case eMainMenu_Startpoint: { + MainMenu_Startpoint(); + + menu_position[0] = -1; + + // reset operation state | INPUT : TRotaryEncoderMode newMode, int newPosition, int newMaxPosition, int newMinPosition, int newSingleStep, int newMultiStep + xSetupRotaryEncoder( eRotaryEncoderMode_Menu, eMainMenu_Startpoint, MENU_SIZE_MAIN_MENU - 1, 0, 1, 1 ); break; } - case state_manual_mixer: { - //runManualTemp(); + case eMainMenu_BetaGlucanase: { + MainMenu_BetaGlucanase(); + + menu_position[0] = -1; + + // reset operation state | INPUT : TRotaryEncoderMode newMode, int newPosition, int newMaxPosition, int newMinPosition, int newSingleStep, int newMultiStep + xSetupRotaryEncoder( eRotaryEncoderMode_Menu, eMainMenu_BetaGlucanase, MENU_SIZE_MAIN_MENU - 1, 0, 1, 1 ); break; - }*/ - case state_error: { - runError(); + } + case eMainMenu_Debranching: { + MainMenu_Debranching(); + + menu_position[0] = -1; + + // reset operation state | INPUT : TRotaryEncoderMode newMode, int newPosition, int newMaxPosition, int newMinPosition, int newSingleStep, int newMultiStep + xSetupRotaryEncoder( eRotaryEncoderMode_Menu, eMainMenu_Settings, MENU_SIZE_MAIN_MENU - 1, 0, 1, 1 ); break; } - default: { - lcdPrint("Error", "The brewer has stoped working properly. Please shutdown NOW for your safety!"); - state = state_error; - error = catastrofic_failure_program; + case eMainMenu_Proteolytic: { + MainMenu_Proteolytic(); + + menu_position[0] = -1; + + // reset operation state | INPUT : TRotaryEncoderMode newMode, int newPosition, int newMaxPosition, int newMinPosition, int newSingleStep, int newMultiStep + xSetupRotaryEncoder( eRotaryEncoderMode_Menu, eMainMenu_Proteolytic, MENU_SIZE_MAIN_MENU - 1, 0, 1, 1 ); + + break; } - } -} - -void runWelcome() { - // Write welcome - lcd.clear(); - lcd.home (); // go home - lcd.print(" Let's start"); - lcd.setCursor (0,1); // go to start of 2nd line - lcd.print(" Brewing!"); - - delay(SETTING_WELCOME_TIMEOUT); - - state = state_menu; -} - -void runMenu() { - digitalWrite(HEATING_ELEMENT,LOW); - - switch(menu_position[0]) { - case main_manual: { - switch(menu_position[1]) { - case manual_temperature: { - // do work - cookTemperature = getTemperature(cookTemperature); - - menu_position[1] = -1; - rotaryEncoderVirtualPosition = manual_temperature; - - break; - } - case manual_time: { - // do work - cookTime = getTimer(cookTime); - - menu_position[1] = -1; - rotaryEncoderVirtualPosition = manual_time; - - break; - } - case manual_mode: { - // do work - int returnMode = getMode(); - switch(returnMode) { - case quick_start: { - cookMode = quick_start; - break; - } - case start_at_temperature: { - cookMode = start_at_temperature; - - break; - } - default: { - cookMode = quick_start; - } - } - - menu_position[1] = -1; - rotaryEncoderVirtualPosition = manual_mode; - - break; - } - case manual_mixer: { - // do work - cookMixerSpeed = getMixerSpeed(cookMixerSpeed); - - menu_position[1] = -1; - rotaryEncoderVirtualPosition = manual_time; - - break; - } - case manual_start: { - // do work - runStart(); - - menu_position[1] = -1; - rotaryEncoderVirtualPosition = manual_start; - - break; - } - case manual_back: { - menu_position[0] = -1; - menu_position[1] = -1; - - rotaryEncoderVirtualPosition = manual_back; - - break; - } - default: { - // reset menu variables - menuSize = 6; - - // display menu - lcd.clear(); - lcd.home (); // go home - lcd.print("Manual Menu"); - - while(true) { - switch(rotaryEncoderVirtualPosition) { - case manual_temperature: { - lcd.setCursor (0,1); // go to start of 2nd line - lcd.print("-> Temperature "); - delay(100); - break; - } - case manual_time: { - lcd.setCursor (0,1); // go to start of 2nd line - lcd.print("-> Time "); - delay(100); - break; - } - case manual_mode: { - lcd.setCursor (0,1); // go to start of 2nd line - lcd.print("-> Mode "); - delay(100); - break; - } - case manual_mixer: { - lcd.setCursor (0,1); // go to start of 2nd line - lcd.print("-> Mixer Speed "); - delay(100); - break; - } - case manual_start: { - lcd.setCursor (0,1); // go to start of 2nd line - lcd.print("-> Start "); - delay(100); - break; - } - case manual_back: { - lcd.setCursor (0,1); // go to start of 2nd line - lcd.print("-> Back "); - delay(100); - break; - } - default: { - //lcd.setCursor (0,1); // go to start of 2nd line - //lcd.print("*** Error ***"); - rotaryEncoderVirtualPosition = 0; - } - } - - if (!(digitalRead(PinSW))) { // check if pushbutton is pressed - menu_position[1] = rotaryEncoderVirtualPosition; - while (!digitalRead(PinSW)) {} // wait til switch is released - delay(10); // debounce - break; - } - } - } - } + case eMainMenu_BetaAmylase: { + MainMenu_BetaAmylase(); + + menu_position[0] = -1; + + // reset operation state | INPUT : TRotaryEncoderMode newMode, int newPosition, int newMaxPosition, int newMinPosition, int newSingleStep, int newMultiStep + xSetupRotaryEncoder( eRotaryEncoderMode_Menu, eMainMenu_BetaAmylase, MENU_SIZE_MAIN_MENU - 1, 0, 1, 1 ); + break; } - case main_auto: { - switch(menu_position[1]) { - case auto_recipe: { - // do work - - menu_position[1] = -1; - rotaryEncoderVirtualPosition = auto_recipe; - - break; - } - case auto_start: { - // do work - - menu_position[1] = -1; - rotaryEncoderVirtualPosition = auto_start; - - break; - } - case auto_back: { - // reset choces - menu_position[0] = -1; - menu_position[1] = -1; - - // set menu position - rotaryEncoderVirtualPosition = main_auto; - - break; - } - default: { - // reset menu variables - //rotaryEncoderVirtualPosition = 0; - menuSize = 3; - - // display menu - lcd.clear(); - lcd.home (); // go home - lcd.print("Automatic Menu"); - - while(true) { - switch(rotaryEncoderVirtualPosition) { - case auto_recipe: { - lcd.setCursor (0,1); // go to start of 2nd line - lcd.print("-> Recipe "); - delay(100); - break; - } - case auto_start: { - lcd.setCursor (0,1); // go to start of 2nd line - lcd.print("-> Start "); - delay(100); - break; - } - case auto_back: { - lcd.setCursor (0,1); // go to start of 2nd line - lcd.print("-> Back "); - delay(100); - break; - } - default: { - //lcd.setCursor (0,1); // go to start of 2nd line - //lcd.print("*** Error ***"); - rotaryEncoderVirtualPosition = 0; - } - } - - if (!(digitalRead(PinSW))) { // check if pushbutton is pressed - menu_position[1] = rotaryEncoderVirtualPosition; - while (!digitalRead(PinSW)) {} // wait til switch is released - delay(10); // debounce - break; - } - } - } - } + case eMainMenu_AlphaAmylase: { + MainMenu_AlphaAmylase(); + + menu_position[0] = -1; + + // reset operation state | INPUT : TRotaryEncoderMode newMode, int newPosition, int newMaxPosition, int newMinPosition, int newSingleStep, int newMultiStep + xSetupRotaryEncoder( eRotaryEncoderMode_Menu, eMainMenu_AlphaAmylase, MENU_SIZE_MAIN_MENU - 1, 0, 1, 1 ); + break; } - default: { - // reset menu variables - //rotaryEncoderVirtualPosition = 0; - menuSize = 2; + case eMainMenu_Mashout: { + MainMenu_Mashout(); + + menu_position[0] = -1; + + // reset operation state | INPUT : TRotaryEncoderMode newMode, int newPosition, int newMaxPosition, int newMinPosition, int newSingleStep, int newMultiStep + xSetupRotaryEncoder( eRotaryEncoderMode_Menu, eMainMenu_Mashout, MENU_SIZE_MAIN_MENU - 1, 0, 1, 1 ); + + break; + } + case eMainMenu_Recirculation: { + MainMenu_Recirculation(); + + menu_position[0] = -1; + + // reset operation state | INPUT : TRotaryEncoderMode newMode, int newPosition, int newMaxPosition, int newMinPosition, int newSingleStep, int newMultiStep + xSetupRotaryEncoder( eRotaryEncoderMode_Menu, eMainMenu_Recirculation, MENU_SIZE_MAIN_MENU - 1, 0, 1, 1 ); - // display menu - lcd.clear(); - lcd.home (); // go home - lcd.print("Main Menu"); + break; + } + case eMainMenu_Sparge: { + MainMenu_Sparge(); - while(true) { + menu_position[0] = -1; + + // reset operation state | INPUT : TRotaryEncoderMode newMode, int newPosition, int newMaxPosition, int newMinPosition, int newSingleStep, int newMultiStep + xSetupRotaryEncoder( eRotaryEncoderMode_Menu, eMainMenu_Sparge, MENU_SIZE_MAIN_MENU - 1, 0, 1, 1 ); + + break; + } + case eMainMenu_Boil: { + MainMenu_Boil(); + + menu_position[0] = -1; + + // reset operation state | INPUT : TRotaryEncoderMode newMode, int newPosition, int newMaxPosition, int newMinPosition, int newSingleStep, int newMultiStep + xSetupRotaryEncoder( eRotaryEncoderMode_Menu, eMainMenu_Boil, MENU_SIZE_MAIN_MENU - 1, 0, 1, 1 ); + + break; + } + case eMainMenu_Hops: { + MainMenu_Hops(); + + menu_position[0] = -1; + + // reset operation state | INPUT : TRotaryEncoderMode newMode, int newPosition, int newMaxPosition, int newMinPosition, int newSingleStep, int newMultiStep + xSetupRotaryEncoder( eRotaryEncoderMode_Menu, eMainMenu_Hops, MENU_SIZE_MAIN_MENU - 1, 0, 1, 1 ); + + break; + } + case eMainMenu_Cooling: { + MainMenu_Cooling(); + + menu_position[0] = -1; + + // reset operation state | INPUT : TRotaryEncoderMode newMode, int newPosition, int newMaxPosition, int newMinPosition, int newSingleStep, int newMultiStep + xSetupRotaryEncoder( eRotaryEncoderMode_Menu, eMainMenu_Cooling, MENU_SIZE_MAIN_MENU - 1, 0, 1, 1 ); + + break; + } + case eMainMenu_Settings: { + MainMenu_Settings(); + + menu_position[0] = -1; + + // reset operation state | INPUT : TRotaryEncoderMode newMode, int newPosition, int newMaxPosition, int newMinPosition, int newSingleStep, int newMultiStep + xSetupRotaryEncoder( eRotaryEncoderMode_Menu, eMainMenu_Settings, MENU_SIZE_MAIN_MENU - 1, 0, 1, 1 ); + + break; + } + default: { + if(repaint) { + + // display menu + lcd.clear(); + lcd.home (); // go home + lcd.print("Brewery Menu"); + switch(rotaryEncoderVirtualPosition) { - case main_manual: { + case eMainMenu_GO: { + lcd.setCursor (0,1); // go to start of 2nd line + lcd.print("-> GO "); + break; + } + case eMainMenu_Presets: { + lcd.setCursor (0,1); // go to start of 2nd line + lcd.print("-> Presets "); + break; + } + case eMainMenu_Malt: { + lcd.setCursor (0,1); // go to start of 2nd line + lcd.print("-> Malt "); + break; + } + case eMainMenu_Startpoint: { + lcd.setCursor (0,1); // go to start of 2nd line + lcd.print("-> Startpoint "); + break; + } + case eMainMenu_BetaGlucanase: { + lcd.setCursor (0,1); // go to start of 2nd line + lcd.print("-> BetaGlucanase"); + break; + } + case eMainMenu_Debranching: { + lcd.setCursor (0,1); // go to start of 2nd line + lcd.print("-> Debranching "); + break; + } + case eMainMenu_Proteolytic: { + lcd.setCursor (0,1); // go to start of 2nd line + lcd.print("-> Proteolytic "); + break; + } + case eMainMenu_BetaAmylase: { + lcd.setCursor (0,1); // go to start of 2nd line + lcd.print("-> Beta Amylase "); + break; + } + case eMainMenu_AlphaAmylase: { + lcd.setCursor (0,1); // go to start of 2nd line + lcd.print("-> Alpha Amylase"); + break; + } + case eMainMenu_Mashout: { lcd.setCursor (0,1); // go to start of 2nd line - lcd.print("-> Manual "); - delay(100); + lcd.print("-> Mashout "); break; } - case main_auto: { + case eMainMenu_Recirculation: { lcd.setCursor (0,1); // go to start of 2nd line - lcd.print("-> Automatic "); - delay(100); + lcd.print("-> Recirculation"); + break; + } + case eMainMenu_Sparge: { + lcd.setCursor (0,1); // go to start of 2nd line + lcd.print("-> Sparge "); + break; + } + case eMainMenu_Boil: { + lcd.setCursor (0,1); // go to start of 2nd line + lcd.print("-> Boil "); + break; + } + case eMainMenu_Hops: { + lcd.setCursor (0,1); // go to start of 2nd line + lcd.print("-> Hops "); + break; + } + case eMainMenu_Cooling: { + lcd.setCursor (0,1); // go to start of 2nd line + lcd.print("-> Cooling "); + break; + } + case eMainMenu_Settings: { + lcd.setCursor (0,1); // go to start of 2nd line + lcd.print("-> Settings "); break; } default: { - //lcd.setCursor (0,1); // go to start of 2nd line - //lcd.print("*** Error ***"); - rotaryEncoderVirtualPosition = 0; + // reset operation state | INPUT : TRotaryEncoderMode newMode, int newPosition, int newMaxPosition, int newMinPosition, int newSingleStep, int newMultiStep + xSetupRotaryEncoder( eRotaryEncoderMode_Menu, eMainMenu_GO, MENU_SIZE_MAIN_MENU - 1, 0, 1, 1 ); } } - if (!(digitalRead(PinSW))) { // check if pushbutton is pressed - menu_position[0] = rotaryEncoderVirtualPosition; - while (!digitalRead(PinSW)) {} // wait til switch is released - delay(10); // debounce - break; - } + repaint = false; + } + + if ((digitalRead(ROTARY_ENCODER_SW_PIN))) { // check if pushbutton is pressed + menu_position[0] = rotaryEncoderVirtualPosition; + while (digitalRead(ROTARY_ENCODER_SW_PIN)) {} // wait til switch is released + delay(10); // debounce + break; } } } } +void MainMenu_GO() { + startBrewing(); + + backToStatus(); +} + +void MainMenu_Presets() { + +} + +void MainMenu_Malt() { + +} + +void MainMenu_Startpoint() { + startpointTime = getTimer( startpointTime ); + + startpointTemperature = xSetGenericValue( startpointTemperature, 0, 120, "temperature", "*C" ); +} + +void MainMenu_BetaGlucanase() { + betaGlucanaseTime = getTimer( betaGlucanaseTime ); + + betaGlucanaseTemperature = xSetGenericValue( betaGlucanaseTemperature, 0, 120, "temperature", "*C" ); +} + +void MainMenu_Debranching() { + debranchingTime = getTimer( debranchingTime ); + + debranchingTemperature = xSetGenericValue( debranchingTemperature, 0, 120, "temperature", "*C" ); +} + +void MainMenu_Proteolytic() { + proteolyticTime = getTimer( proteolyticTime ); + + proteolyticTemperature = xSetGenericValue( proteolyticTemperature, 0, 120, "temperature", "*C" ); +} + +void MainMenu_BetaAmylase() { + betaAmylaseTime = getTimer( betaAmylaseTime ); + + betaAmylaseTemperature = xSetGenericValue( betaAmylaseTemperature, 0, 120, "temperature", "*C" ); +} + +void MainMenu_AlphaAmylase() { + alphaAmylaseTime = getTimer( alphaAmylaseTime ); + + alphaAmylaseTemperature = xSetGenericValue( alphaAmylaseTemperature, 0, 120, "temperature", "*C" ); +} + +void MainMenu_Mashout() { + mashoutTime = getTimer( mashoutTime ); + + mashoutTemperature = xSetGenericValue( mashoutTemperature, 0, 120, "temperature", "*C" ); +} + +void MainMenu_Recirculation() { + recirculationTime = getTimer( recirculationTime ); + + recirculationTemperature = xSetGenericValue( recirculationTemperature, 0, 120, "temperature", "*C" ); +} + +void MainMenu_Sparge() { + spargeTime = getTimer( spargeTime ); + + spargeTemperature = xSetGenericValue( spargeTemperature, 0, 120, "temperature", "*C" ); +} + +void MainMenu_Boil() { + boilTime = getTimer( boilTime ); + + boilTemperature = xSetGenericValue( boilTemperature, 0, 120, "temperature", "*C" ); +} + +void MainMenu_Hops() { + +} + +void MainMenu_Coooling() { + coolingTime = getTimer( coolingTime ); + + coolingTemperature = xSetGenericValue( coolingTemperature, 0, 120, "temperature", "*C" ); +} + +void MainMenu_Settings() { + +} + + +void xCountTheTime( int temperatureRange ) { + // Check if the machine is in the right temperature range, for the current mode, + if(!(basePT100.getCurrentTemperature() > (cookTemperature - temperatureRange) && basePT100.getCurrentTemperature() < (cookTemperature + temperatureRange))) { + clockIgnore += millis() - clockStartTime - clockCounter; + } + + // Calculate the remaining time on the clock + clockCounter = cookTime - ((millis() - clockStartTime - clockIgnore) / 1000); +} + +bool isTimeLeft() { + if( clockCounter >= cookTime ) { + return false; + } + return true; +} + +unsigned long ulWattToWindowTime( unsigned long appliedWatts ) { + unsigned long ulPulsesRequired = ulAppliedWatts / dWattPerPulse; + return windowSize / 1000.0 * ulPulsesRequired; +} + +bool xRegulateTemperature() { + double diference = basePT100.getCurrentTemperature() - cookTemperature; + bool overTemperature = false; + unsigned long wattage = 0.0; + + // Deviation between the cook temperature set and the cook temperature measured + if( diference < 0.0 ) { + diference = diference * (-1.0); + overTemperature = true; + } + + // Calculate applied wattage, based on the distance from the target temperature + if( overTemperature ) { + // turn it off + wattage = 0.0; + } else { + if(diffrence <= 1) { + // turn it off + wattage = 0.0; + } else { + if(diffrence <= 3) { + // pulse lightly at 500 watt + wattage = 500.0; + } else { + if(diffrence <= 6) { + // pulse moderately at 1000 watt + wattage = 1000.0; + } else { + if(diffrence <= 9) { + // pulse hardly at 2000 watt + wattage = 2000.0; + } else { + //pulse constantly at HEATING_ELEMENT_MAX_WATTAGE watt + wattage = HEATING_ELEMENT_MAX_WATTAGE; + } + } + } + } + } + + // Update the recorded time for the begining of the window, if the previous window has passed + while((millis() - windowStartTime) > WindowSize) { // Check if it's time to vary the pulse width modulation and if so do it by shifting the "Relay in ON" Window + windowStartTime += WindowSize; + } + + // Apply wattage to the element at the right time + if( ulWattToWindowTime( wattage ) > (millis() - windowStartTime)) { + digitalWrite(HEATING_ELEMENT_OUTPUT_PIN,HIGH); + } else { + digitalWrite(HEATING_ELEMENT_OUTPUT_PIN,LOW); + } +} + +void xWarnClockEnded() { + /// TODO +} + +void xStageFirstRun( int stageTime, int stageTemperature ) { + // Set the clock + cookTime = stageTime; + + // Set the target temperature + cookTemperature = stageTemperature; + + // Reset the clock + clockStartTime = millis(); + clockIgnore = 0; +} + +void xTransitionIntoStage_GlobalVariables(eCookingStages nextStage) { + // Reset global stage variables + stageFirstRun = true; + cookingStage = nextStage; +} + +void xTransitionIntoStage(eCookingStages nextStage) { + + // Turn off all hardware that can damage itself if the machine is not cooking + xSafeHardwarePowerOff(); + + // Warn the user a stage has ended + xWarnClockEnded(); + + // Reset global stage variables + xTransitionIntoStage_GlobalVariables( nextStage ); +} + +void xBasicStageOperation( int iStageTime, int iStageTemperature, int iStageTemperatureRange, eCookingStages nextStage ) { + if(stageFirstRun) { + // Don't run this again + stageFirstRun = false; + + // When the stage should be skipped + if( iStageTime == 0) { + // Continue to the next stage + xTransitionIntoStage_GlobalVariables( nextStage ); + + // There is nothing to do, in this stage + return; + } else { + // Set the clock, target temperature and Reset the clock + xStageFirstRun( iStageTime, iStageTemperature ); + } + } else { + // Account for time spent at the target temperature | Input 1: range in ÂșC within which the target temperature is considered to be reached + xCountTheTime( iStageTemperatureRange ); + + if( isTimeLeft() ) { + // Do temperature control + xRegulateTemperature(); + + } else { + // Continue to the next stage + xTransitionIntoStage( nextStage ); + + // There is nothing to do, in this stage + return; + } + } + // There is nothing to do, in this iteration + return; +} + +void xWarnCookEnded() { + /// TODO +} + +bool stageFirstRun = true; +void operateMachine() { + + // Measure temperature, for effect + basePT100.measure(); + upPT100.measure(); + downPT100.measure(); + + // If cooking is done, return (this is a nice place to double check safety and ensure the cooking parts aren't on. + if(!cooking) { + xSafeHardwarePowerOff(); + + return; + } + + // Operate the machine according to the current mode + switch(cookingStage) { + case eCookingStage_Startpoint: { + // A basic operation for a basic stage + xBasicStageOperation( startpointTime, startpointTemperature, 1, eCookingStage_BetaGlucanase ); + + // There is nothing to do, in this iteration + break; + } + case eCookingStage_BetaGlucanase: { + // A basic operation for a basic stage + xBasicStageOperation( betaGlucanaseTime, betaGlucanaseTemperature, 1, eCookingStage_Debranching ); + + // There is nothing to do, in this iteration + break; + } + case eCookingStage_Debranching: { + // A basic operation for a basic stage + xBasicStageOperation( debranchingTime, debranchingTemperature, 1, eCookingStage_Proteolytic ); + + // There is nothing to do, in this iteration + break; + } + case eCookingStage_Proteolytic: { + // A basic operation for a basic stage + xBasicStageOperation( proteolyticTime, proteolyticTemperature, 1, eCookingStage_BetaAmylase ); + + // There is nothing to do, in this iteration + break; + } + case eCookingStage_BetaAmylase: { + // A basic operation for a basic stage + xBasicStageOperation( betaAmylaseTime, betaAmylaseTemperature, 1, eCookingStage_AlphaAmylase ); + + // There is nothing to do, in this iteration + break; + } + case eCookingStage_AlphaAmylase: { + // A basic operation for a basic stage + xBasicStageOperation( alphaAmylaseTime, alphaAmylaseTemperature, 1, eCookingStage_Mashout ); + + // There is nothing to do, in this iteration + break; + } + case eCookingStage_Mashout: { + // A basic operation for a basic stage + xBasicStageOperation( mashoutTime, mashoutTemperature, 1, eCookingStage_Recirculation ); + + // There is nothing to do, in this iteration + break; + } + case eCookingStage_Recirculation: { + // A basic operation for a basic stage + xBasicStageOperation( recirculationTime, recirculationTemperature, 1, eCookingStage_Sparge ); + + // There is nothing to do, in this iteration + break; + } + case eCookingStage_Sparge: { + // A basic operation for a basic stage + xBasicStageOperation( spargeTime, spargeTemperature, 1, eCookingStage_Boil ); + + // There is nothing to do, in this iteration + break; + } + case eCookingStage_Boil: { + // A basic operation for a basic stage + xBasicStageOperation( boilTime, boilTemperature, 1, eCookingStage_Cooling ); + + // There is nothing to do, in this iteration + break; + } + case eCookingStage_Cooling: { + // A basic operation for a basic stage + xBasicStageOperation( coolingTime, coolingTemperature, 1, eCookingStage_Done ); + + // There is nothing to do, in this iteration + break; + } + default : { + // Update state + cooking = false; + + // Warn the user that the cooking is done + xWarnCookEnded(); + } + } +} + +// #################################################### Helpers ################################################################## + +void startBrewing() { + cooking = true; +} + +void stopBrewing() { + cooking = false; +} + +void backToStatus() { + lastInterruptTime = millis() - SETTING_MAX_INACTIVITY_TIME - 1; +} +// #################################################### Helpers ################################################################## + +// #################################################### Set Variables ################################################################## int getTimer(int init) { - state_machine initialState = state; - - // set operation state - state = state_manual_time; - rotaryEncoderVirtualPosition = init; + // set operation state | INPUT : TRotaryEncoderMode newMode, int newPosition, int newMaxPosition, int newMinPosition, int newSingleStep, int newMultiStep + xSetupRotaryEncoder( eRotaryEncoderMode_Time, init, 7200, 0, 1, 30 ); // initialize variables int rotaryEncoderPreviousPosition = 0; @@ -635,16 +1186,24 @@ int getTimer(int init) { lcd.clear(); lcd.home(); lcd.print("Set Time"); - lcd.setCursor (0,LCD_Y-1); + lcd.setCursor (0,LCD_VERTICAL_RESOLUTION-1); lcd.print(" 0:00"); while(true) { - // Check for timer set - if (!(digitalRead(PinSW))) { // check if pushbutton is pressed - while (!digitalRead(PinSW)) {} // wait til switch is released - delay(10); // debounce + // Check if pushbutton is pressed + if ((digitalRead(ROTARY_ENCODER_SW_PIN))) { + // Wait until switch is released + while (digitalRead(ROTARY_ENCODER_SW_PIN)) {} + + // debounce + delay(10); + + // Job is done, break the circle break; - } + } else { + // Don't forget to keep an eye on the cooking + operateMachine(); + } // display current timer if (rotaryEncoderVirtualPosition != rotaryEncoderPreviousPosition) { @@ -652,7 +1211,7 @@ int getTimer(int init) { minutes = rotaryEncoderVirtualPosition/60; seconds = rotaryEncoderVirtualPosition-minutes*60; - lcd.setCursor (0,LCD_Y-1); + lcd.setCursor (0,LCD_VERTICAL_RESOLUTION-1); lcd.print(" "); lcd.print(minutes); lcd.print(":"); @@ -664,15 +1223,16 @@ int getTimer(int init) { } } - state = initialState; + backToStatus(); + rotaryEncoderMode = initialState; return rotaryEncoderVirtualPosition; } int getTemperature(int init) { - state_machine initialState = state; + TRotaryEncoderMode initialState = rotaryEncoderMode; // set operation state - state = state_manual_temperature; + rotaryEncoderMode = eRotaryEncoderMode_Generic; rotaryEncoderVirtualPosition = init; // initialize variables @@ -682,24 +1242,32 @@ int getTemperature(int init) { lcd.clear(); lcd.home(); lcd.print("Set Temperature"); - lcd.setCursor (0,LCD_Y-1); + lcd.setCursor (0,LCD_VERTICAL_RESOLUTION-1); lcd.print(" 0 *C"); - rotaryEncoderMaxPosition = TEMPERATURE_MAX_POSITION; + rotaryEncoderMaxPosition = TEMPERATURE_SETTING_MAX_VALUE; while(true) { - // Check for timer set - if (!(digitalRead(PinSW))) { // check if pushbutton is pressed - while (!digitalRead(PinSW)) {} // wait til switch is released - delay(10); // debounce + // Check if pushbutton is pressed + if ((digitalRead(ROTARY_ENCODER_SW_PIN))) { + // Wait until switch is released + while (digitalRead(ROTARY_ENCODER_SW_PIN)) {} + + // debounce + delay(10); + + // Job is done, break the circle break; - } + } else { + // Don't forget to keep an eye on the cooking + operateMachine(); + } // display current timer if (rotaryEncoderVirtualPosition != rotaryEncoderPreviousPosition) { rotaryEncoderPreviousPosition = rotaryEncoderVirtualPosition; - lcd.setCursor (0,LCD_Y-1); + lcd.setCursor (0,LCD_VERTICAL_RESOLUTION-1); lcd.print(" "); if(rotaryEncoderVirtualPosition<10) { lcd.print(" "); @@ -715,426 +1283,69 @@ int getTemperature(int init) { } } - state = initialState; + backToStatus(); + rotaryEncoderMode = initialState; return rotaryEncoderVirtualPosition; } -int getMode() { - state_machine initialState = state; - int initialMenuSize = menuSize; - - // set operation state - state = state_manual_mode; - menuSize = 2; - rotaryEncoderVirtualPosition = cookMode; +int xSetGenericValue(int init, int min, int max, char *valueName, char *unit) { + // set operation state | INPUT : TRotaryEncoderMode newMode, int newPosition, int newMaxPosition, int newMinPosition, int newSingleStep, int newMultiStep + xSetupRotaryEncoder( eRotaryEncoderMode_Generic, init, max, min, 1, 5 ); // initialize variables int rotaryEncoderPreviousPosition = 0; // Setup Screen lcd.clear(); - lcd.home(); - lcd.print("Set Mode"); - lcd.setCursor (0,LCD_Y-1); - lcd.print(" Quick Start"); + lcd.home(); + lcd.print( "Set " ); + lcd.print( valueName ); + lcd.setCursor ( 0 , LCD_VERTICAL_RESOLUTION - 1 ); + lcd.print( " 0 " ); + lcd.print( unit ); + + rotaryEncoderMaxPosition = TEMPERATURE_SETTING_MAX_VALUE; while(true) { - // Check for timer set - if (!(digitalRead(PinSW))) { // check if pushbutton is pressed - while (!digitalRead(PinSW)) {} // wait til switch is released - delay(10); // debounce - break; - } - - // display current timer - if (rotaryEncoderVirtualPosition != rotaryEncoderPreviousPosition) { - rotaryEncoderPreviousPosition = rotaryEncoderVirtualPosition; - - lcd.setCursor (0,LCD_Y-1); + // Check if pushbutton is pressed + if ( digitalRead(ROTARY_ENCODER_SW_PIN) ) { + // Wait until switch is released + while ( digitalRead(ROTARY_ENCODER_SW_PIN) ) {} - switch(rotaryEncoderVirtualPosition) { - case quick_start: { - lcd.print(" Quick Start "); - - break; - } - case start_at_temperature: { - lcd.print("Start After Temp"); - - break; - } - default: { - lcd.print("*** error ***"); - } - } - lcd.println(" "); - } - } - - state = initialState; - menuSize = initialMenuSize; - return rotaryEncoderVirtualPosition; -} - -int getMixerSpeed(int init) { - state_machine initialState = state; - - // set operation state - state = state_manual_mixer; - rotaryEncoderVirtualPosition = init; + // debounce + delay( 10 ); - // initialize variables - int rotaryEncoderPreviousPosition = 0; - int mixerSpeed = 0; - - // Setup Screen - lcd.clear(); - lcd.home(); - lcd.print("Set Mixer Speed"); - lcd.setCursor (0,LCD_Y-1); - lcd.print(" 000"); - - rotaryEncoderMaxPosition = MIXER_MAX_POSITION; - - while(true) { - // Check for timer set - if (!(digitalRead(PinSW))) { // check if pushbutton is pressed - while (!digitalRead(PinSW)) {} // wait til switch is released - delay(10); // debounce + // Job is done, break the circle break; - } + } else { + // Don't forget to keep an eye on the cooking + operateMachine(); + } - // display current timer - if (rotaryEncoderVirtualPosition != rotaryEncoderPreviousPosition) { + // Check if there was an update by the rotary encoder + if( rotaryEncoderVirtualPosition != rotaryEncoderPreviousPosition ) { rotaryEncoderPreviousPosition = rotaryEncoderVirtualPosition; - lcd.setCursor (0,LCD_Y-1); - lcd.print(" "); - //lcd.print(minutes); - //lcd.print(":"); - if(rotaryEncoderVirtualPosition<100) { - lcd.print("0"); - if(rotaryEncoderVirtualPosition<10) { - lcd.print("0"); - } - } - lcd.print(rotaryEncoderVirtualPosition); - lcd.println(" "); - - // DEBUG - analogWrite(MIXER_PIN, rotaryEncoderVirtualPosition); - } - } - - state = initialState; - return rotaryEncoderVirtualPosition; -} - -void runStart() { - - // Working environment variables - float runCurrentTemperature; - long runTargetTemperature; - unsigned long runStartTime; - unsigned long runTargetTime; - cook_mode_list runCurrentMode; - unsigned long runMixerSpeed; - - // Configure environment - boolean clockStart = false; - boolean clockEnd = false; - - // Iterative work - while(true) { - - // Build Instructions - switch(menu_position[0]) { - case main_manual: { - - // whenever changes are made to the cook variables, they must be applied to the running variables - runTargetTemperature = cookTemperature; - runTargetTime = cookTime; - runCurrentMode = cookMode; - runMixerSpeed = cookMixerSpeed; - - // check if time ended and is time to stop and return to menu - if(clockStart && clockEnd) { - - // Turn mixer OFF for safety - analogWrite(MIXER_PIN, 0); - - // Turn heading element OFF for safety - digitalWrite(HEATING_ELEMENT,LOW); - - // Pause for efect - delay(1000); - - return; - } - - break; - } - case main_auto: { - // get the next instruction - - // if it's time for a new instruction - - // if human interaction is required - - // display message - - // sound buzzer - - // check if rotary encoder press to continue - - // check what variables are afected - - // check what the new values are - - // apply the values - - // if it's NOT time for a new instruction - //delay(1000); - - break; - } - default: { - lcdPrint("Error", "The system has failed to be set into manual or automatic mode!"); - state = state_error; - error = catastrofic_failure_logic_auto_manual; - return; - } - } - - // ************ Run Instructions ************ - - // Setup LCD - lcd.clear(); - lcd.home(); - lcd.print("Hot: 000*C/000*C"); - //lcd.print("Cool:000*C/000*C"); - lcd.setCursor (0,LCD_Y-1); - if(runCurrentMode == quick_start) { - lcd.print("Quick 00:00"); - - clockStart = true; - runStartTime = millis(); - } - else { - lcd.print("Wait 00:00"); - } - - float amostra1 = -1; - float amostraAnterior = -1; - unsigned long lastTemperatureRead = millis(); - - while(true) { - - if(millis() - lastTemperatureRead >= 1000) { - amostraAnterior = amostra1; - digitalWrite(TEMPERATURE_SENSOR_PIN, HIGH); - //delay(20); - amostra1 = analogRead(ponto1); - digitalWrite(TEMPERATURE_SENSOR_PIN, LOW); - lastTemperatureRead = millis(); - } - - float Vs = 1.081; //4.9345; - float Vin = 4.87; //8.8345; - float adcStepCount = 1024.0; - float R1 = 606.0; - float Rl = 2.7; //2.9; - float R_OpTemp = 0; //19.7; //21.597; //24.37; - - //Vout = amostra1 * Vs / adcStepCount;// + 0.0079816667; - Vout = (amostra1+amostraAnterior) / 2 * Vs / adcStepCount;// + 0.0079816667; - //Rx = 151.5 * Vout / ( 11.01 - Vout ) - 30; - - Rx = R1 / ( Vin / Vout - 1.0) - Rl - R_OpTemp; - - runCurrentTemperature = 1.08271 * pow(10.0, -13.0) * (3.12508 * pow(10.0, 16.0) - 5.65566 * pow(10.0, 6.0) * sqrt(3.51501 * pow(10.0, 19.0) - 4.61805 * pow(10.0, 16.0) * Rx)); - - /* - Serial.print("O valor das entradas sao: ["); - Serial.print(amostra1); - Serial.print(", "); - Serial.print(amostra2); - Serial.print("]"); - Serial.print("diferenca: ["); - Serial.print(diferenca, 6); - Serial.print("] tensao por amortra: ["); - Serial.print(tensaoPorAmostra, 6); - Serial.print("] Vg: ["); - Serial.print(Vg, 6); - Serial.print("] Vs: ["); - Serial.print(Vs); - Serial.print("] a: ["); - Serial.print(a, 6); - Serial.print("] Rx: ["); - Serial.print(Rx, 6); - */ - - // Operate mixer - analogWrite(MIXER_PIN, runMixerSpeed); - - // Operate the heating element - Input = runCurrentTemperature; - Setpoint = runTargetTemperature; - myPID.Compute(); - - // Get time and use as "date" of the sensor readings - unsigned long now = millis(); - - // Check if it's time to vary the pulse width modulation and if so do it by shifting the "Relay in ON" Window - if(now - windowStartTime>WindowSize) - { - windowStartTime += WindowSize; - } - - // Check if the "date" is inside the "Relay ON" window and turn it ON; if not, turn it OFF - if(Output > now - windowStartTime) { - digitalWrite(HEATING_ELEMENT,HIGH); - - if(Output != 0) { - Serial.print("O valor das entradas sao: ["); - Serial.print(amostra1); - Serial.print("] Vout["); - Serial.print(Vout,6); - Serial.print("] Rx["); - Serial.print(Rx,6); - Serial.print("] Temperature["); - Serial.print(runCurrentTemperature,6); - Serial.print("] "); - - Serial.print("+++ Diff: "); - Serial.print(now - windowStartTime); - Serial.print(" | Output: "); - Serial.println(Output); - - } + lcd.setCursor( 0, LCD_VERTICAL_RESOLUTION - 1 ); + lcd.print( " " ); + if( rotaryEncoderVirtualPosition < 10 ) { + lcd.print( " " ); } else { - digitalWrite(HEATING_ELEMENT,LOW); - - if(Output != 0) { - Serial.print("O valor das entradas sao: ["); - Serial.print(amostra1); - Serial.print("] Vout["); - Serial.print(Vout,6); - Serial.print("] Rx["); - Serial.print(Rx,6); - Serial.print("] Temperature["); - Serial.print(runCurrentTemperature,6); - Serial.print("] "); - - Serial.print("--- Diff: "); - Serial.print(now - windowStartTime); - Serial.print(" | Output: "); - Serial.println(Output); - - } - else { - Serial.print("O valor das entradas sao: ["); - Serial.print(amostra1); - Serial.print("] Vout["); - Serial.print(Vout,6); - Serial.print("] Rx["); - Serial.print(Rx,6); - Serial.print("] Temperature["); - Serial.print(runCurrentTemperature,6); - Serial.println("]"); + if( rotaryEncoderVirtualPosition < 100 ) { + lcd.print( " " ); } } - - // Print status to LCD - //if(runCurrentTemperature > 0) { - lcd.setCursor (5,0); - if (runCurrentTemperature < 10) { - lcd.print(" "); - } - else { - if (runCurrentTemperature < 100) { - lcd.print(" "); - } - } - lcd.print(runCurrentTemperature, 1); - - lcd.setCursor (11,0); - if (runTargetTemperature < 10) { - lcd.print(" "); - } - else { - if (runTargetTemperature < 100) { - lcd.print(" "); - } - } - lcd.print(runTargetTemperature); - //} - - // Check if the target temperature has been reached so the clock can move forward. - if(runCurrentTemperature == runTargetTemperature && clockStart == false) { - clockStart = true; - runStartTime = now; - } - - // If the clock can move forward, calculate it's display time; if not, set it to the total cooking time - int displayTime = 0; - if(clockStart) { - displayTime = runTargetTime - ((now - runStartTime) / 1000); - - if(displayTime <= 0) { - displayTime = 0; - clockEnd = true; - - break; - } - } - else { - displayTime = runTargetTime; - } - - // Print the clock to the LCD - int minutes = displayTime/60; - int seconds = displayTime-minutes*60; - lcd.setCursor (10,1); - //lcd.print(" "); - if (minutes < 10) { - lcd.print(" 0"); - } - else { - if (minutes < 100) { - lcd.print(" "); - } - } - lcd.print(minutes); - lcd.print(":"); - if(seconds<10) { - lcd.print("0"); - } - lcd.print(seconds); + lcd.print( rotaryEncoderVirtualPosition ); + lcd.print( " *C" ); + lcd.println( " " ); } } + + return rotaryEncoderVirtualPosition; } -void runError() { - if(error != no_error) { - if (error == catastrofic_failure_sensor_temperature) - { - Serial.println("[Error] catastrofic_failure_sensor_temperature!"); - - lcdPrint("ERROR", "A catastrofic failure was detected on the temperature sensor!"); - /* - if (!isnan(dht.readTemperature())) { // Check if any reads failed and exit early (to try again). - error = no_error; - return; - } - */ - } - } - else { - state = state_welcome; - } -} +// ###################### Set Variables ################################################## void lcdPrint(String title, String message) { int messageLength = message.length(); @@ -1146,8 +1357,8 @@ void lcdPrint(String title, String message) { lcd.print(title); // print message - if(messageLength <= LCD_X) { - lcd.setCursor(0,LCD_Y-1); + if(messageLength <= LCD_HORIZONTAL_RESOLUTION) { + lcd.setCursor(0,LCD_VERTICAL_RESOLUTION-1); lcd.print(message); delay(1000); } @@ -1164,8 +1375,8 @@ void lcdPrint(String title, String message) { } // print scrolling message - for (int cursor = 0; cursor < messageLength - LCD_X; cursor+=2) { - lcd.setCursor(0,LCD_Y-1); + for (int cursor = 0; cursor < messageLength - LCD_HORIZONTAL_RESOLUTION; cursor+=2) { + lcd.setCursor(0,LCD_VERTICAL_RESOLUTION-1); lcd.print(output_message.substring(cursor, cursor+16)); delay(500); } -- 2.24.1