Components and supplies
Resistor 220 ohm
irf540n n-channel mosfet
5mm Red LED
Yungui 12 PCs Universal PCB Board Single Sided
100x68x50mm ABS PLASTIC ELECTRONICS PROJECT BOX
Assorted DuPont Wires
5mm Yellow LED
36 Ohm 5 Watt
Diode 1N4001
Arduino Nano
5K Potentiometer
Binding Posts
10kOhm potentiometer
20x4 LCD Display with I2C
Fan 12 V 50x50x10 mm
Gikfun 2 pin and 3 pin Screw Terminal Blocks
Temperature Sensor: LM35dz
Resistor 30 Ohm s 5 watts
Tools and machines
Soldering Station
Apps and platforms
Arduino IDE
Project description
Code
PID Temperature Control of Thermal Chamber
c
Code is heavily commented
1#include <Wire.h> 2#include <LiquidCrystal_I2C.h> 3LiquidCrystal_I2C lcd(0x27, 20, 4); // I2C address 0x27, 20 , 4 4 5//#define C_Variable TR_C_Filtered 6float C_Variable; 7float propBand; 8float integralTime; 9float derivativeTime; 10bool LM35_1=true; 11bool LM35_2; 12bool Forward=false; 13bool Reverse=true; 14bool controlAction; 15String command; 16 17int tempLocal;// read from analog pin A0 18int tempRemote;// read from analog pin A3 19int potA1;// pot setting from analog pin A1 20int potA3;//pot setting from analog pin A3 21 22 23 24 25 26float TR_C;// Remote temperature in deg C, must be normalized in argument for PI Controller 27float TL_C;//Local temperature in deg C 28float TR_C_Filtered; 29float TL_C_Filtered; 30 31bool Auto=true; 32bool Manual=false; 33 34void LM35_A2();//Read the Remote LM35 on analog input A3 and display on LCD 35void LM35_A7();//Read the Local LM35 on analog input A1 and display to LCD 36void Potentiometer(bool action);// Read the potentiometer setting as an analog input and display as 0 to 100% 37void printText();// Print static text to display 38void SerialPlotter(int controllerOutput); 39 40float PID_output(float process, float setpoint, float Prop, float Integ, float deriv, int Interval, bool action); 41float SetpointGenerator(); 42float TR_C_filterFunction(float timeConstant, float processGain,float blockIn, float intervalTime); 43float TL_C_filterFunction(float timeConstant, float processGain,float blockIn, float intervalTime); 44float DerivativefilterFunction(float timeConstant, float processGain,float blockIn, float intervalTime); 45void setup() 46{ 47 lcd.init(); //initialize the lcd 48 lcd.backlight(); //open the backlight 49 50 //********** Set the PWM pins output.*********************** 51 pinMode(10, OUTPUT); 52 pinMode(11, OUTPUT); 53 //***********Serial Monitor******************************* 54 Serial.begin(9600); 55 //*******Print Static Text****************************** 56 57 printText(); 58 59 C_Variable=TR_C_Filtered; 60 propBand = 7; 61 integralTime=40; 62 derivativeTime=10; 63 //analogReference(INTERNAL);// Set to 1.1 volts 64 65} 66void loop() 67{ 68 float heaterSetting;// Normalized PI Controller Set Point 69 float contOutNorm;//Normalized PI Controller Output 70 71 72 if (Serial.available()) 73 { 74 command = Serial.readStringUntil('\n'); 75 command.trim(); 76 77 if (command.equals("Auto")) 78 { 79 Auto=true; 80 Manual=false; 81 } 82 83 else if (command.equals("Manual")) 84 { 85 Manual =true; 86 Auto=false; 87 } 88 89 else if (command.equals("LM35_1")) 90 { 91 LM35_1=true; 92 LM35_2=false; 93 propBand = 7; 94 integralTime=40; 95 derivativeTime=10; 96 } 97 98 else if (command.equals("LM35_2")) 99 { 100 LM35_2=true; 101 LM35_1=false; 102 propBand = 1.8; 103 integralTime=128; 104 derivativeTime=32; 105 } 106 107 else if (command.equals("Forward")) 108 { 109 Forward=true; 110 Reverse=false; 111 } 112 113 else if (command.equals("Reverse")) 114 { 115 Forward=false; 116 Reverse=true; 117 } 118 else 119 { 120 Serial.println("bad command"); 121 } 122 Serial.print("Command: "); 123 Serial.println(command); 124 } 125 //analogReference(INTERNAL); 126 LM35_A7();// read LM35 connected to A7 127 LM35_A2();// read LM35 connected to A2 128 //********Manual Fan Speed Setting Code ********************* 129 //analogReference(DEFAULT); 130 Potentiometer(controlAction);// manually set motor speed for OCR1B 131 //*********End of Manual Speed Setting Code***************** 132 133 //********PI Controller Code****************************** 134 if(Reverse==true) 135 { 136 controlAction =true; 137 } 138 else if(Forward==true) 139 { 140 controlAction=false; 141 } 142 if(LM35_1 ==true) 143 { 144 C_Variable=TR_C_Filtered; 145 } 146 else if (LM35_2==true) 147 { 148 C_Variable =TL_C_Filtered; 149 } 150 if(Auto==true ) 151 { 152 heaterSetting=SetpointGenerator();// this establishes the PID Setpoint ... range is 0 to 110 deg C 153 contOutNorm=PID_output(C_Variable/500, heaterSetting/500,propBand, integralTime, derivativeTime, 2000, controlAction); //normalized 0 to 1.0 of PID controller output ... PB=800, Tint = 32, Td=0, interval =100msec 154 if (controlAction==true) 155 { 156 analogWrite(10,255*contOutNorm);// converts PID controller output toa PWM value 157 } 158 else if(controlAction==false) 159 { 160 analogWrite(11,255*contOutNorm);// converts PID controller output toa PWM value 161 } 162 163 lcd.setCursor(0, 3); 164 lcd.print("Set Pt C "); 165 } 166 if (Manual==true ) 167 { 168 potA1=analogRead(A1); 169 if (controlAction==true) 170 { 171 analogWrite(10,((float)potA1/1023*255*2.90));// 2.90 added to compensate for 1.66 volts at top of pot 172 } else if (controlAction==false) 173 { 174 analogWrite(11,((float)potA1/1023*255)); 175 } 176 177 lcd.setCursor(9 , 3); 178 lcd.print(" "); 179 lcd.setCursor(9 , 3); 180 lcd.print (int((float)potA1/1023*100*2.90)); 181 182 lcd.setCursor(0, 3); 183 lcd.print("Manual % "); 184 } 185 //***********End of PID Controller Code********************* 186 187 delay(2000); 188 189 SerialPlotter(contOutNorm);//plot values on Serial plotter 190} 191 192void printText() 193 { 194 195 lcd.setCursor(0, 0); 196 lcd.print("Temp R C "); 197 lcd.setCursor(0, 1); 198 lcd.print("Temp L C "); 199 lcd.setCursor(0, 2); 200 lcd.print("C Out % "); 201 lcd.setCursor(0, 3); 202 lcd.print("Set Pt C "); 203 204 lcd.setCursor(13, 0); 205 lcd.print("P "); 206 lcd.setCursor(13, 1); 207 lcd.print("I "); 208 lcd.setCursor(13, 2); 209 lcd.print("D "); 210 lcd.setCursor(13, 3); 211 lcd.print("Fn% "); 212 } 213void SerialPlotter(float controllerOutput) 214{ 215 if (Auto==true & Manual==false) 216 { 217 Serial.print(150.0);//plot value of potA1, either Set Point or Manual 218 Serial.print(","); 219 Serial.print(0.0);//plot value of potA1, either Set Point or Manual 220 Serial.print(","); 221 Serial.print(((float)potA1*0.4887585));//plot value of potA1, either Set Point or Manual 222 Serial.print(","); 223 Serial.print(TR_C_Filtered);// Plot remote LM35 which is controlled variable 0 to 500 224 Serial.print(","); 225 Serial.println(TL_C_Filtered);// Plot 2'nd LM35 in thermal chamber 0 to 500 226 } 227 228 else if (Manual==true & Auto==false) 229 { 230 Serial.print(150.0);//plot value of potA1, either Set Point or Manual 231 Serial.print(","); 232 Serial.print(0.0);//plot value of potA1, either Set Point or Manual 233 Serial.print(","); 234 Serial.print(int((float)potA1*0.09775*2.90));//plot value of potA1, either Set Point or Manual 235 Serial.print(","); 236 Serial.print(TL_C_Filtered);// Plot remote LM35 which is controlled variable 0 to 500 237 Serial.print(","); 238 Serial.println(TR_C_Filtered);// Plot remote LM35 which is controlled variable 0 to 500 239 240 } 241 242 243 //Serial.println(100*controllerOutput);// Plot controller output 0 to 100% 244 //Serial.println(","); 245 //Serial.print(","); 246 //Serial.print("tempRemote = "); 247 //Serial.print(","); 248 //Serial.println(tempRemote);// Plot remote LM35 which is controlled variable 0 to 110 249 //Serial.print(","); 250 //Serial.print("TR_C_Filtered = "); 251 //Serial.print(","); 252 253 //Serial.print(100*controllerOutput);// Plot controller output 0 to 100% 254 //Serial.print(","); 255 //Serial.print("tempLocal = "); 256 //Serial.print(","); 257 //Serial.println(tempLocal); 258 //Serial.print(","); 259 //Serial.print("TL_C_Filtered = "); 260 //Serial.print(","); 261 262 //Serial.print("potA1 =");//plot value of potA1, either Set Point or Manual 263 //Serial.print(","); 264 //Serial.println(potA1); 265 266 267 268 269} 270void LM35_A2() 271{ 272 tempRemote=analogRead(A2); 273 TR_C=(float)tempRemote*0.4887585; 274 TR_C_Filtered=TR_C_filterFunction(5, 1.0,TR_C, 2000);//filter time constant is first argument in seconds 275 276 lcd.setCursor(9, 0); 277 lcd.print(" "); 278 lcd.setCursor(9, 0); 279 lcd.print((int)TR_C_Filtered); 280} 281void LM35_A7() 282{ 283 tempLocal=analogRead(A7); 284 TL_C= (float)tempLocal*0.4887585; 285 TL_C_Filtered=TL_C_filterFunction(25, 1.0,TL_C, 2000 ); 286 287 lcd.setCursor(9, 1); 288 lcd.print(" "); 289 lcd.setCursor(9, 1); 290 lcd.print((int)TL_C_Filtered); 291 292} 293 294void Potentiometer(bool action)// fan setting 0 to 100% 295{ 296 float speedPercent; 297 potA3=analogRead(A3); 298 299 speedPercent=(float)potA3*100/1023; 300 if (action==false) 301 { 302 analogWrite(10,speedPercent/100*255); 303 } else if (action==true) 304 { 305 analogWrite(11,speedPercent/100*255); 306 } 307 308 lcd.setCursor(17, 3); 309 lcd.print(" "); 310 lcd.setCursor(17, 3); 311 lcd.print ((int) (speedPercent)); 312 313} 314 315float SetpointGenerator()// Set Point 0 to 110 dg C 316{ 317 float setTemp; 318 319 potA1=analogRead(A1); 320 //if (potA1<=300) 321 //{ 322 setTemp=(float)potA1*0.4887585;// generates a temp setpoint of 0 to 500 deg C 323 //setTemp=(float)potA1*0.14174;// generates a temp setpoint of 0 to 145 deg C 324 //.10826 is based upon pot voltage of 0 to 1.092 V or 1016 counts from A/D 325 lcd.setCursor( 9, 3); 326 lcd.print(" "); 327 lcd.setCursor(9 , 3); 328 lcd.print((int)setTemp); 329 return setTemp; 330 //} else 331 /*{ 332 setTemp=146; 333 lcd.setCursor( 9, 3); 334 lcd.print(" "); 335 lcd.setCursor(9 , 3); 336 lcd.print((int)setTemp); 337 return setTemp; 338 }*/ 339 340} 341 342float PID_output(float process, float setpoint, float Prop, float Integ, float deriv, int Interval, bool action) 343{ 344float Er; 345static float Olderror, Cont; 346static int Limiter_Switch; 347static float Integral; 348float derivative; 349float proportional; 350float deltaT; 351float filteredDerivative; 352deltaT=float(Interval)/1000; 353Limiter_Switch = 1; 354//delay(Interval); // Interval in msec is delta t in the integral and derivative calculations 355 356if (action==false) 357 { 358 Er = (process-setpoint);// forward or direct acting 359 } else if (action==true) 360 { 361 Er=(setpoint-process); //reverse acting 362 } 363 364//Limiter switch turns integration OFF if controller is already at 100% output or 0% output 365//Prevents integral windup, where controller keeps integrating when controller output can no longer 366//affect the process. 367// 1 is the interval time in seconds 368 369if ((Cont >= 1 && Er > 0) || (Cont <= 0 && Er < 0) || (Integ >= 3600)) 370 Limiter_Switch = 0; 371else 372 Limiter_Switch = 1; 373 374Integral = Integral + 100 / Prop / Integ * Er *deltaT * Limiter_Switch;// Integral calculator 375derivative = 100 / Prop * deriv * (Er - Olderror) / deltaT;// Derivative calculator 376filteredDerivative=DerivativefilterFunction(5, 1.0,derivative, 1000); 377proportional = 100 / Prop * Er;// Proportional calculator 378 379Cont = proportional + Integral + filteredDerivative; 380Olderror = Er;// remember previous error for deriative calculator 381 382if (Cont > 1) // limit controller output between 0.0 and 1.0 a normalized value 383 Cont = 1; 384 385if (Cont < 0) 386 Cont = 0; 387lcd.setCursor(9 , 2); 388lcd.print(" "); 389lcd.setCursor(9 , 2); 390lcd.print((int)(Cont*100.0)); 391 392lcd.setCursor(15 , 0); 393lcd.print(" "); 394lcd.setCursor(15 , 0); 395lcd.print((int)(proportional*100.0)); 396lcd.setCursor(15 , 1); 397lcd.print(" "); 398lcd.setCursor(15 , 1); 399lcd.print((int)(Integral*100.0)); 400 401lcd.setCursor(15 , 2); 402lcd.print(" "); 403lcd.setCursor(15 , 2); 404lcd.print((int)(filteredDerivative*100.0)); 405/*Serial.println(" *************************************** "); 406Serial.print("Error = "); 407Serial.println(Er); 408Serial.print("setpoint = "); 409Serial.println(setpoint); 410Serial.print("Process = "); 411Serial.println(process); 412Serial.print("Proportional = "); 413Serial.println(proportional); 414Serial.print("Intgral = "); 415Serial.println(Integral); 416Serial.print("Forward = "); 417Serial.println(Forward); 418Serial.print("Reverse = "); 419Serial.println(Reverse);*/ 420 421 422return Cont; 423} 424 425float TR_C_filterFunction(float timeConstant, float processGain,float blockIn, float intervalTime) 426{ 427float static blockOut; 428blockOut=blockOut+(intervalTime/1000/(timeConstant+intervalTime/1000))*(processGain*blockIn-blockOut); 429return blockOut; 430} 431 432float TL_C_filterFunction(float timeConstant, float processGain,float blockIn, float intervalTime) 433{ 434float static blockOut; 435blockOut=blockOut+(intervalTime/1000/(timeConstant+intervalTime/1000))*(processGain*blockIn-blockOut); 436return blockOut; 437} 438 439float DerivativefilterFunction(float timeConstant, float processGain,float blockIn, float intervalTime) 440{ 441float static blockOut; 442blockOut=blockOut+(intervalTime/1000/(timeConstant+intervalTime/1000))*(processGain*blockIn-blockOut); 443return blockOut; 444}
Comments
Only logged in users can leave comments
lenfromtoronto
0 Followers
•0 Projects
Table of contents
Intro
1
0