Controls the central heating system and the lights.
Dependencies: 1-wire clock crypto fram log lpc1768 net web wiz mbed
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 "settings.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; 00028 static char* outputRom; 00029 static char* returnRom; 00030 00031 static int8_t fullSpeedSecs; 00032 00033 static int8_t tankSetPoint; 00034 static int16_t tankHysteresis; 00035 static int16_t _runOnDelta16ths; 00036 static uint8_t runOnTime2s; 00037 00038 static int8_t pumpSpeedCalling; 00039 static int8_t _rampDownTime; 00040 static int8_t boilerTarget; 00041 00042 static int8_t _minSpeed; 00043 static int8_t _midSpeedPwm; 00044 static int16_t _fullSpeedDeltaT16ths; 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); SetTankRom ( tankRom ); } 00071 static void setOutputRom (char* value) { memcpy(outputRom, value, 8); SetOutputRom ( outputRom ); } 00072 static void setReturnRom (char* value) { memcpy(returnRom, value, 8); SetReturnRom ( returnRom ); } 00073 void BoilerSetFullSpeedSecs (int value) { fullSpeedSecs = value; SetBoilerFullSpeedSecs (&fullSpeedSecs ); } 00074 void BoilerSetTankSetPoint (int value) { tankSetPoint = value; SetTankSetPoint (&tankSetPoint ); } 00075 void BoilerSetTankHysteresis (int value) { tankHysteresis = value; SetTankHysteresis (&tankHysteresis ); } 00076 void BoilerSetRunOnDeltaT (int value) { _runOnDelta16ths = value; SetBoilerRunOnDeltaT (&_runOnDelta16ths ); } 00077 void BoilerSetRunOnTime (int value) { runOnTime2s = value >> 1; SetBoilerRunOnTime2s (&runOnTime2s ); } 00078 void BoilerSetPumpSpeedCalling (int value) { pumpSpeedCalling = value; SetBoilerPumpSpeedCalling(&pumpSpeedCalling ); } 00079 void BoilerSetRampDownTime (int value) { _rampDownTime = value; SetBoilerRampDownTime (&_rampDownTime ); } 00080 void BoilerSetOutputTarget (int value) { boilerTarget = value; SetBoilerTarget (&boilerTarget ); } 00081 void BoilerSetMinSpeed (int value) { _minSpeed = value; SetBoilerMinSpeed (&_minSpeed ); } 00082 void BoilerSetMidSpeedPwm (int value) { _midSpeedPwm = value; SetBoilerMidSpeedPwm (&_midSpeedPwm ); } 00083 void BoilerSetFullSpeedDeltaT (int value) { _fullSpeedDeltaT16ths = value; SetBoilerFullSpeedDeltaT (&_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 GetTankRom ( tankRom ); 00126 GetOutputRom ( outputRom ); 00127 GetReturnRom ( returnRom ); 00128 GetBoilerFullSpeedSecs (&fullSpeedSecs ); 00129 GetTankSetPoint (&tankSetPoint ); 00130 GetTankHysteresis (&tankHysteresis ); 00131 GetBoilerRunOnDeltaT (&_runOnDelta16ths ); 00132 GetBoilerRunOnTime2s (&runOnTime2s ); 00133 GetBoilerPumpSpeedCalling(&pumpSpeedCalling ); 00134 GetBoilerRampDownTime (&_rampDownTime ); 00135 GetBoilerTarget (&boilerTarget ); 00136 GetBoilerMinSpeed (&_minSpeed ); 00137 GetBoilerMidSpeedPwm (&_midSpeedPwm ); 00138 GetBoilerFullSpeedDeltaT (&_fullSpeedDeltaT16ths); 00139 00140 BOILER_PUMP_DIR = 1; //Set the direction to 1 == output 00141 BOILER_CALL_DIR = 1; //Set the direction to 1 == output 00142 00143 PwmInit(400, 100); 00144 00145 return 0; 00146 } 00147 bool BoilerCallEnable = true; 00148 bool BoilerCall = false; 00149 static void controlBoilerCall() 00150 { 00151 if (BoilerCallEnable) 00152 { 00153 int tankTemp16ths = DS18B20ValueFromRom(tankRom); 00154 if (DS18B20IsValidValue(tankTemp16ths)) //Ignore values which are likely to be wrong 00155 { 00156 int tankUpper16ths = tankSetPoint << 4; 00157 int hysteresis16ths = tankHysteresis << 4; 00158 int tankLower16ths = tankUpper16ths - hysteresis16ths; 00159 00160 if (tankTemp16ths >= tankUpper16ths) BoilerCall = false; 00161 if (tankTemp16ths <= tankLower16ths) BoilerCall = true; 00162 } 00163 } 00164 else 00165 { 00166 BoilerCall = false; 00167 } 00168 } 00169 bool BoilerPump = false; 00170 static void controlBoilerPump() 00171 { 00172 static uint32_t msTimerBoilerPumpRunOn = 0; 00173 if (BoilerCall) 00174 { 00175 BoilerPump = true; 00176 msTimerBoilerPumpRunOn = MsTimerCount; 00177 } 00178 else 00179 { 00180 if (MsTimerRelative(msTimerBoilerPumpRunOn, runOnTime2s * 2000)) BoilerPump = false; 00181 if (_boilerDeltaTisValid && _boilerDeltaT16ths < _runOnDelta16ths ) BoilerPump = false; 00182 } 00183 } 00184 int BoilerPumpFlow = MAX_SPEED; 00185 int BoilerPumpSpeed = MAX_SPEED; 00186 int BoilerPumpPwm = 0; 00187 static int _autoSpeed = 0; 00188 static void calculateAutoSpeed() 00189 { 00190 if (!DS18B20IsValidValue(_boilerReturn16ths)) return; 00191 00192 int target16ths = (int)boilerTarget << 4; 00193 int targetRise16ths = target16ths - _boilerReturn16ths; //eg 65 - eg 45 = 20*16 16ths 00194 00195 _autoSpeed = calculateSpeedFromDeltaT(targetRise16ths); 00196 } 00197 static void controlBoilerPumpSpeed() 00198 { 00199 static uint32_t msTimerReduction = 0; 00200 calculateAutoSpeed(); 00201 if (BoilerCall) 00202 { 00203 if (pumpSpeedCalling < 0) BoilerPumpSpeed = _autoSpeed; //Auto 00204 else BoilerPumpSpeed = pumpSpeedCalling; //Manual 00205 msTimerReduction = MsTimerCount; 00206 } 00207 else 00208 { 00209 if (BoilerPumpSpeed > _minSpeed) 00210 { 00211 int msPerUnit = 1000 * _rampDownTime / (MAX_SPEED - _minSpeed); 00212 if (MsTimerRepetitive(&msTimerReduction, msPerUnit)) BoilerPumpSpeed--; 00213 } 00214 else 00215 { 00216 BoilerPumpSpeed = _minSpeed; 00217 } 00218 } 00219 if (BoilerPumpSpeed < _minSpeed) BoilerPumpSpeed = _minSpeed; 00220 if (BoilerPumpSpeed > MAX_SPEED) BoilerPumpSpeed = MAX_SPEED; 00221 } 00222 static int speedToPwm(int speed) 00223 { 00224 #define MAX_SPEED_PWM 10 00225 #define MIN_SPEED_PWM 84 00226 /* 00227 PWM input signal [%] Pump status 00228 ≤ 10 Maximum speed 00229 > 10 / ≤ 84 Variable speed from minimum to maximum 00230 speed 00231 > 84 / ≤ 91 Minimum speed 00232 > 91/95 Hysteresis area: on/off 00233 > 95 / ≤ 100 Standby mode: off 00234 00235 Max speed 100 is at fitted = 74; pwm = 10 00236 Min speed 0 is at fitted = 0; pwm = 84 00237 */ 00238 if (speed <= _minSpeed) return MIN_SPEED_PWM; 00239 if (speed >= MAX_SPEED) return MAX_SPEED_PWM; 00240 int midSpeed = (_minSpeed + MAX_SPEED) / 2; 00241 if (speed < midSpeed) return calculateBetweenTwoPoints(speed, _minSpeed, midSpeed, MIN_SPEED_PWM, _midSpeedPwm); 00242 else return calculateBetweenTwoPoints(speed, midSpeed, MAX_SPEED, _midSpeedPwm, MAX_SPEED_PWM); 00243 //int pwm = calculateBetweenTwoPoints(BoilerPumpSpeed, _minSpeed, MAX_SPEED, 84, 10); 00244 //if (pwm < 10) pwm = 10; 00245 //if (pwm > 84) pwm = 84; 00246 //BoilerPumpPwm = pwm; 00247 } 00248 #define TIME_BEFORE_TWEAK_SECS 120 00249 static void tweakDeltaTs() 00250 { 00251 if (pumpSpeedCalling != PUMP_SPEED_CALLING_AUTO_TWEAK) return; 00252 00253 static uint32_t msTimerBoilerHeating = 0; 00254 if (!BoilerCall) msTimerBoilerHeating = MsTimerCount; 00255 if (!MsTimerRelative(msTimerBoilerHeating, TIME_BEFORE_TWEAK_SECS * 1000)) return; 00256 00257 if (!_boilerDeltaTisValid) return; 00258 00259 static int speedLastScan = -1; 00260 00261 if (speedLastScan < MAX_SPEED && BoilerPumpSpeed == MAX_SPEED) 00262 { 00263 if (_fullSpeedDeltaT16ths > _boilerDeltaT16ths) _fullSpeedDeltaT16ths--; 00264 if (_fullSpeedDeltaT16ths < _boilerDeltaT16ths) _fullSpeedDeltaT16ths++; 00265 } 00266 00267 speedLastScan = BoilerPumpSpeed; 00268 } 00269 00270 #define TIME_BEFORE_DELTA_T_ALARM_SECS 300 00271 #define DELTA_T_LIMIT 3 00272 static void checkDeltaTs() 00273 { 00274 static uint32_t msTimerDeltaTNonConform = 0; 00275 if (!BoilerCall) 00276 { 00277 msTimerDeltaTNonConform = MsTimerCount; 00278 return; 00279 } 00280 00281 int expectedDeltaT16ths = calculateDeltaTFromSpeed(BoilerPumpSpeed); 00282 00283 bool deltaTisOk = _boilerDeltaTisValid && 00284 _boilerDeltaT16ths > (expectedDeltaT16ths - (DELTA_T_LIMIT << 4)) && 00285 _boilerDeltaT16ths < (expectedDeltaT16ths + (DELTA_T_LIMIT << 4)); 00286 00287 static bool hadAlarm = false; 00288 if (deltaTisOk) msTimerDeltaTNonConform = MsTimerCount; 00289 bool haveAlarm = MsTimerRelative(msTimerDeltaTNonConform, TIME_BEFORE_DELTA_T_ALARM_SECS * 1000); 00290 if (haveAlarm && !hadAlarm) 00291 { 00292 //BoilerCallEnable = false; 00293 LogTimeF("Boiler disabled - delta T was outside %d degree window for %d seconds", DELTA_T_LIMIT, TIME_BEFORE_DELTA_T_ALARM_SECS); 00294 Log(": actual "); 00295 DS18B20Log(_boilerDeltaT16ths); 00296 Log(", expected "); 00297 DS18B20Log(expectedDeltaT16ths); 00298 Log("\r\n"); 00299 } 00300 hadAlarm = haveAlarm; 00301 } 00302 #define NUMBER_OF_STEPS 10 00303 static int16_t _returns16ths[NUMBER_OF_STEPS]; //0 is last, 9th is first 00304 static void delayLine() 00305 { 00306 static uint32_t msTimerDelay = 0; 00307 if (BoilerPump) 00308 { 00309 int msTotal = 1000 * fullSpeedSecs * MAX_SPEED / BoilerPumpSpeed; //speed 10 ==> 10000; speed 100 ==> 1000 00310 int msPerStep = msTotal / NUMBER_OF_STEPS; 00311 if (MsTimerRelative(msTimerDelay, msPerStep)) 00312 { 00313 for (int i = 0; i < NUMBER_OF_STEPS - 1; i++) _returns16ths[i] = _returns16ths[i + 1]; 00314 _returns16ths[NUMBER_OF_STEPS - 1] = _boilerReturn16ths; 00315 msTimerDelay = MsTimerCount; 00316 //LogTimeF("Ms per step = %d, delayed boiler return = ", msPerStep); 00317 //DS18B20Log(_returns16ths[0]); 00318 //Log("\r\n"); 00319 } 00320 } 00321 else 00322 { 00323 msTimerDelay = MsTimerCount; 00324 for (int i = 0; i < NUMBER_OF_STEPS; i++) _returns16ths[i] = DS18B20_ERROR_VALUE_NOT_SET; 00325 } 00326 } 00327 00328 void BoilerMain() 00329 { 00330 delayLine(); 00331 _boilerOutput16ths = DS18B20ValueFromRom(outputRom); 00332 _boilerReturn16ths = DS18B20ValueFromRom(returnRom); 00333 _boilerRtnDel16ths = _returns16ths[0]; 00334 _boilerDeltaTisValid = DS18B20IsValidValue(_boilerOutput16ths) && DS18B20IsValidValue(_boilerRtnDel16ths); 00335 if (_boilerDeltaTisValid) _boilerDeltaT16ths = _boilerOutput16ths - _boilerRtnDel16ths; 00336 else _boilerDeltaT16ths = DS18B20_ERROR_VALUE_NOT_SET; 00337 00338 controlBoilerCall(); 00339 if (BoilerCall) BOILER_CALL_SET; 00340 else BOILER_CALL_CLR; 00341 00342 controlBoilerPump(); 00343 if (BoilerPump) BOILER_PUMP_SET; 00344 else BOILER_PUMP_CLR; 00345 00346 controlBoilerPumpSpeed(); 00347 BoilerPumpPwm = speedToPwm(BoilerPumpSpeed); 00348 PwmSet(BoilerPumpPwm); 00349 00350 tweakDeltaTs(); 00351 checkDeltaTs(); 00352 }
Generated on Sat Nov 12 2022 10:03:51 by 1.7.2