Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependencies: net 1-wire lpc1768 crypto clock web fram log
boiler.c
00001 #include <string.h> 00002 #include <stdint.h> 00003 #include <stdbool.h> 00004 00005 #include "gpio.h" 00006 #include "mstimer.h" 00007 #include "ds18b20.h" 00008 #include "fram.h" 00009 #include "pwm.h" 00010 #include "log.h" 00011 00012 #define BOILER_PUMP_DIR FIO2DIR(4) // P2.4 == p22 00013 #define BOILER_PUMP_PIN FIO2PIN(4) 00014 #define BOILER_PUMP_SET FIO2SET(4) 00015 #define BOILER_PUMP_CLR FIO2CLR(4) 00016 00017 #define BOILER_CALL_DIR FIO2DIR(5) // P2.5 == p21 00018 #define BOILER_CALL_PIN FIO2PIN(5) 00019 #define BOILER_CALL_SET FIO2SET(5) 00020 #define BOILER_CALL_CLR FIO2CLR(5) 00021 00022 #define PUMP_SPEED_CALLING_AUTO_ONLY -1 00023 #define PUMP_SPEED_CALLING_AUTO_TWEAK -2 00024 00025 #define MAX_SPEED 100 00026 00027 static char* tankRom; static int iTankRom; 00028 static char* outputRom; static int iOutputRom; 00029 static char* returnRom; static int iReturnRom; 00030 00031 static int8_t fullSpeedSecs; static int iFullSpeedSecs; 00032 00033 static int8_t tankSetPoint; static int iTankSetPoint; 00034 static int16_t tankHysteresis; static int iTankHysteresis; 00035 static int16_t _runOnDelta16ths; static int iRunOnResidual; 00036 static uint8_t runOnTime2s; static int iRunOnTime; 00037 00038 static int8_t boilerTarget; static int iBoilerTarget; 00039 static int8_t pumpSpeedCalling; static int iPumpSpeedCalling; 00040 static int8_t _rampDownTime; static int _iRampDownTime; 00041 00042 static int8_t _minSpeed; static int _iMinSpeed; 00043 static int8_t _midSpeedPwm; static int _iMidSpeedPwm; 00044 static int16_t _fullSpeedDeltaT16ths; static int _iFullSpeedDeltaT; 00045 00046 //Set in main scan 00047 static int16_t _boilerOutput16ths = DS18B20_ERROR_VALUE_NOT_SET; 00048 static int16_t _boilerReturn16ths = DS18B20_ERROR_VALUE_NOT_SET; 00049 static int16_t _boilerRtnDel16ths = DS18B20_ERROR_VALUE_NOT_SET; 00050 static int16_t _boilerDeltaT16ths = DS18B20_ERROR_VALUE_NOT_SET; 00051 static bool _boilerDeltaTisValid = false; 00052 00053 int16_t BoilerGetTankDS18B20Value () { return DS18B20ValueFromRom(tankRom); } 00054 int16_t BoilerGetOutputDS18B20Value() { return _boilerOutput16ths; } 00055 int16_t BoilerGetReturnDS18B20Value() { return _boilerReturn16ths; } 00056 int16_t BoilerGetRtnDelDS18B20Value() { return _boilerRtnDel16ths; } 00057 int16_t BoilerGetDeltaTDS18B20Value() { return _boilerDeltaT16ths; } 00058 int BoilerGetFullSpeedSecs () { return fullSpeedSecs; } 00059 int BoilerGetTankSetPoint () { return tankSetPoint; } 00060 int BoilerGetTankHysteresis () { return tankHysteresis; } 00061 int BoilerGetRunOnDeltaT () { return _runOnDelta16ths; } 00062 int BoilerGetRunOnTime () { return runOnTime2s << 1; } 00063 int BoilerGetPumpSpeedCalling () { return pumpSpeedCalling; } 00064 int BoilerGetRampDownTime () { return _rampDownTime; } 00065 int BoilerGetOutputTarget () { return boilerTarget; } 00066 int BoilerGetMinSpeed () { return _minSpeed; } 00067 int BoilerGetMidSpeedPwm () { return _midSpeedPwm; } 00068 int BoilerGetFullSpeedDeltaT () { return _fullSpeedDeltaT16ths; } 00069 00070 static void setTankRom (char* value) { memcpy(tankRom, value, 8); FramWrite(iTankRom, 8, tankRom ); } 00071 static void setOutputRom (char* value) { memcpy(outputRom, value, 8); FramWrite(iOutputRom, 8, outputRom ); } 00072 static void setReturnRom (char* value) { memcpy(returnRom, value, 8); FramWrite(iReturnRom, 8, returnRom ); } 00073 void BoilerSetFullSpeedSecs (int value) { fullSpeedSecs = value; FramWrite(iFullSpeedSecs, 1, &fullSpeedSecs ); } 00074 void BoilerSetTankSetPoint (int value) { tankSetPoint = value; FramWrite(iTankSetPoint, 1, &tankSetPoint ); } 00075 void BoilerSetTankHysteresis (int value) { tankHysteresis = value; FramWrite(iTankHysteresis, 2, &tankHysteresis ); } 00076 void BoilerSetRunOnDeltaT (int value) { _runOnDelta16ths = value; FramWrite(iRunOnResidual, 2, &_runOnDelta16ths ); } 00077 void BoilerSetRunOnTime (int value) { runOnTime2s = value >> 1;FramWrite(iRunOnTime, 1, &runOnTime2s ); } 00078 void BoilerSetPumpSpeedCalling (int value) { pumpSpeedCalling = value; FramWrite(iPumpSpeedCalling,1, &pumpSpeedCalling ); } 00079 void BoilerSetRampDownTime (int value) { _rampDownTime = value; FramWrite(_iRampDownTime, 1, &_rampDownTime ); } 00080 void BoilerSetOutputTarget (int value) { boilerTarget = value; FramWrite(iBoilerTarget, 1, &boilerTarget ); } 00081 void BoilerSetMinSpeed (int value) { _minSpeed = value; FramWrite(_iMinSpeed, 1, &_minSpeed ); } 00082 void BoilerSetMidSpeedPwm (int value) { _midSpeedPwm = value; FramWrite(_iMidSpeedPwm, 1, &_midSpeedPwm ); } 00083 void BoilerSetFullSpeedDeltaT (int value) { _fullSpeedDeltaT16ths = value; FramWrite(_iFullSpeedDeltaT,2, &_fullSpeedDeltaT16ths); } 00084 00085 static int calculateBetweenTwoPoints(int x, int xA, int xB, int yA, int yB) 00086 { 00087 float m = (float)(yB - yA) / (xB - xA); 00088 return yA + m * (x - xA); 00089 } 00090 static int calculateSpeedFromDeltaT(int deltaT16ths) 00091 { 00092 if (deltaT16ths < _fullSpeedDeltaT16ths) return MAX_SPEED; //Needed in case deltaT16ths is negative or zero 00093 int speed = MAX_SPEED * _fullSpeedDeltaT16ths / deltaT16ths; //eg for 20 deg ==> 100 * (10 << 4) / (20 << 4) == 50 00094 if (speed > MAX_SPEED) speed = MAX_SPEED; 00095 if (speed < _minSpeed) speed = _minSpeed; 00096 return speed; 00097 } 00098 static int calculateDeltaTFromSpeed(int speed) 00099 { 00100 int deltaT16ths = MAX_SPEED * _fullSpeedDeltaT16ths / speed; //eg for speed = 50 ==> 100 * (10 << 4) / 50 == 20 << 4 00101 return deltaT16ths; 00102 } 00103 00104 int BoilerInit() 00105 { 00106 tankRom = DS18B20Roms + 8 * DS18B20RomCount; 00107 DS18B20RomSetters[DS18B20RomCount] = setTankRom; 00108 DS18B20RomNames[DS18B20RomCount] = "Tank"; 00109 DS18B20RomCount++; 00110 00111 outputRom = DS18B20Roms + 8 * DS18B20RomCount; 00112 DS18B20RomSetters[DS18B20RomCount] = setOutputRom; 00113 DS18B20RomNames[DS18B20RomCount] = "BlrOut"; 00114 DS18B20RomCount++; 00115 00116 returnRom = DS18B20Roms + 8 * DS18B20RomCount; 00117 DS18B20RomSetters[DS18B20RomCount] = setReturnRom; 00118 DS18B20RomNames[DS18B20RomCount] = "BlrRtn"; 00119 DS18B20RomCount++; 00120 00121 int address; 00122 uint8_t def1; 00123 int16_t def2; 00124 int32_t def4; 00125 address = FramLoad( 8, tankRom, 0); if (address < 0) return -1; iTankRom = address; 00126 address = FramLoad( 8, outputRom, 0); if (address < 0) return -1; iOutputRom = address; 00127 address = FramLoad( 8, returnRom, 0); if (address < 0) return -1; iReturnRom = address; 00128 def1 = 100; address = FramLoad( 1, &fullSpeedSecs, &def1); if (address < 0) return -1; iFullSpeedSecs = address; 00129 def1 = 65; address = FramLoad( 1, &tankSetPoint, &def1); if (address < 0) return -1; iTankSetPoint = address; 00130 def2 = 5; address = FramLoad( 2, &tankHysteresis, &def2); if (address < 0) return -1; iTankHysteresis = address; 00131 def2 = 2; address = FramLoad( 2, &_runOnDelta16ths, &def2); if (address < 0) return -1; iRunOnResidual = address; 00132 def1 = 180; address = FramLoad( 1, &runOnTime2s, &def1); if (address < 0) return -1; iRunOnTime = address; 00133 def1 = 100; address = FramLoad( 1, &pumpSpeedCalling, &def1); if (address < 0) return -1; iPumpSpeedCalling = address; 00134 def1 = 10; address = FramLoad( 1, &_rampDownTime, &def1); if (address < 0) return -1; _iRampDownTime = address; 00135 def1 = 65; address = FramLoad( 1, &boilerTarget, &def1); if (address < 0) return -1; iBoilerTarget = address; 00136 def1 = 50; address = FramLoad( 1, &_minSpeed, &def1); if (address < 0) return -1; _iMinSpeed = address; 00137 FramAllocate(1); 00138 def1 = 50; address = FramLoad( 1, &_midSpeedPwm, &def1); if (address < 0) return -1; _iMidSpeedPwm = address; 00139 FramAllocate(1); 00140 def2 = 10<<4; address = FramLoad( 2, &_fullSpeedDeltaT16ths, &def2); if (address < 0) return -1; _iFullSpeedDeltaT = address; 00141 00142 BOILER_PUMP_DIR = 1; //Set the direction to 1 == output 00143 BOILER_CALL_DIR = 1; //Set the direction to 1 == output 00144 00145 PwmInit(400, 100); 00146 00147 return 0; 00148 } 00149 bool BoilerCallEnable = true; 00150 bool BoilerCall = false; 00151 static void controlBoilerCall() 00152 { 00153 if (BoilerCallEnable) 00154 { 00155 int tankTemp16ths = DS18B20ValueFromRom(tankRom); 00156 if (DS18B20IsValidValue(tankTemp16ths)) //Ignore values which are likely to be wrong 00157 { 00158 int tankUpper16ths = tankSetPoint << 4; 00159 int hysteresis16ths = tankHysteresis << 4; 00160 int tankLower16ths = tankUpper16ths - hysteresis16ths; 00161 00162 if (tankTemp16ths >= tankUpper16ths) BoilerCall = false; 00163 if (tankTemp16ths <= tankLower16ths) BoilerCall = true; 00164 } 00165 } 00166 else 00167 { 00168 BoilerCall = false; 00169 } 00170 } 00171 bool BoilerPump = false; 00172 static void controlBoilerPump() 00173 { 00174 static uint32_t msTimerBoilerPumpRunOn = 0; 00175 if (BoilerCall) 00176 { 00177 BoilerPump = true; 00178 msTimerBoilerPumpRunOn = MsTimerCount; 00179 } 00180 else 00181 { 00182 if (MsTimerRelative(msTimerBoilerPumpRunOn, runOnTime2s * 2000)) BoilerPump = false; 00183 if (_boilerDeltaTisValid && _boilerDeltaT16ths < _runOnDelta16ths ) BoilerPump = false; 00184 } 00185 } 00186 int BoilerPumpFlow = MAX_SPEED; 00187 int BoilerPumpSpeed = MAX_SPEED; 00188 int BoilerPumpPwm = 0; 00189 static int _autoSpeed = 0; 00190 static void calculateAutoSpeed() 00191 { 00192 if (!DS18B20IsValidValue(_boilerReturn16ths)) return; 00193 00194 int target16ths = (int)boilerTarget << 4; 00195 int targetRise16ths = target16ths - _boilerReturn16ths; //eg 65 - eg 45 = 20*16 16ths 00196 00197 _autoSpeed = calculateSpeedFromDeltaT(targetRise16ths); 00198 } 00199 static void controlBoilerPumpSpeed() 00200 { 00201 static uint32_t msTimerReduction = 0; 00202 calculateAutoSpeed(); 00203 if (BoilerCall) 00204 { 00205 if (pumpSpeedCalling < 0) BoilerPumpSpeed = _autoSpeed; //Auto 00206 else BoilerPumpSpeed = pumpSpeedCalling; //Manual 00207 msTimerReduction = MsTimerCount; 00208 } 00209 else 00210 { 00211 if (BoilerPumpSpeed > _minSpeed) 00212 { 00213 int msPerUnit = 1000 * _rampDownTime / (MAX_SPEED - _minSpeed); 00214 if (MsTimerRepetitive(&msTimerReduction, msPerUnit)) BoilerPumpSpeed--; 00215 } 00216 else 00217 { 00218 BoilerPumpSpeed = _minSpeed; 00219 } 00220 } 00221 if (BoilerPumpSpeed < _minSpeed) BoilerPumpSpeed = _minSpeed; 00222 if (BoilerPumpSpeed > MAX_SPEED) BoilerPumpSpeed = MAX_SPEED; 00223 } 00224 static int speedToPwm(int speed) 00225 { 00226 #define MAX_SPEED_PWM 10 00227 #define MIN_SPEED_PWM 84 00228 /* 00229 PWM input signal [%] Pump status 00230 ≤ 10 Maximum speed 00231 > 10 / ≤ 84 Variable speed from minimum to maximum 00232 speed 00233 > 84 / ≤ 91 Minimum speed 00234 > 91/95 Hysteresis area: on/off 00235 > 95 / ≤ 100 Standby mode: off 00236 00237 Max speed 100 is at fitted = 74; pwm = 10 00238 Min speed 0 is at fitted = 0; pwm = 84 00239 */ 00240 if (speed <= _minSpeed) return MIN_SPEED_PWM; 00241 if (speed >= MAX_SPEED) return MAX_SPEED_PWM; 00242 int midSpeed = (_minSpeed + MAX_SPEED) / 2; 00243 if (speed < midSpeed) return calculateBetweenTwoPoints(speed, _minSpeed, midSpeed, MIN_SPEED_PWM, _midSpeedPwm); 00244 else return calculateBetweenTwoPoints(speed, midSpeed, MAX_SPEED, _midSpeedPwm, MAX_SPEED_PWM); 00245 //int pwm = calculateBetweenTwoPoints(BoilerPumpSpeed, _minSpeed, MAX_SPEED, 84, 10); 00246 //if (pwm < 10) pwm = 10; 00247 //if (pwm > 84) pwm = 84; 00248 //BoilerPumpPwm = pwm; 00249 } 00250 #define TIME_BEFORE_TWEAK_SECS 120 00251 static void tweakDeltaTs() 00252 { 00253 if (pumpSpeedCalling != PUMP_SPEED_CALLING_AUTO_TWEAK) return; 00254 00255 static uint32_t msTimerBoilerHeating = 0; 00256 if (!BoilerCall) msTimerBoilerHeating = MsTimerCount; 00257 if (!MsTimerRelative(msTimerBoilerHeating, TIME_BEFORE_TWEAK_SECS * 1000)) return; 00258 00259 if (!_boilerDeltaTisValid) return; 00260 00261 static int speedLastScan = -1; 00262 00263 if (speedLastScan < MAX_SPEED && BoilerPumpSpeed == MAX_SPEED) 00264 { 00265 if (_fullSpeedDeltaT16ths > _boilerDeltaT16ths) _fullSpeedDeltaT16ths--; 00266 if (_fullSpeedDeltaT16ths < _boilerDeltaT16ths) _fullSpeedDeltaT16ths++; 00267 } 00268 00269 speedLastScan = BoilerPumpSpeed; 00270 } 00271 00272 #define TIME_BEFORE_DELTA_T_ALARM_SECS 300 00273 #define DELTA_T_LIMIT (3 << 4) 00274 static void checkDeltaTs() 00275 { 00276 static uint32_t msTimerDeltaTNonConform = 0; 00277 if (!BoilerCall) 00278 { 00279 msTimerDeltaTNonConform = MsTimerCount; 00280 return; 00281 } 00282 00283 int expectedDeltaT16ths = calculateDeltaTFromSpeed(BoilerPumpSpeed); 00284 00285 bool deltaTisOk = _boilerDeltaTisValid && 00286 _boilerDeltaT16ths > (expectedDeltaT16ths - DELTA_T_LIMIT) && 00287 _boilerDeltaT16ths < (expectedDeltaT16ths + DELTA_T_LIMIT); 00288 00289 00290 static bool deltaTwasOk = true; 00291 00292 /* 00293 if (deltaTwasOk != deltaTisOk) 00294 { 00295 LogTimeF("Boiler delta T "); 00296 DS18B20Log(_boilerDeltaT16ths); 00297 if (deltaTisOk) 00298 { 00299 Log(" is inside expected value "); 00300 } 00301 else 00302 { 00303 Log(" is outside expected value "); 00304 } 00305 DS18B20Log(expectedDeltaT16ths); 00306 Log("\r\n"); 00307 } 00308 00309 deltaTwasOk = deltaTisOk; 00310 */ 00311 00312 static bool hadAlarm = false; 00313 if (deltaTisOk) msTimerDeltaTNonConform = MsTimerCount; 00314 bool haveAlarm = MsTimerRelative(msTimerDeltaTNonConform, TIME_BEFORE_DELTA_T_ALARM_SECS * 1000); 00315 if (haveAlarm && !hadAlarm) 00316 { 00317 LogTimeF("Boiler delta T would have tripped after not being ok for %d seconds\r\n", TIME_BEFORE_DELTA_T_ALARM_SECS); 00318 } 00319 hadAlarm = haveAlarm; 00320 } 00321 #define NUMBER_OF_STEPS 10 00322 static int16_t _returns16ths[NUMBER_OF_STEPS]; //0 is last, 9th is first 00323 static void delayLine() 00324 { 00325 static uint32_t msTimerDelay = 0; 00326 if (BoilerPump) 00327 { 00328 int msTotal = 1000 * fullSpeedSecs * MAX_SPEED / BoilerPumpSpeed; //speed 10 ==> 10000; speed 100 ==> 1000 00329 int msPerStep = msTotal / NUMBER_OF_STEPS; 00330 if (MsTimerRelative(msTimerDelay, msPerStep)) 00331 { 00332 for (int i = 0; i < NUMBER_OF_STEPS - 1; i++) _returns16ths[i] = _returns16ths[i + 1]; 00333 _returns16ths[NUMBER_OF_STEPS - 1] = _boilerReturn16ths; 00334 msTimerDelay = MsTimerCount; 00335 //LogTimeF("Ms per step = %d, delayed boiler return = ", msPerStep); 00336 //DS18B20Log(_returns16ths[0]); 00337 //Log("\r\n"); 00338 } 00339 } 00340 else 00341 { 00342 msTimerDelay = MsTimerCount; 00343 for (int i = 0; i < NUMBER_OF_STEPS; i++) _returns16ths[i] = DS18B20_ERROR_VALUE_NOT_SET; 00344 } 00345 } 00346 00347 void BoilerMain() 00348 { 00349 delayLine(); 00350 _boilerOutput16ths = DS18B20ValueFromRom(outputRom); 00351 _boilerReturn16ths = DS18B20ValueFromRom(returnRom); 00352 _boilerRtnDel16ths = _returns16ths[0]; 00353 _boilerDeltaTisValid = DS18B20IsValidValue(_boilerOutput16ths) && DS18B20IsValidValue(_boilerRtnDel16ths); 00354 if (_boilerDeltaTisValid) _boilerDeltaT16ths = _boilerOutput16ths - _boilerRtnDel16ths; 00355 else _boilerDeltaT16ths = DS18B20_ERROR_VALUE_NOT_SET; 00356 00357 controlBoilerCall(); 00358 if (BoilerCall) BOILER_CALL_SET; 00359 else BOILER_CALL_CLR; 00360 00361 controlBoilerPump(); 00362 if (BoilerPump) BOILER_PUMP_SET; 00363 else BOILER_PUMP_CLR; 00364 00365 controlBoilerPumpSpeed(); 00366 BoilerPumpPwm = speedToPwm(BoilerPumpSpeed); 00367 PwmSet(BoilerPumpPwm); 00368 00369 tweakDeltaTs(); 00370 checkDeltaTs(); 00371 }
Generated on Tue Jul 12 2022 18:50:15 by
