Components and supplies
Arduino UNO
Standard LCD - 16x2 White on Blue
Resistor 1k ohm
Jumper wires (generic)
Buzzer
Project description
Code
Arduino based electric smoker controller
arduino
1 2// Note: The format offered here does not allow sufficient space on one line 3// to accomidate lengthy comments. Some changes may be necessary in the form 4// of "//" if the code is to be cut and pasted but may be ok if pasted into 5// the Arduino compiler 6 7// Start of Arduino Sketch: 8 9#include <LiquidCrystal_I2C.h> // Library for I2C LCD 10#include <OnewireKeypad.h> // OneWireKeypad Library 11 12char KEYS[] = { // Define keys values of Keypad 13 '1', '2', '3', 14 '4', '5', '6', 15 '7', '8', '9', 16 '*', '0', '#'}; 17 18#include <SPI.h> //The two max6675 thermocouples use SPI communications 19#include <Thermocouple.h> //This is the max6675 library that works (could not use "include max6675.h" library) 20#define csTC1 9 //chip select for MAX6675 #1 (SPI)--Smoker temperature--TC1--Orange wire 21#define csTC2 10 //chip select for MAX6675 #2 (SPI)--Meat temperature--TC3--Blue wire 22#include <PID_v1.h> //Library for implementing PID control of the set Smoker temperature 23#include <Wire.h> // Allows the use of the I2C bus 24Thermocouple tc1 = Thermocouple(csTC1); //Identify Thermocouple (from library) as Smoker pin 9 25Thermocouple tc2 = Thermocouple(csTC2); //Identify Thermocouple (from library) as Smoker pin 10 26OnewireKeypad <Print, 12 > Keypad(Serial, KEYS, 4, 3, A0, 4700, 1000 ); // Defines keypad as a 4 row, 3 column device //with pin A0 input along with the voltage dividing resistance value. 27 28LiquidCrystal_I2C lcd(0x3F, 16, 2); // Provides the I2C Bus address and defines the LCD as a 16 char, 2 line device 29double Input; // declare Input to be a double variable because the PID control library uses double (not interger) variables 30double Input2; 31double Input3; 32double InputAve; 33int RelayPin = 8; // declare pin8 for relay control 34int alert = 7; // declare pin7 for alert control 35const int tempMax = 320; // declare tempMax to be a constant 320 (degreeF)as the maximum temperature the smoker can reach 36double tempSmoke = 0; // declare tempSmoke to be a double variable of the internal temp. of the smoker (DegF) read from thermocouple1 37int tempMeat = 0; // declare tempMeat to be an interger value of the internal temp. of the meat being smoked (DegF) read from thermocouple2 38int tempMeat1 = 0; 39int tempMeat2 = 0; 40int tempMeatAve = 0; // tempMeatAve is the average of three tc2 readings to increase the accuracy of the actual meat temp reading 41int keypress = 0; // Set to 0 to eliminate any residual values from previous cycles 42int keypress1 = 0; 43int keypress2 = 0; 44double Setpoint; // declare 'Setpoint' as the value entered from the keypad as the desired maximum internal smoker temp. 45int SetMeatTemp; // declare SetMeatTemp as the value entered from the kaypad as the desired maximum internal meat temp. 46char Stop=0; // Sets the variable 'Stop' to zero to enable use of the 'while' function 47char Str1[15] = "CYCLE COMPLETE"; // declare a character string variable to be used at the end of the smoking cycle 48char Str2[15] = "ENJOY DINNER!!"; // declare a character string variable to be used at the end of the smoking cycle 49double Output; //Define Variables we'll be connecting to for PID control 50int Input1=Input; // declare 'Input1' as an integer so the places past the decimal are dropped for the Android (BT) display 51int Setpoint1=Setpoint; // declare 'Setpoint1' as an integer so the places past the decimal are dropped for the Android (BT) display 52PID myPID(&InputAve, &Output, &Setpoint,150,1,1, DIRECT); //Specify the links and initial tuning parameters for PID control 53int WindowSize = 3500; 54unsigned long windowStartTime; 55 56 57void setup () 58{ 59 60 Serial.begin(9600); 61 windowStartTime = millis(); 62 63 myPID.SetOutputLimits(0, WindowSize); //tell the PID to range between 0 and the full window size 64 65 myPID.SetMode(AUTOMATIC); //activate the PID 66 pinMode(RelayPin, OUTPUT); //declare pin8 as an output to the 120v relay to turn power on or off to the heating coil 67 lcd.init(); 68 lcd.backlight(); 69 Wire.begin(); 70 Keypad.SetHoldTime(100); 71 Keypad.Getkey(); 72 lcd.begin(16, 2); 73 lcd.clear(); 74 pinMode(alert, OUTPUT); // declare pin7 as output for the alert 75 lcd.print("SMOKE TEMP?"); //Displays 'SMOKE TEMP?' on LCD 76 77 delay(100); //Allows everything to get set 78} 79void loop() 80{ // The following section of the code reads the desired temperature for the smoker and the meat and sets up a 3 digit integer using 81 // (int number = 100 * int1 + 10 * int2 + int3) for the variables 'Setpoint' and 'SetMeatTemp'. 82 83 // 1st digit of the desired smoker temperature: 84 85 while (Stop == 0) { // Allows void loop to be executed in segments to control when events happen. Without 'while' the ketpress is a random entry. 86 if ((Keypad.Key_State() == 3)) // not pressed = 0, pressed = 1, released = 2, held = 3 87 { 88 lcd.setCursor(13, 0); 89 90 keypress = Keypad.Getkey(); 91 while ((Keypad.Key_State())) {} // Stay here until Key is held down 92 keypress = keypress - '0'; 93 lcd.print(keypress); 94 Stop = 1; 95 } 96 } 97 98 //2nd digit smoke: 99 while (Stop == 1) { 100 if ((Keypad.Key_State() == 3)) // not pressed = 0, pressed = 1, released = 2, held = 3 101 { 102 lcd.setCursor(14, 0); 103 keypress1 = Keypad.Getkey(); 104 while ((Keypad.Key_State())) {} // Stay here until Key is held down 105 keypress1 = keypress1 - '0'; 106 lcd.print(keypress1); 107 Stop = 2; 108 } 109 } 110 //3rd digit smoke: 111 while (Stop == 2) { 112 if ((Keypad.Key_State() == 3)) // not pressed = 0, pressed = 1, released = 2, held = 3 113 { 114 lcd.setCursor(15, 0); 115 keypress2 = Keypad.Getkey(); 116 while ((Keypad.Key_State())) {} // Stay here until Key is held down 117 keypress2 = keypress2 - '0'; 118 lcd.print(keypress2); 119 Stop = 3; 120 } 121 } 122 123 while (Stop == 3) { 124 Setpoint = 100 * keypress + 10 * keypress1 + keypress2; // Combines the three entered digits into one (3 digit) variable called 'SetSmokeTemp'. 125 126 lcd.setCursor(0, 1); 127 delay(10); 128 lcd.print("MEAT TEMP?"); //Displays 'MEAT TEMP' on LCD 129 Stop = 4; 130 } 131 // 1st digit of the desired meat temperature: 132 while (Stop == 4) { // Allows void loop to be executed in segments to control when events happen 133 134 if ((Keypad.Key_State() == 3)) // not pressed = 0, pressed = 1, released = 2, held = 3 135 { 136 lcd.setCursor(13, 1); 137 keypress = Keypad.Getkey(); 138 while ((Keypad.Key_State())) {} // Stay here until Key is held down 139 keypress = keypress - '0'; 140 lcd.print(keypress); 141 Stop = 5; 142 } 143 } 144 //2nd digit meat: 145 while (Stop == 5) { 146 if ((Keypad.Key_State() == 3)) // not pressed = 0, pressed = 1, released = 2, held = 3 147 { 148 lcd.setCursor(14, 1); 149 keypress1 = Keypad.Getkey(); 150 while ((Keypad.Key_State())) {} // Stay here until Key is held down 151 keypress1 = keypress1 - '0'; 152 lcd.print(keypress1); 153 Stop = 6; 154 } 155 } 156 157 //3rd digit meat: 158 while (Stop == 6) { 159 if ((Keypad.Key_State() == 3)) // not pressed = 0, pressed = 1, released = 2, held = 3 160 { 161 lcd.setCursor(15, 1); 162 keypress2 = Keypad.Getkey(); 163 while ((Keypad.Key_State())) {} // Stay here until Key is held down 164 keypress2 = keypress2 - '0'; 165 SetMeatTemp = 100 * keypress + 10 * keypress1 + keypress2; //Combines the 3 entered digits into one (3 digit) variable called 'SetMeatTemp'. 166 lcd.print(keypress2); 167 Stop = 7; 168 } 169 } 170 171 delay(50); // Provides a delay before the cycle begins 172 173 Input = (tc1.readF()-19); //'Input' is the reading of the actual internal smoker temperature adjusted(-19deg)to match the Redi reading(at225deg) 174 delay(350); 175 176 Input2=(tc1.readF()-19); 177 delay(350); 178 179 Input3=(tc1.readF()-19); 180 delay(350); 181 182 InputAve=(Input+Input2+Input3)/3; //The average of 3 readings is a bit more accurate 183 184 if (InputAve>335){InputAve=225;} //Prevents a 'flier' from shutting down the program (max temp 320) 185 186 delay(350); //the Max 6675 board is slow and should not be read more than 3 times per second 187 tempMeat = (tc2.readF()); //The reading from Thermocouple2 becomes the variable 'tempMeat' adjustment not needed to match the Redi reading(at165deg) 188 189 delay(350); //the Max 6675 board is slow and should not be read more than 3 times per second 190 tempMeat1 = (tc2.readF()); 191 192 delay(350); 193 tempMeat2 = (tc2.readF()); 194 195 delay(350); 196 if(tempMeat>tempMeat1+5||tempMeat<tempMeat1-5){tempMeat=100;tempMeat1=100;Serial.print("flier1 ");} //prevents 'fliers' from adversely affecting //the program 197 if(tempMeat>tempMeat2+5||tempMeat<tempMeat2-5){tempMeat=100;tempMeat2=100;Serial.print("flier2");} //prevents' fliers' from adversely affecting //the program 198 tempMeatAve = (tempMeat+tempMeat1+tempMeat2)/3; //Accuracy improved by averaging readings 199 200 if(tempMeatAve>SetMeatTemp+10){tempMeatAve=150;Serial.print("flier3");} //prevents 'fliers' from adversely affecting the program 201 202 203 // The following 7 lines turns the output pin on/off based on PID output 204 205 myPID.Compute(); 206 207 unsigned long now = millis(); 208 209 if(now - windowStartTime>WindowSize) 210 { 211 windowStartTime += WindowSize; //time to shift the Relay Window 212 } 213 if(Output > (now - windowStartTime)){ 214 digitalWrite(RelayPin, HIGH);Serial.println("ON"); 215 } 216 else {digitalWrite(RelayPin,LOW);Serial.println("OFF");}//} 217 218 lcd.clear(); // The following 17 lines set up the LCD display to indicate the Set & Actual temperatures 219 lcd.setCursor(0, 0); 220 lcd.print("SKset"); 221 lcd.setCursor(5, 0); 222 lcd.print(Setpoint); 223 lcd.setCursor(9, 0); 224 lcd.print("ACT"); 225 lcd.setCursor(13, 0); 226 lcd.print(InputAve); 227 lcd.setCursor(0, 1); 228 lcd.print("MTset"); 229 lcd.setCursor(5, 1); 230 lcd.print(SetMeatTemp); 231 lcd.setCursor(9, 1); 232 lcd.print("ACT"); 233 lcd.setCursor(13, 1); 234 lcd.print(tempMeatAve); 235 236 Serial.print("SmokerSetTemp="); // All "Serial.print" and "Serial.println" commands are to send status of smoker to Android BT device 237 Setpoint1=Setpoint; 238 Serial.print(Setpoint1); 239 Serial.print(" "); 240 Serial.print("ActualTemp="); 241 Input1=InputAve; 242 Serial.print(Input1); 243 Serial.println(); 244 Serial.println(); 245 Serial.print("MeatSetTemp = "); 246 Serial.print(SetMeatTemp); 247 Serial.print(" "); 248 Serial.print("ActualMeatTemp="); 249 Serial.print(tempMeatAve); 250 Serial.println(); 251 Serial.println(); 252 Serial.println(); 253 Serial.println(); 254 Serial.println(); 255 Serial.println(); 256 Serial.println(); 257 Serial.println(); 258 Serial.println(); 259 delay(50); 260 261 if (InputAve>=tempMax) // The following 8 lines monitor the maximum temperature of 320deg, shuts down the cycle, 262 {digitalWrite(RelayPin, LOW); // sends an alert to the display, and buzzer 263 264 lcd.clear(); 265 lcd.setCursor(0,0); 266 lcd.print("TEMPERATURE OUT"); 267 lcd.setCursor(0,1); 268 lcd.print(" OF CONTROL!!!"); 269 digitalWrite(alert, HIGH);} 270 271 if (tempMeatAve >= SetMeatTemp) // When tempMeat(from MAX6675(2)(thermocouple in meat))equals the meat set temp turn smoker coil OFF, 272 // indicate CYCLE COMPLETE on display, sound the Alert, and stop the Smoker cycle 273 { 274 digitalWrite(RelayPin, LOW); //"Stops"the smoking cycle (until the meat temp drops below the meat set temp) 275 Serial.println(" DINNER IS READY"); //Sends message to Android BT device 276 Serial.println(" COME AND GET IT!"); //Sends message to Android BT device 277 Serial.println(); 278 lcd.clear(); 279 lcd.setCursor(0, 0); 280 lcd.print(Str1); // print "CYCLE COMPLETE" on first line of LCD display 281 lcd.setCursor(0, 1); 282 lcd.print(Str2); // print "ENJOY DINNER!!" on second line of LCD display 283 digitalWrite(alert, HIGH); // Sets off the alert buzzer 284 delay(150); 285 digitalWrite(alert, LOW); // Provides a short 'beep-beep' instead of an annoying constant single'beeeeeeeep' 286 delay(150); 287 digitalWrite(alert, HIGH); 288 delay(150); 289 digitalWrite(alert, LOW); 290 delay(3000);} 291 } 292 293 294 295
Comments
Only logged in users can leave comments