//****************************************************************
//* Name : SmokerDuino PID Controller *
//* Author : Robert Joseph Korn *
//* Notice : Copyright (c) 2015 Open Valley Consulting Corp *
//* Date : 10/18/15 *
//* Version : 1.1 *
//* Notes : *
//* : *
//****************************************************************
//-------------------------------------------------------------------
// Based on Sous Videno
// by Brady Doll
//
// Which was based on the Sous Vide Controller
// by Bill Earl - for Adafruit Industries
// https://github.com/adafruit/Sous_Viduino
//
// which is in turn was
// Based on the Arduino PID and PID AutoTune Libraries
// by Brett Beauregard
// http://playground.arduino.cc/Code/PIDLibrary
// http://playground.arduino.cc//Code/PIDAutotuneLibrary
//
// Uses the Adafruit RGB LCD Shield library
// https://github.com/adafruit/Adafruit-RGB-LCD-Shield-Library
//
//-----------
// Large LCD font based on Instructable:
// Custom Large Font for 16x2 LCDs by mpilchfamily
// http://www.instructables.com/id/Custom-Large-Font-For-16x2-LCDs/
//------------------------------------------------------------------
// ************************************************
// Compilation options
//
// Comment/Uncomment to disable/enable options
// ************************************************
// LCD Options
#define CHARS 16 // Screen characters, Supports 16 or 20
// Support color LCD backlight
#define COLOR true // Comment for monochrome backlight
// Enable serial logging
#define LOGGING true // Comment to disable logging
// Default setpoint
#define SETPOINT_DEF 64.5
// Default Kp, Ki, & Kd values
#define KP_DEF 850
#define KI_DEF 0.5
#define KD_DEF 0.1
// ************************************************
// Libraries
// ************************************************
// Libraries for Adafruit LCD shield
#include <Wire.h>
//#include <Adafruit_MCP23017.h>
#include <Adafruit_RGBLCDShield.h>
// Libraries for the max6675 Thermocouple
#include "max6675.h"
// PID Library
#include <PID_v1.h>
#include <PID_AutoTune_v0.h>
// So we can save and retrieve settings
#include <EEPROM.h>
// ************************************************
// PID Variables and constants
// ************************************************
//Define Variables we'll be connecting to
double Setpoint = SETPOINT_DEF;
double Input;
double Output;
// Output relay on time
volatile long onTime = 0;
// pid tuning parameters
double Kp = KP_DEF;
double Ki = KI_DEF;
double Kd = KD_DEF;
// EEPROM addresses for persisted data
const int SpAddress = 0;
const int KpAddress = 8;
const int KiAddress = 16;
const int KdAddress = 24;
const int configAddress = 32; // Bitmask, Unit settings, pump settings
//Specify the links and initial tuning parameters
PID myPID(&Input, &Output, &Setpoint, Kp, Ki, Kd, DIRECT);
// 10 second Time Proportional Output window
const int WindowSize = 10000;
unsigned long windowStartTime;
// ************************************************
// Auto Tune Variables and constants
// ************************************************
byte ATuneModeRemember = 2;
const double aTuneStep = 500;
const double aTuneNoise = 1;
const unsigned int aTuneLookBack = 20;
// Tuning mode
boolean tuning = false;
// Auto Tuner
PID_ATune aTune(&Input, &Output);
// ************************************************
// Display variables and constants
// ************************************************
// Backlight colors
#if defined(COLOR)
#define RED 0x1
#define YELLOW 0x3
#define GREEN 0x2
#define TEAL 0x6
#define BLUE 0x4
#define VIOLET 0x5
#endif
#define WHITE 0x7
// Large font segments
const int TOP_LEFT = 0;
const int TOP_BAR = 1;
const int TOP_RIGHT = 2;
const int LOWER_LEFT = 3;
const int LOWER_BAR = 4;
const int LOWER_RIGHT = 5;
const int TOP_MIDDLE_BAR = 6;
const int DEGREE = 7;
const int BLANK = 254;
const int SOLID = 255;
// Define custom characters that make up segmetns
// Top left
uint8_t tl[8] = { B00111, B01111, B11111, B11111, B11111, B11111, B11111, B11111, };
// Top bar
uint8_t ub[8] = { B11111, B11111, B11111, B00000, B00000, B00000, B00000, B00000, };
// Top right
uint8_t tr[8] = { B11100, B11110, B11111, B11111, B11111, B11111, B11111, B11111, };
// Bottom left
uint8_t ll[8] = { B11111, B11111, B11111, B11111, B11111, B11111, B01111, B00111, };
// Bottom bar
uint8_t lb[8] = { B00000, B00000, B00000, B00000, B00000, B11111, B11111, B11111 };
// Bottom right
uint8_t lr[8] = { B11111, B11111, B11111, B11111, B11111, B11111, B11110, B11100 };
// Upper middle bar
uint8_t umb[8] = { B11111, B11111, B11111, B00000, B00000, B00000, B11111, B11111 };
// Degree
uint8_t deg[8] = { B01110, B11111, B11011, B11111, B01110, B00000, B00000, B00000 };
// Define large characters
uint8_t zero[6] = { TOP_LEFT, TOP_BAR, TOP_RIGHT, LOWER_LEFT, LOWER_BAR, LOWER_RIGHT };
uint8_t one[6] = { TOP_BAR, TOP_RIGHT, BLANK, LOWER_BAR, SOLID, LOWER_BAR };
uint8_t two[6] = { TOP_MIDDLE_BAR, TOP_MIDDLE_BAR, TOP_RIGHT, LOWER_LEFT, LOWER_BAR, LOWER_BAR };
uint8_t three[6] = { TOP_MIDDLE_BAR, TOP_MIDDLE_BAR, TOP_RIGHT, LOWER_BAR, LOWER_BAR, LOWER_RIGHT };
uint8_t four[6] = { LOWER_LEFT, LOWER_BAR, SOLID, BLANK, BLANK, SOLID };
uint8_t five[6] = { LOWER_LEFT, TOP_MIDDLE_BAR, TOP_MIDDLE_BAR, LOWER_BAR, LOWER_BAR, LOWER_RIGHT };
uint8_t six[6] = { TOP_LEFT, TOP_MIDDLE_BAR, TOP_MIDDLE_BAR, LOWER_LEFT, LOWER_BAR, LOWER_RIGHT };
uint8_t seven[6] = { TOP_BAR, TOP_BAR, TOP_RIGHT, BLANK, BLANK, SOLID };
uint8_t eight[6] = { TOP_LEFT, TOP_MIDDLE_BAR, TOP_RIGHT, LOWER_LEFT, LOWER_BAR, LOWER_RIGHT };
uint8_t nine[6] = { TOP_LEFT, TOP_MIDDLE_BAR, TOP_RIGHT, BLANK, BLANK, SOLID };
uint8_t c[6] = { TOP_LEFT, TOP_BAR, TOP_BAR, LOWER_LEFT, LOWER_BAR, LOWER_BAR };
uint8_t f[6] = { TOP_LEFT, TOP_MIDDLE_BAR, TOP_MIDDLE_BAR, SOLID, BLANK, BLANK };
uint8_t s[6] = { TOP_LEFT, TOP_MIDDLE_BAR, TOP_MIDDLE_BAR, LOWER_BAR, LOWER_BAR, LOWER_RIGHT };
uint8_t v[6] = { LOWER_LEFT, BLANK, BLANK, BLANK, LOWER_LEFT, LOWER_RIGHT };
uint8_t blank[6] = { BLANK, BLANK, BLANK, BLANK, BLANK, BLANK };
// Initalize the Adafruit LCD shield
Adafruit_RGBLCDShield lcd = Adafruit_RGBLCDShield();
// Flash state
unsigned long previousFlash = 0;
const int flashInterval = 500;
bool flashed = false;
int8_t prevFlash = -1;
// Current display offset
uint8_t x = 0;
// ************************************************
// Relay control
// ************************************************
// Output Relay
#define RelayPin 5
// ************************************************
// Logging
// ************************************************
// Optional logging support
#if defined(LOGGING)
const int logInterval = 10000; // log every 10 seconds
unsigned long lastLogTime = 0;
#endif
// ************************************************
// Mode variables and constants
// ************************************************
// Maximum number of menu items
const int MENU_MAX = 4;
const int SETTINGS_MENU_MAX = 6;
const int TUNE_MENU_MAX = 11;
// Menu timeout
const long menuTimeout = 20000; // 20s
enum mode {
MENU = 0,
RUN, // --> begin Main menu
SET_TEMP,
DISPLAY_TEMP,
SETTINGS, // <-- end Main menu
CHOOSE_UNITS, // --> begin Settings menu
TUNING, // <-- end Settings menu
TUNE_KP, // --> begin Tuning menu
TUNE_KI,
TUNE_KD,
AUTOTUNE // <-- end Tuning menu
};
int8_t currentMode = MENU;
uint8_t previousMode = MENU;
unsigned long menuReturn = 0;
// Run PID
bool runPID = false;
// ************************************************
// Button variables and constants
// ************************************************
#define BUTTON_MENU BUTTON_SELECT
// Current selected button(s)
uint8_t buttons = 0;
// Delay interval for button registration
const unsigned long selectInterval = 90;
// Previous states of buttons
bool buttonStates[5] = {
false, // BUTTON_LEFT
false, // BUTTON_RIGHT
false, // BUTTON_UP
false, // BUTTON_DOWN
false // SELECT
};
// ************************************************
// Temperature interface constants
int tcDO = 6;
int tcCS = 7;
int tcCLK = 8;
// Load temperature sensor
MAX6675 tc(tcCLK, tcCS, tcDO);
// Temperature (for viewing)
float currentTemp;
// Change temperature
float changeTemp;
// Selected digit
int8_t selected = 0;
// Units
enum units { C = 0, F };
// Current unit
uint8_t currentUnits = C;
// Selected unit
uint8_t selectedUnits = currentUnits;
enum cycle {
SHOW_TEMP = 0,
SETP_TEMP,
DUTY,
DETAILED
};
uint8_t cycleDisplay = 0;
const int cycleInterval = 5000;
// Current time
unsigned long currentMillis = 0;
//// Misc Interval
unsigned long previousInterval = 0;
// Last selected item
int8_t lastSelect;
float changeValue = 0.0;
float prevValue = 0.0;
// ************************************************
// Setup
// ************************************************
void setup()
{
// Initialize the LCD
lcd.begin(CHARS, 2);
lcd.clear();
#if defined(COLOR)
lcd.setBacklight(GREEN);
#endif
// Create custom characters segements
lcd.createChar(TOP_LEFT, tl);
lcd.createChar(TOP_BAR, ub);
lcd.createChar(TOP_RIGHT, tr);
lcd.createChar(LOWER_LEFT, ll);
lcd.createChar(LOWER_BAR, lb);
lcd.createChar(LOWER_RIGHT, lr);
lcd.createChar(TOP_MIDDLE_BAR, umb);
lcd.createChar(DEGREE, deg);
// Display splash screen
x = 1;
customChar(s);
lcd.print(F("moker"));
x += 5;
lcd.setCursor(x, 0);
lcd.write(255);
lcd.write(1);
lcd.write(2);
lcd.setCursor(x, 1);
lcd.write(255);
lcd.write(4);
lcd.write(5);
lcd.print(F("uino"));
#if defined(LOGGING)
Serial.begin(9600);
#endif
// Initialize Output Relay Control
pinMode(RelayPin, OUTPUT); // Output mode to drive relay
digitalWrite(RelayPin, LOW); // Make sure it is off to start
// Initialize the PID and related variables
LoadParameters();
myPID.SetTunings(Kp, Ki, Kd);
myPID.SetSampleTime(1000);
myPID.SetOutputLimits(0, WindowSize);
// Run timer2 interrupt every 15 ms
TCCR2A = 0;
TCCR2B = 1<<CS22 | 1<<CS21 | 1<<CS20;
//Timer2 Overflow Interrupt Enable
TIMSK2 |= 1<<TOIE2;
myPID.SetMode(MANUAL);
// Delay for splash screen
delay(3000);
lcd.clear();
// Load menu
changeMode(MENU);
}
// ************************************************
// Main Loop
// ************************************************
void loop()
{
currentMillis = millis();
buttons = lcd.readButtons();
// Determine the current mode
switch (currentMode) {
case MENU:
displayMenu(MENU);
break;
case RUN:
Run();
break;
case SET_TEMP:
setValue(true, 1, true, MENU);
break;
case DISPLAY_TEMP:
displayTemp();
break;
case SETTINGS:
displayMenu(SETTINGS);
break;
case CHOOSE_UNITS:
chooseUnits();
break;
case TUNING:
displayMenu(TUNING);
break;
case TUNE_KP:
setValue(false, 0, true, TUNING);
break;
case TUNE_KI:
case TUNE_KD:
setValue(false, 2, false, TUNING);
break;
}
if (runPID) {
doControl();
}
}
// ************************************************
// Timer Interrupt Handler
// ************************************************
SIGNAL(TIMER2_OVF_vect)
{
if (runPID) {
DriveOutput();
} else {
digitalWrite(RelayPin, LOW); // make sure relay is off
}
}
// ************************************************
// Mode Functions
// ************************************************
/// Handles mode changes
///
/// <param name="newMode"></param>
void changeMode( uint8_t newMode )
{
// Reset the button states
for (uint8_t i = 0; i < 5; i++) {
buttonStates[i] = false;
}
bool celsius = (C == currentUnits);
previousMode = currentMode;
switch (previousMode) {
case SET_TEMP:
Setpoint = (celsius) ? changeValue : (changeValue - 32) * 0.555555555555556;
SaveParameters();
break;
case TUNE_KP:
Kp = changeValue;
SaveParameters();
myPID.SetTunings(Kp, Ki, Kd);
break;
case TUNE_KI:
Ki = changeValue;
SaveParameters();
myPID.SetTunings(Kp, Ki, Kd);
break;
case TUNE_KD:
Kd = changeValue;
SaveParameters();
myPID.SetTunings(Kp, Ki, Kd);
break;
}
switch (newMode) {
case MENU:
case SETTINGS:
case TUNING:
#if defined(COLOR)
lcd.setBacklight(BLUE);
#endif
lastSelect = -1;
selected = currentMode;
menuReturn = previousInterval = currentMillis;
break;
case RUN:
if (!runPID) {
myPID.SetMode(AUTOMATIC);
windowStartTime = millis();
runPID = true;
}
previousInterval = currentMillis;
cycleDisplay = SHOW_TEMP;
getTemp(celsius);
break;
case SET_TEMP:
#if defined(COLOR)
lcd.setBacklight(TEAL);
#endif
prevValue = changeValue = (celsius) ? Setpoint : (Setpoint * 1.8) + 32;
selected = 2;
lcd.clear();
printTemp(changeValue, celsius, true, true, 1);
prevFlash = -1;
break;
case DISPLAY_TEMP:
if (runPID) {
turnOff();
changeMode(MENU);
return;
} else {
#if defined(COLOR)
lcd.setBacklight(GREEN);
#endif
getTemp(celsius);
}
break;
case CHOOSE_UNITS:
#if defined(COLOR)
lcd.setBacklight(TEAL);
#endif
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(F("Units"));
selectedUnits = currentUnits;
displayUnitChooser();
break;
case TUNE_KP:
#if defined(COLOR)
lcd.setBacklight(TEAL);
#endif
prevValue = changeValue = Kp;
selected = 2;
lcd.clear();
x = (CHARS - 12) / 2;
printLargeNumber(changeValue, 0, true);
prevFlash = -1;
break;
case TUNE_KI:
#if defined(COLOR)
lcd.setBacklight(TEAL);
#endif
prevValue = changeValue = Ki;
selected = 2;
lcd.clear();
x = (CHARS - 10) / 2;
printLargeNumber(changeValue, 2, false);
prevFlash = -1;
break;
case TUNE_KD:
#if defined(COLOR)
lcd.setBacklight(TEAL);
#endif
prevValue = changeValue= Kd;
selected = 2;
lcd.clear();
x = (CHARS - 10) / 2;
printLargeNumber(changeValue, 2, false);
prevFlash = -1;
break;
case AUTOTUNE:
if (abs(Input - Setpoint) < 0.5) {
// Remember the mode we're in
ATuneModeRemember = myPID.GetMode();
// set up the auto-tune parameters
aTune.SetNoiseBand(aTuneNoise);
aTune.SetOutputStep(aTuneStep);
aTune.SetLookbackSec(int(aTuneLookBack));
tuning = true;
// Switch to the RUN mode
changeMode(RUN);
} else {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(F("The temperature must"));
lcd.setCursor(0, 1);
lcd.print(F("be within 0.5"));
lcd.write(B11011111);
lcd.print(F("C"));
delay(cycleInterval);
changeMode(SETTINGS);
}
return;
break;
}
currentMode = newMode;
}
/// Displays the menu
///
///
void displayMenu( uint8_t menu )
{
bool change = false;
if (buttons) {
if ((currentMillis - menuReturn) > flashInterval ) {
//if (checkButton(BUTTON_MENU)) {
// if ((currentMillis - menuReturn) > flashInterval ) {
// // Change back to the previous mode
// changeMode(previousMode);
// }
//} else if (checkButton(BUTTON_UP)) {
if (checkButton(BUTTON_UP)) {
selected--;
} else if(checkButton(BUTTON_DOWN)) {
selected++;
} else if (checkButton(BUTTON_RIGHT)) {
changeMode(selected);
return;
} else if (MENU != menu && (checkButton(BUTTON_LEFT) || checkButton(BUTTON_MENU))) {
if (SETTINGS == menu) {
changeMode(MENU);
selected = SETTINGS;
} else if (TUNING == menu) {
changeMode(SETTINGS);
selected = TUNING;
}
}
previousInterval = currentMillis;
}
} else {
// Reset the button states
for (uint8_t i = 0; i < 5; i++) {
buttonStates[i] = false;
}
// Check if we have reached our timout interval
if ((currentMillis - previousInterval) > menuTimeout) {
if (runPID) {
changeMode(RUN);
} else {
turnOff();
// Turn off the display backlight
lcd.setBacklight(0);
// Wait until a button is pressed
while (!buttons) {
buttons = lcd.readButtons();
}
menuReturn = previousInterval = millis();
// Turn the backlight back on
#if defined(COLOR)
lcd.setBacklight(BLUE);
#else
lcd.setBacklight(WHITE);
#endif
}
}
}
x = 0;
uint8_t min;
uint8_t max;
// Get the item ranges for the selected menu
if (MENU == menu) {
min = 1;
max = MENU_MAX;
} else if (SETTINGS == menu) {
min = MENU_MAX + 1;
max = SETTINGS_MENU_MAX;
} else if (TUNING == menu) {
min = SETTINGS_MENU_MAX + 1;
max = TUNE_MENU_MAX;
}
// Make sure the currently selected item is within the range
if (min > selected) {
selected = min;
} else if (max < selected) {
selected = max;
}
// Check if the selected item has changed
if (selected != lastSelect) {
bool celsius = (C == currentUnits);
lcd.clear();
int selected_num = selected;
if (SETTINGS == menu) {
selected_num -= MENU_MAX;
} else if (TUNING == menu) {
selected_num -= SETTINGS_MENU_MAX;
}
printLargeDigit(selected_num);
x++;
lcd.setCursor(x, 0);
switch ( selected ) {
case RUN:
if (runPID) {
if (tuning) {
lcd.print(F("Tuning"));
} else {
lcd.print(F("Running"));
}
} else {
lcd.print(F("Run"));
}
lcd.setCursor(( (celsius) ? CHARS - 9 : CHARS - 10 ), 1);
lcd.print(F("SP:"));
lcd.print( (celsius) ? Setpoint : (Setpoint * 1.8) + 32 );
lcd.setCursor(CHARS - 2, 1);
lcd.write(B11011111); // Degree symbol
lcd.print( (celsius) ? 'C' : 'F' );
break;
case SET_TEMP:
lcd.print(F("Set"));
lcd.setCursor(x, 1);
lcd.print(F("Temperature"));
break;
case DISPLAY_TEMP:
if (runPID) {
lcd.print(F("Stop"));
lcd.setCursor(x, 1);
lcd.print(F("Running"));
} else {
lcd.print(F("Display"));
lcd.setCursor(x, 1);
lcd.print(F("Temperature"));
}
break;
case SETTINGS:
lcd.print(F("Settings"));
lcd.setCursor(x,1);
break;
// Settings Menu
case CHOOSE_UNITS:
lcd.print(F("Set"));
lcd.setCursor(x, 1);
lcd.print(F("Units"));
lcd.setCursor(CHARS - 1, 1);
lcd.print( (celsius) ? 'C' : 'F' );
break;
case TUNING:
lcd.print(F("Configure"));
lcd.setCursor(x, 1);
lcd.print(F("Tuning"));
break;
// Tuning Menu
case TUNE_KP:
lcd.print(F("Tune"));
lcd.setCursor(x, 1);
lcd.print(F("Kp"));
if (Kp < 100) {
lcd.setCursor(CHARS - 5, 1);
} else if (Kp < 1000) {
lcd.setCursor(CHARS - 6, 1);
} else {
lcd.setCursor(CHARS - 7, 1);
}
lcd.print(Kp);
break;
case TUNE_KI:
lcd.print(F("Tune"));
lcd.setCursor(x, 1);
lcd.print(F("Ki"));
lcd.setCursor(CHARS - 4, 1);
lcd.print(Ki);
break;
case TUNE_KD:
lcd.print(F("Tune"));
lcd.setCursor(x, 1);
lcd.print(F("Kd"));
lcd.setCursor(CHARS - 4, 1);
lcd.print(Kd);
break;
case AUTOTUNE:
lcd.print(F("Auto"));
lcd.setCursor(x,1);
lcd.print(F("Tuning"));
break;
}
lcd.setCursor(CHARS - 1, 0);
lcd.write(B01111110);
lastSelect = selected;
}
}
// Handles the run state
//
//
void Run() {
bool celsius = (C == currentUnits);
if (buttons) {
if (checkButton(BUTTON_MENU)) {
changeMode(MENU);
return;
} else if (buttons & BUTTON_LEFT && buttons & BUTTON_RIGHT) {
if (DETAILED != cycleDisplay) {
cycleDisplay = DETAILED;
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(F("Sp: "));
lcd.print((celsius) ? Setpoint : (Setpoint * 1.8) + 32);
lcd.write(B11011111); // degree symbol
lcd.print((celsius) ? 'C' : 'F');
lcd.setCursor(CHARS - 1, 0);
if (tuning) {
lcd.print(F("T"));
} else {
lcd.write(BLANK);
}
}
}
} else {
for (uint8_t i = 0; i < 5; i++) {
buttonStates[i] = false;
}
}
if (DETAILED != cycleDisplay) {
if ((SHOW_TEMP == cycleDisplay && (currentMillis - previousInterval) > menuTimeout) || ((SHOW_TEMP != cycleDisplay) && (currentMillis - previousInterval) > cycleInterval)) {
cycleDisplay++;
if (cycleDisplay > 2) {
cycleDisplay = 0;
}
if (SETP_TEMP == cycleDisplay) {
float setpTemp = (celsius) ? Setpoint : (Setpoint * 1.8) + 32;
printTemp(setpTemp, celsius, true, true, 1);
lcd.setCursor(0, 0);
lcd.print(F("S"));
lcd.setCursor(0, 1);
lcd.print(F("P"));
lcd.setCursor(CHARS - 1, 0);
if (tuning) {
lcd.print(F("T"));
} else {
lcd.write(BLANK);
}
} else if (DUTY == cycleDisplay) {
lcd.clear();
lcd.setCursor(CHARS - 2, 0);
lcd.print(F("%"));
lcd.setCursor(CHARS - 1, 0);
if (tuning) {
lcd.print(F("T"));
} else {
lcd.write(BLANK);
}
}
previousInterval = currentMillis;
}
}
float pct;
switch (cycleDisplay) {
case SHOW_TEMP:
printTemp(currentTemp, celsius, false, true, 2);
lcd.setCursor(CHARS - 1, 0);
if (tuning) {
lcd.print(F("T"));
} else {
lcd.write(BLANK);
}
break;
case DUTY:
pct = (map(Output, 0, WindowSize, 0, 1000) / 10);
x = (CHARS - 14) / 2;
printLargeNumber(pct, 2, false);
break;
case DETAILED:
lcd.setCursor(0, 1);
lcd.print(currentTemp);
lcd.write(B11011111); // degree symbol
if (celsius) {
lcd.print(F("C :"));
} else {
lcd.print(F("F :"));
}
pct = (map(Output, 0, WindowSize, 0, 1000) / 10);
if (pct < 100) {
lcd.write(BLANK);
}
lcd.print(pct);
lcd.print("%");
break;
}
#if defined(COLOR)
setBacklight();
#endif
}
///
///
///
void turnOff() {
runPID = false;
myPID.SetMode(MANUAL);
// Turn off the relay
digitalWrite(RelayPin, LOW); // make sure it is off
}
// ************************************************
// Execute the control loop
// ************************************************
void doControl() {
getTemp(C == currentUnits);
if (tuning) {
if (aTune.Runtime()) { // returns 'true' when done
FinishAutoTune();
}
} else {
// TODO: Add feed forward/quick heat mode
myPID.Compute();
}
// Time Proportional relay state is updated regularly via timer interrupt.
onTime = Output;
#if defined(LOGGING)
// Periodically log to the serial port in CSV format
if (currentMillis - lastLogTime > logInterval) {
Serial.print(Input);
Serial.print(",");
Serial.print(Output);
Serial.print(",");
Serial.print(Setpoint);
lastLogTime = currentMillis;
}
#endif
}
///
void displayTemp() {
if (buttons) {
if (checkButton(BUTTON_MENU)) {
changeMode(MENU);
return;
}
} else {
for (int i = 0; i < 5; i++) {
buttonStates[i] = false;
}
}
bool celsius = (C == currentUnits);
getTemp(celsius);
printTemp(currentTemp, celsius, false, true, 2);
#if defined(LOGGING)
// Periodically log to the serial port in CSV format
if (currentMillis - lastLogTime > logInterval) {
Serial.print(Input);
Serial.println(",0,0");
lastLogTime = currentMillis;
}
#endif
}
///
///
///
...
This file has been truncated, please download it to see its full contents.
Comments