Central Heating controller using the real time clock, PHY module for internet, 1-wire interface for temperature sensors, a system log and a configuration file
Dependencies: net 1-wire lpc1768 crypto clock web fram log
/media/uploads/andrewboyson/heating.sch
/media/uploads/andrewboyson/heating.brd
/media/uploads/andrewboyson/eagle.epf
heating/boiler.c@105:1899f7ed17ec, 2021-02-23 (annotated)
- Committer:
- andrewboyson
- Date:
- Tue Feb 23 20:35:07 2021 +0000
- Revision:
- 105:1899f7ed17ec
- Parent:
- 104:46ce1aaf8be7
- Child:
- 106:41ed3ea0bbba
Added ability to set the minimum flow rate and removed the correction to delta T relative to speed. Adding the round circuit time and linked to speed. Next task is to linearize the flow.
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
andrewboyson | 0:3c04f4b47041 | 1 | #include <string.h> |
andrewboyson | 0:3c04f4b47041 | 2 | #include <stdint.h> |
andrewboyson | 0:3c04f4b47041 | 3 | #include <stdbool.h> |
andrewboyson | 0:3c04f4b47041 | 4 | |
andrewboyson | 35:bb8a6d1c034c | 5 | #include "gpio.h" |
andrewboyson | 35:bb8a6d1c034c | 6 | #include "mstimer.h" |
andrewboyson | 1:ccc66fdf858d | 7 | #include "ds18b20.h" |
andrewboyson | 35:bb8a6d1c034c | 8 | #include "fram.h" |
andrewboyson | 104:46ce1aaf8be7 | 9 | #include "pwm.h" |
andrewboyson | 104:46ce1aaf8be7 | 10 | #include "log.h" |
andrewboyson | 0:3c04f4b47041 | 11 | |
andrewboyson | 5:82197a6997fd | 12 | #define BOILER_PUMP_DIR FIO2DIR(4) // P2.4 == p22 |
andrewboyson | 5:82197a6997fd | 13 | #define BOILER_PUMP_PIN FIO2PIN(4) |
andrewboyson | 5:82197a6997fd | 14 | #define BOILER_PUMP_SET FIO2SET(4) |
andrewboyson | 5:82197a6997fd | 15 | #define BOILER_PUMP_CLR FIO2CLR(4) |
andrewboyson | 5:82197a6997fd | 16 | |
andrewboyson | 5:82197a6997fd | 17 | #define BOILER_CALL_DIR FIO2DIR(5) // P2.5 == p21 |
andrewboyson | 5:82197a6997fd | 18 | #define BOILER_CALL_PIN FIO2PIN(5) |
andrewboyson | 5:82197a6997fd | 19 | #define BOILER_CALL_SET FIO2SET(5) |
andrewboyson | 5:82197a6997fd | 20 | #define BOILER_CALL_CLR FIO2CLR(5) |
andrewboyson | 0:3c04f4b47041 | 21 | |
andrewboyson | 105:1899f7ed17ec | 22 | #define PUMP_SPEED_CALLING_AUTO_ONLY -1 |
andrewboyson | 105:1899f7ed17ec | 23 | #define PUMP_SPEED_CALLING_AUTO_TWEAK -2 |
andrewboyson | 105:1899f7ed17ec | 24 | |
andrewboyson | 105:1899f7ed17ec | 25 | #define MIN_SPEED 40 |
andrewboyson | 105:1899f7ed17ec | 26 | #define MAX_SPEED 100 |
andrewboyson | 105:1899f7ed17ec | 27 | |
andrewboyson | 48:6eac12df3ad5 | 28 | static char* tankRom; static int iTankRom; |
andrewboyson | 48:6eac12df3ad5 | 29 | static char* outputRom; static int iOutputRom; |
andrewboyson | 48:6eac12df3ad5 | 30 | static char* returnRom; static int iReturnRom; |
andrewboyson | 0:3c04f4b47041 | 31 | |
andrewboyson | 105:1899f7ed17ec | 32 | static int8_t fullSpeedSecs; static int iFullSpeedSecs; |
andrewboyson | 105:1899f7ed17ec | 33 | |
andrewboyson | 105:1899f7ed17ec | 34 | static int8_t tankSetPoint; static int iTankSetPoint; |
andrewboyson | 104:46ce1aaf8be7 | 35 | static int16_t tankHysteresis; static int iTankHysteresis; |
andrewboyson | 104:46ce1aaf8be7 | 36 | static int16_t runOnResidual16ths; static int iRunOnResidual; |
andrewboyson | 105:1899f7ed17ec | 37 | static uint8_t runOnTime2s; static int iRunOnTime; |
andrewboyson | 104:46ce1aaf8be7 | 38 | |
andrewboyson | 104:46ce1aaf8be7 | 39 | static int8_t boilerTarget; static int iBoilerTarget; |
andrewboyson | 104:46ce1aaf8be7 | 40 | static int8_t pumpSpeedCalling; static int iPumpSpeedCalling; |
andrewboyson | 104:46ce1aaf8be7 | 41 | static int8_t pumpSpeedRunOn; static int iPumpSpeedRunOn; |
andrewboyson | 104:46ce1aaf8be7 | 42 | |
andrewboyson | 104:46ce1aaf8be7 | 43 | static int16_t rise16thsAt0; static int iRiseAt0; |
andrewboyson | 104:46ce1aaf8be7 | 44 | static int16_t rise16thsAt50; static int iRiseAt50; |
andrewboyson | 104:46ce1aaf8be7 | 45 | static int16_t rise16thsAt100; static int iRiseAt100; |
andrewboyson | 0:3c04f4b47041 | 46 | |
andrewboyson | 105:1899f7ed17ec | 47 | //Set in main scan |
andrewboyson | 105:1899f7ed17ec | 48 | static int16_t _boilerOutput16ths = DS18B20_ERROR_VALUE_NOT_SET; |
andrewboyson | 105:1899f7ed17ec | 49 | static int16_t _boilerReturn16ths = DS18B20_ERROR_VALUE_NOT_SET; |
andrewboyson | 105:1899f7ed17ec | 50 | static int16_t _boilerRtnDel16ths = DS18B20_ERROR_VALUE_NOT_SET; |
andrewboyson | 105:1899f7ed17ec | 51 | static int16_t _boilerDeltaT16ths = DS18B20_ERROR_VALUE_NOT_SET; |
andrewboyson | 105:1899f7ed17ec | 52 | static bool _boilerDeltaTisValid = false; |
andrewboyson | 105:1899f7ed17ec | 53 | |
andrewboyson | 105:1899f7ed17ec | 54 | int16_t BoilerGetTankDS18B20Value () { return DS18B20ValueFromRom(tankRom); } |
andrewboyson | 105:1899f7ed17ec | 55 | int16_t BoilerGetOutputDS18B20Value() { return _boilerOutput16ths; } |
andrewboyson | 105:1899f7ed17ec | 56 | int16_t BoilerGetReturnDS18B20Value() { return _boilerReturn16ths; } |
andrewboyson | 105:1899f7ed17ec | 57 | int16_t BoilerGetRtnDelDS18B20Value() { return _boilerRtnDel16ths; } |
andrewboyson | 105:1899f7ed17ec | 58 | int16_t BoilerGetDeltaTDS18B20Value() { return _boilerDeltaT16ths; } |
andrewboyson | 105:1899f7ed17ec | 59 | int BoilerGetFullSpeedSecs () { return fullSpeedSecs; } |
andrewboyson | 105:1899f7ed17ec | 60 | int BoilerGetTankSetPoint () { return tankSetPoint; } |
andrewboyson | 105:1899f7ed17ec | 61 | int BoilerGetTankHysteresis () { return tankHysteresis; } |
andrewboyson | 105:1899f7ed17ec | 62 | int BoilerGetRunOnDeltaT () { return runOnResidual16ths; } |
andrewboyson | 105:1899f7ed17ec | 63 | int BoilerGetRunOnTime () { return runOnTime2s << 1; } |
andrewboyson | 105:1899f7ed17ec | 64 | int BoilerGetPumpSpeedCalling () { return pumpSpeedCalling; } |
andrewboyson | 105:1899f7ed17ec | 65 | int BoilerGetPumpSpeedRunOn () { return pumpSpeedRunOn; } |
andrewboyson | 105:1899f7ed17ec | 66 | int BoilerGetOutputTarget () { return boilerTarget; } |
andrewboyson | 105:1899f7ed17ec | 67 | int BoilerGetMinimumFlow () { return rise16thsAt0; } |
andrewboyson | 105:1899f7ed17ec | 68 | int BoilerGetMidFlowSpeed () { return rise16thsAt50; } |
andrewboyson | 105:1899f7ed17ec | 69 | int BoilerGetFullSpeedDeltaT () { return rise16thsAt100; } |
andrewboyson | 0:3c04f4b47041 | 70 | |
andrewboyson | 91:8b192efd0288 | 71 | static void setTankRom (char* value) { memcpy(tankRom, value, 8); FramWrite(iTankRom, 8, tankRom ); } |
andrewboyson | 91:8b192efd0288 | 72 | static void setOutputRom (char* value) { memcpy(outputRom, value, 8); FramWrite(iOutputRom, 8, outputRom ); } |
andrewboyson | 91:8b192efd0288 | 73 | static void setReturnRom (char* value) { memcpy(returnRom, value, 8); FramWrite(iReturnRom, 8, returnRom ); } |
andrewboyson | 105:1899f7ed17ec | 74 | void BoilerSetFullSpeedSecs (int value) { fullSpeedSecs = value; FramWrite(iFullSpeedSecs, 1, &fullSpeedSecs ); } |
andrewboyson | 105:1899f7ed17ec | 75 | void BoilerSetTankSetPoint (int value) { tankSetPoint = value; FramWrite(iTankSetPoint, 1, &tankSetPoint ); } |
andrewboyson | 104:46ce1aaf8be7 | 76 | void BoilerSetTankHysteresis (int value) { tankHysteresis = value; FramWrite(iTankHysteresis, 2, &tankHysteresis ); } |
andrewboyson | 105:1899f7ed17ec | 77 | void BoilerSetRunOnDeltaT (int value) { runOnResidual16ths = value; FramWrite(iRunOnResidual, 2, &runOnResidual16ths ); } |
andrewboyson | 104:46ce1aaf8be7 | 78 | void BoilerSetRunOnTime (int value) { runOnTime2s = value >> 1;FramWrite(iRunOnTime, 1, &runOnTime2s ); } |
andrewboyson | 104:46ce1aaf8be7 | 79 | void BoilerSetPumpSpeedCalling (int value) { pumpSpeedCalling = value; FramWrite(iPumpSpeedCalling,1, &pumpSpeedCalling ); } |
andrewboyson | 104:46ce1aaf8be7 | 80 | void BoilerSetPumpSpeedRunOn (int value) { pumpSpeedRunOn = value; FramWrite(iPumpSpeedRunOn, 1, &pumpSpeedRunOn ); } |
andrewboyson | 104:46ce1aaf8be7 | 81 | void BoilerSetOutputTarget (int value) { boilerTarget = value; FramWrite(iBoilerTarget, 1, &boilerTarget ); } |
andrewboyson | 105:1899f7ed17ec | 82 | void BoilerSetMinimumFlow (int value) { rise16thsAt0 = value; FramWrite(iRiseAt0, 2, &rise16thsAt0 ); } |
andrewboyson | 105:1899f7ed17ec | 83 | void BoilerSetMidFlowSpeed (int value) { rise16thsAt50 = value; FramWrite(iRiseAt50, 2, &rise16thsAt50 ); } |
andrewboyson | 105:1899f7ed17ec | 84 | void BoilerSetFullSpeedDeltaT (int value) { rise16thsAt100 = value; FramWrite(iRiseAt100, 2, &rise16thsAt100 ); } |
andrewboyson | 104:46ce1aaf8be7 | 85 | |
andrewboyson | 104:46ce1aaf8be7 | 86 | static int calculateBetweenTwoPoints(int x, int xA, int xB, int yA, int yB) |
andrewboyson | 104:46ce1aaf8be7 | 87 | { |
andrewboyson | 104:46ce1aaf8be7 | 88 | float m = (float)(yB - yA) / (xB - xA); |
andrewboyson | 104:46ce1aaf8be7 | 89 | return yA + m * (x - xA); |
andrewboyson | 104:46ce1aaf8be7 | 90 | } |
andrewboyson | 105:1899f7ed17ec | 91 | static int calculateSpeedFromDeltaT(int deltaT16ths) |
andrewboyson | 104:46ce1aaf8be7 | 92 | { |
andrewboyson | 105:1899f7ed17ec | 93 | if (deltaT16ths < rise16thsAt100) return MAX_SPEED; //Needed in case deltaT16ths is negative or zero |
andrewboyson | 105:1899f7ed17ec | 94 | int flow = MAX_SPEED * rise16thsAt100 / deltaT16ths; //eg for 20 deg ==> 100 * (10 << 4) / (20 << 4) == 50 |
andrewboyson | 105:1899f7ed17ec | 95 | if (flow > MAX_SPEED) flow = MAX_SPEED; |
andrewboyson | 105:1899f7ed17ec | 96 | if (flow < MIN_SPEED) flow = MIN_SPEED; |
andrewboyson | 105:1899f7ed17ec | 97 | return flow; |
andrewboyson | 105:1899f7ed17ec | 98 | |
andrewboyson | 105:1899f7ed17ec | 99 | //if (deltaT16ths > rise16thsAt0 ) return MIN_SPEED; |
andrewboyson | 105:1899f7ed17ec | 100 | //else if (deltaT16ths > rise16thsAt50 ) return calculateBetweenTwoPoints(deltaT16ths, rise16thsAt50, rise16thsAt0, MID_SPEED, MIN_SPEED); |
andrewboyson | 105:1899f7ed17ec | 101 | //else if (deltaT16ths > rise16thsAt100) return calculateBetweenTwoPoints(deltaT16ths, rise16thsAt100, rise16thsAt50, MAX_SPEED, MID_SPEED); |
andrewboyson | 105:1899f7ed17ec | 102 | //else return MAX_SPEED; |
andrewboyson | 105:1899f7ed17ec | 103 | } |
andrewboyson | 105:1899f7ed17ec | 104 | static int calculateDeltaTFromSpeed(int speed) |
andrewboyson | 105:1899f7ed17ec | 105 | { |
andrewboyson | 105:1899f7ed17ec | 106 | int deltaT16ths = MAX_SPEED * rise16thsAt100 / speed; //eg for speed = 50 ==> 100 * (10 << 4) / 50 == 20 << 4 |
andrewboyson | 105:1899f7ed17ec | 107 | //if (speed >= MAX_SPEED) return rise16thsAt100; |
andrewboyson | 105:1899f7ed17ec | 108 | //else if (speed > MID_SPEED) return calculateBetweenTwoPoints(speed, MID_SPEED, MAX_SPEED, rise16thsAt50, rise16thsAt100); |
andrewboyson | 105:1899f7ed17ec | 109 | //else if (speed > MIN_SPEED) return calculateBetweenTwoPoints(speed, MIN_SPEED, MID_SPEED, rise16thsAt0, rise16thsAt50 ); |
andrewboyson | 105:1899f7ed17ec | 110 | //else return rise16thsAt0; |
andrewboyson | 105:1899f7ed17ec | 111 | return deltaT16ths; |
andrewboyson | 104:46ce1aaf8be7 | 112 | } |
andrewboyson | 0:3c04f4b47041 | 113 | |
andrewboyson | 0:3c04f4b47041 | 114 | int BoilerInit() |
andrewboyson | 0:3c04f4b47041 | 115 | { |
andrewboyson | 48:6eac12df3ad5 | 116 | tankRom = DS18B20Roms + 8 * DS18B20RomCount; |
andrewboyson | 48:6eac12df3ad5 | 117 | DS18B20RomSetters[DS18B20RomCount] = setTankRom; |
andrewboyson | 48:6eac12df3ad5 | 118 | DS18B20RomNames[DS18B20RomCount] = "Tank"; |
andrewboyson | 48:6eac12df3ad5 | 119 | DS18B20RomCount++; |
andrewboyson | 48:6eac12df3ad5 | 120 | |
andrewboyson | 48:6eac12df3ad5 | 121 | outputRom = DS18B20Roms + 8 * DS18B20RomCount; |
andrewboyson | 48:6eac12df3ad5 | 122 | DS18B20RomSetters[DS18B20RomCount] = setOutputRom; |
andrewboyson | 48:6eac12df3ad5 | 123 | DS18B20RomNames[DS18B20RomCount] = "BlrOut"; |
andrewboyson | 48:6eac12df3ad5 | 124 | DS18B20RomCount++; |
andrewboyson | 48:6eac12df3ad5 | 125 | |
andrewboyson | 48:6eac12df3ad5 | 126 | returnRom = DS18B20Roms + 8 * DS18B20RomCount; |
andrewboyson | 48:6eac12df3ad5 | 127 | DS18B20RomSetters[DS18B20RomCount] = setReturnRom; |
andrewboyson | 48:6eac12df3ad5 | 128 | DS18B20RomNames[DS18B20RomCount] = "BlrRtn"; |
andrewboyson | 48:6eac12df3ad5 | 129 | DS18B20RomCount++; |
andrewboyson | 48:6eac12df3ad5 | 130 | |
andrewboyson | 0:3c04f4b47041 | 131 | int address; |
andrewboyson | 104:46ce1aaf8be7 | 132 | uint8_t def1; |
andrewboyson | 104:46ce1aaf8be7 | 133 | int16_t def2; |
andrewboyson | 0:3c04f4b47041 | 134 | int32_t def4; |
andrewboyson | 104:46ce1aaf8be7 | 135 | address = FramLoad( 8, tankRom, 0); if (address < 0) return -1; iTankRom = address; |
andrewboyson | 104:46ce1aaf8be7 | 136 | address = FramLoad( 8, outputRom, 0); if (address < 0) return -1; iOutputRom = address; |
andrewboyson | 104:46ce1aaf8be7 | 137 | address = FramLoad( 8, returnRom, 0); if (address < 0) return -1; iReturnRom = address; |
andrewboyson | 105:1899f7ed17ec | 138 | def1 = 100; address = FramLoad( 1, &fullSpeedSecs, &def1); if (address < 0) return -1; iFullSpeedSecs = address; |
andrewboyson | 105:1899f7ed17ec | 139 | def1 = 65; address = FramLoad( 1, &tankSetPoint, &def1); if (address < 0) return -1; iTankSetPoint = address; |
andrewboyson | 104:46ce1aaf8be7 | 140 | def2 = 5; address = FramLoad( 2, &tankHysteresis, &def2); if (address < 0) return -1; iTankHysteresis = address; |
andrewboyson | 104:46ce1aaf8be7 | 141 | def2 = 2; address = FramLoad( 2, &runOnResidual16ths, &def2); if (address < 0) return -1; iRunOnResidual = address; |
andrewboyson | 104:46ce1aaf8be7 | 142 | def1 = 180; address = FramLoad( 1, &runOnTime2s, &def1); if (address < 0) return -1; iRunOnTime = address; |
andrewboyson | 104:46ce1aaf8be7 | 143 | def1 = 100; address = FramLoad( 1, &pumpSpeedCalling, &def1); if (address < 0) return -1; iPumpSpeedCalling = address; |
andrewboyson | 104:46ce1aaf8be7 | 144 | def1 = 10; address = FramLoad( 1, &pumpSpeedRunOn, &def1); if (address < 0) return -1; iPumpSpeedRunOn = address; |
andrewboyson | 104:46ce1aaf8be7 | 145 | def1 = 65; address = FramLoad( 1, &boilerTarget, &def1); if (address < 0) return -1; iBoilerTarget = address; |
andrewboyson | 104:46ce1aaf8be7 | 146 | def2 = 10<<4; address = FramLoad( 2, &rise16thsAt0, &def2); if (address < 0) return -1; iRiseAt0 = address; |
andrewboyson | 104:46ce1aaf8be7 | 147 | def2 = 15<<4; address = FramLoad( 2, &rise16thsAt50, &def2); if (address < 0) return -1; iRiseAt50 = address; |
andrewboyson | 104:46ce1aaf8be7 | 148 | def2 = 20<<4; address = FramLoad( 2, &rise16thsAt100, &def2); if (address < 0) return -1; iRiseAt100 = address; |
andrewboyson | 0:3c04f4b47041 | 149 | |
andrewboyson | 5:82197a6997fd | 150 | BOILER_PUMP_DIR = 1; //Set the direction to 1 == output |
andrewboyson | 5:82197a6997fd | 151 | BOILER_CALL_DIR = 1; //Set the direction to 1 == output |
andrewboyson | 48:6eac12df3ad5 | 152 | |
andrewboyson | 104:46ce1aaf8be7 | 153 | PwmInit(400, 100); |
andrewboyson | 104:46ce1aaf8be7 | 154 | |
andrewboyson | 0:3c04f4b47041 | 155 | return 0; |
andrewboyson | 0:3c04f4b47041 | 156 | } |
andrewboyson | 105:1899f7ed17ec | 157 | bool BoilerCallEnable = true; |
andrewboyson | 0:3c04f4b47041 | 158 | bool BoilerCall = false; |
andrewboyson | 35:bb8a6d1c034c | 159 | static void controlBoilerCall() |
andrewboyson | 0:3c04f4b47041 | 160 | { |
andrewboyson | 105:1899f7ed17ec | 161 | if (BoilerCallEnable) |
andrewboyson | 0:3c04f4b47041 | 162 | { |
andrewboyson | 105:1899f7ed17ec | 163 | int tankTemp16ths = DS18B20ValueFromRom(tankRom); |
andrewboyson | 105:1899f7ed17ec | 164 | if (DS18B20IsValidValue(tankTemp16ths)) //Ignore values which are likely to be wrong |
andrewboyson | 105:1899f7ed17ec | 165 | { |
andrewboyson | 105:1899f7ed17ec | 166 | int tankUpper16ths = tankSetPoint << 4; |
andrewboyson | 105:1899f7ed17ec | 167 | int hysteresis16ths = tankHysteresis << 4; |
andrewboyson | 105:1899f7ed17ec | 168 | int tankLower16ths = tankUpper16ths - hysteresis16ths; |
andrewboyson | 105:1899f7ed17ec | 169 | |
andrewboyson | 105:1899f7ed17ec | 170 | if (tankTemp16ths >= tankUpper16ths) BoilerCall = false; |
andrewboyson | 105:1899f7ed17ec | 171 | if (tankTemp16ths <= tankLower16ths) BoilerCall = true; |
andrewboyson | 105:1899f7ed17ec | 172 | } |
andrewboyson | 105:1899f7ed17ec | 173 | } |
andrewboyson | 105:1899f7ed17ec | 174 | else |
andrewboyson | 105:1899f7ed17ec | 175 | { |
andrewboyson | 105:1899f7ed17ec | 176 | BoilerCall = false; |
andrewboyson | 0:3c04f4b47041 | 177 | } |
andrewboyson | 35:bb8a6d1c034c | 178 | } |
andrewboyson | 35:bb8a6d1c034c | 179 | bool BoilerPump = false; |
andrewboyson | 35:bb8a6d1c034c | 180 | static void controlBoilerPump() |
andrewboyson | 35:bb8a6d1c034c | 181 | { |
andrewboyson | 35:bb8a6d1c034c | 182 | static uint32_t msTimerBoilerPumpRunOn = 0; |
andrewboyson | 0:3c04f4b47041 | 183 | if (BoilerCall) |
andrewboyson | 0:3c04f4b47041 | 184 | { |
andrewboyson | 0:3c04f4b47041 | 185 | BoilerPump = true; |
andrewboyson | 35:bb8a6d1c034c | 186 | msTimerBoilerPumpRunOn = MsTimerCount; |
andrewboyson | 0:3c04f4b47041 | 187 | } |
andrewboyson | 0:3c04f4b47041 | 188 | else |
andrewboyson | 0:3c04f4b47041 | 189 | { |
andrewboyson | 104:46ce1aaf8be7 | 190 | if (MsTimerRelative(msTimerBoilerPumpRunOn, runOnTime2s * 2000)) BoilerPump = false; |
andrewboyson | 105:1899f7ed17ec | 191 | if (_boilerDeltaTisValid && _boilerDeltaT16ths < runOnResidual16ths ) BoilerPump = false; |
andrewboyson | 104:46ce1aaf8be7 | 192 | } |
andrewboyson | 104:46ce1aaf8be7 | 193 | } |
andrewboyson | 105:1899f7ed17ec | 194 | int BoilerPumpFlow = MIN_SPEED; |
andrewboyson | 105:1899f7ed17ec | 195 | int BoilerPumpSpeed = MIN_SPEED; |
andrewboyson | 104:46ce1aaf8be7 | 196 | int BoilerPumpPwm = 0; |
andrewboyson | 104:46ce1aaf8be7 | 197 | static int _autoSpeed = 0; |
andrewboyson | 104:46ce1aaf8be7 | 198 | static void calculateAutoSpeed() |
andrewboyson | 104:46ce1aaf8be7 | 199 | { |
andrewboyson | 105:1899f7ed17ec | 200 | if (!DS18B20IsValidValue(_boilerReturn16ths)) return; |
andrewboyson | 104:46ce1aaf8be7 | 201 | |
andrewboyson | 104:46ce1aaf8be7 | 202 | int target16ths = (int)boilerTarget << 4; |
andrewboyson | 105:1899f7ed17ec | 203 | int targetRise16ths = target16ths - _boilerReturn16ths; //eg 65 - eg 45 = 20*16 16ths |
andrewboyson | 104:46ce1aaf8be7 | 204 | |
andrewboyson | 105:1899f7ed17ec | 205 | _autoSpeed = calculateSpeedFromDeltaT(targetRise16ths); |
andrewboyson | 104:46ce1aaf8be7 | 206 | } |
andrewboyson | 104:46ce1aaf8be7 | 207 | static void controlBoilerPumpSpeed() |
andrewboyson | 104:46ce1aaf8be7 | 208 | { |
andrewboyson | 104:46ce1aaf8be7 | 209 | static uint32_t msTimerReduction = 0; |
andrewboyson | 104:46ce1aaf8be7 | 210 | calculateAutoSpeed(); |
andrewboyson | 104:46ce1aaf8be7 | 211 | if (BoilerCall) |
andrewboyson | 104:46ce1aaf8be7 | 212 | { |
andrewboyson | 105:1899f7ed17ec | 213 | if (pumpSpeedCalling > MAX_SPEED || pumpSpeedCalling < MIN_SPEED) BoilerPumpSpeed = _autoSpeed; //Auto |
andrewboyson | 105:1899f7ed17ec | 214 | else BoilerPumpSpeed = pumpSpeedCalling; //Manual |
andrewboyson | 104:46ce1aaf8be7 | 215 | msTimerReduction = MsTimerCount; |
andrewboyson | 104:46ce1aaf8be7 | 216 | } |
andrewboyson | 104:46ce1aaf8be7 | 217 | else |
andrewboyson | 104:46ce1aaf8be7 | 218 | { |
andrewboyson | 104:46ce1aaf8be7 | 219 | if (BoilerPumpSpeed > pumpSpeedRunOn) |
andrewboyson | 104:46ce1aaf8be7 | 220 | { |
andrewboyson | 104:46ce1aaf8be7 | 221 | if (MsTimerRepetitive(&msTimerReduction, 250)) BoilerPumpSpeed--; |
andrewboyson | 104:46ce1aaf8be7 | 222 | } |
andrewboyson | 104:46ce1aaf8be7 | 223 | else |
andrewboyson | 104:46ce1aaf8be7 | 224 | { |
andrewboyson | 104:46ce1aaf8be7 | 225 | BoilerPumpSpeed = pumpSpeedRunOn; |
andrewboyson | 104:46ce1aaf8be7 | 226 | } |
andrewboyson | 0:3c04f4b47041 | 227 | } |
andrewboyson | 35:bb8a6d1c034c | 228 | } |
andrewboyson | 105:1899f7ed17ec | 229 | static void flowToSpeed() |
andrewboyson | 105:1899f7ed17ec | 230 | { |
andrewboyson | 105:1899f7ed17ec | 231 | //Do nothing yet |
andrewboyson | 105:1899f7ed17ec | 232 | } |
andrewboyson | 104:46ce1aaf8be7 | 233 | static void speedToPwm() |
andrewboyson | 104:46ce1aaf8be7 | 234 | { |
andrewboyson | 104:46ce1aaf8be7 | 235 | /* |
andrewboyson | 104:46ce1aaf8be7 | 236 | PWM input signal [%] Pump status |
andrewboyson | 104:46ce1aaf8be7 | 237 | ≤ 10 Maximum speed |
andrewboyson | 104:46ce1aaf8be7 | 238 | > 10 / ≤ 84 Variable speed from minimum to maximum |
andrewboyson | 104:46ce1aaf8be7 | 239 | speed |
andrewboyson | 104:46ce1aaf8be7 | 240 | > 84 / ≤ 91 Minimum speed |
andrewboyson | 104:46ce1aaf8be7 | 241 | > 91/95 Hysteresis area: on/off |
andrewboyson | 104:46ce1aaf8be7 | 242 | > 95 / ≤ 100 Standby mode: off |
andrewboyson | 104:46ce1aaf8be7 | 243 | |
andrewboyson | 104:46ce1aaf8be7 | 244 | Max speed 100 is at fitted = 74; pwm = 10 |
andrewboyson | 104:46ce1aaf8be7 | 245 | Min speed 0 is at fitted = 0; pwm = 84 |
andrewboyson | 104:46ce1aaf8be7 | 246 | */ |
andrewboyson | 105:1899f7ed17ec | 247 | int pwm = calculateBetweenTwoPoints(BoilerPumpSpeed, MIN_SPEED, MAX_SPEED, 84, 10); |
andrewboyson | 105:1899f7ed17ec | 248 | if (pwm < 10) pwm = 10; |
andrewboyson | 105:1899f7ed17ec | 249 | if (pwm > 84) pwm = 84; |
andrewboyson | 105:1899f7ed17ec | 250 | BoilerPumpPwm = pwm; |
andrewboyson | 104:46ce1aaf8be7 | 251 | } |
andrewboyson | 104:46ce1aaf8be7 | 252 | #define TIME_BEFORE_TWEAK_SECS 120 |
andrewboyson | 104:46ce1aaf8be7 | 253 | static void tweakDeltaTs() |
andrewboyson | 104:46ce1aaf8be7 | 254 | { |
andrewboyson | 105:1899f7ed17ec | 255 | if (pumpSpeedCalling != PUMP_SPEED_CALLING_AUTO_TWEAK) return; |
andrewboyson | 105:1899f7ed17ec | 256 | |
andrewboyson | 104:46ce1aaf8be7 | 257 | static uint32_t msTimerBoilerHeating = 0; |
andrewboyson | 104:46ce1aaf8be7 | 258 | if (!BoilerCall) msTimerBoilerHeating = MsTimerCount; |
andrewboyson | 104:46ce1aaf8be7 | 259 | if (!MsTimerRelative(msTimerBoilerHeating, TIME_BEFORE_TWEAK_SECS * 1000)) return; |
andrewboyson | 104:46ce1aaf8be7 | 260 | |
andrewboyson | 105:1899f7ed17ec | 261 | if (!_boilerDeltaTisValid) return; |
andrewboyson | 104:46ce1aaf8be7 | 262 | |
andrewboyson | 104:46ce1aaf8be7 | 263 | static int speedLastScan = -1; |
andrewboyson | 104:46ce1aaf8be7 | 264 | |
andrewboyson | 105:1899f7ed17ec | 265 | if (speedLastScan < MAX_SPEED && BoilerPumpSpeed == MAX_SPEED) |
andrewboyson | 104:46ce1aaf8be7 | 266 | { |
andrewboyson | 105:1899f7ed17ec | 267 | if (rise16thsAt100 > _boilerDeltaT16ths) rise16thsAt100--; |
andrewboyson | 105:1899f7ed17ec | 268 | if (rise16thsAt100 < _boilerDeltaT16ths) rise16thsAt100++; |
andrewboyson | 104:46ce1aaf8be7 | 269 | } |
andrewboyson | 104:46ce1aaf8be7 | 270 | |
andrewboyson | 104:46ce1aaf8be7 | 271 | speedLastScan = BoilerPumpSpeed; |
andrewboyson | 104:46ce1aaf8be7 | 272 | } |
andrewboyson | 105:1899f7ed17ec | 273 | |
andrewboyson | 105:1899f7ed17ec | 274 | #define TIME_BEFORE_DELTA_T_ALARM_SECS 300 |
andrewboyson | 105:1899f7ed17ec | 275 | #define DELTA_T_LIMIT (3 << 4) |
andrewboyson | 105:1899f7ed17ec | 276 | static void checkDeltaTs() |
andrewboyson | 105:1899f7ed17ec | 277 | { |
andrewboyson | 105:1899f7ed17ec | 278 | static uint32_t msTimerDeltaTNonConform = 0; |
andrewboyson | 105:1899f7ed17ec | 279 | if (!BoilerCall) |
andrewboyson | 105:1899f7ed17ec | 280 | { |
andrewboyson | 105:1899f7ed17ec | 281 | msTimerDeltaTNonConform = MsTimerCount; |
andrewboyson | 105:1899f7ed17ec | 282 | return; |
andrewboyson | 105:1899f7ed17ec | 283 | } |
andrewboyson | 105:1899f7ed17ec | 284 | |
andrewboyson | 105:1899f7ed17ec | 285 | int expectedDeltaT16ths = calculateDeltaTFromSpeed(BoilerPumpSpeed); |
andrewboyson | 105:1899f7ed17ec | 286 | |
andrewboyson | 105:1899f7ed17ec | 287 | bool deltaTisOk = _boilerDeltaTisValid && |
andrewboyson | 105:1899f7ed17ec | 288 | _boilerDeltaT16ths > (expectedDeltaT16ths - DELTA_T_LIMIT) && |
andrewboyson | 105:1899f7ed17ec | 289 | _boilerDeltaT16ths < (expectedDeltaT16ths + DELTA_T_LIMIT); |
andrewboyson | 105:1899f7ed17ec | 290 | |
andrewboyson | 105:1899f7ed17ec | 291 | |
andrewboyson | 105:1899f7ed17ec | 292 | static bool deltaTwasOk = true; |
andrewboyson | 105:1899f7ed17ec | 293 | |
andrewboyson | 105:1899f7ed17ec | 294 | /* |
andrewboyson | 105:1899f7ed17ec | 295 | if (deltaTwasOk != deltaTisOk) |
andrewboyson | 105:1899f7ed17ec | 296 | { |
andrewboyson | 105:1899f7ed17ec | 297 | LogTimeF("Boiler delta T "); |
andrewboyson | 105:1899f7ed17ec | 298 | DS18B20Log(_boilerDeltaT16ths); |
andrewboyson | 105:1899f7ed17ec | 299 | if (deltaTisOk) |
andrewboyson | 105:1899f7ed17ec | 300 | { |
andrewboyson | 105:1899f7ed17ec | 301 | Log(" is inside expected value "); |
andrewboyson | 105:1899f7ed17ec | 302 | } |
andrewboyson | 105:1899f7ed17ec | 303 | else |
andrewboyson | 105:1899f7ed17ec | 304 | { |
andrewboyson | 105:1899f7ed17ec | 305 | Log(" is outside expected value "); |
andrewboyson | 105:1899f7ed17ec | 306 | } |
andrewboyson | 105:1899f7ed17ec | 307 | DS18B20Log(expectedDeltaT16ths); |
andrewboyson | 105:1899f7ed17ec | 308 | Log("\r\n"); |
andrewboyson | 105:1899f7ed17ec | 309 | } |
andrewboyson | 105:1899f7ed17ec | 310 | |
andrewboyson | 105:1899f7ed17ec | 311 | deltaTwasOk = deltaTisOk; |
andrewboyson | 105:1899f7ed17ec | 312 | */ |
andrewboyson | 105:1899f7ed17ec | 313 | |
andrewboyson | 105:1899f7ed17ec | 314 | static bool hadAlarm = false; |
andrewboyson | 105:1899f7ed17ec | 315 | if (deltaTisOk) msTimerDeltaTNonConform = MsTimerCount; |
andrewboyson | 105:1899f7ed17ec | 316 | bool haveAlarm = MsTimerRelative(msTimerDeltaTNonConform, TIME_BEFORE_DELTA_T_ALARM_SECS * 1000); |
andrewboyson | 105:1899f7ed17ec | 317 | if (haveAlarm && !hadAlarm) |
andrewboyson | 105:1899f7ed17ec | 318 | { |
andrewboyson | 105:1899f7ed17ec | 319 | LogTimeF("Boiler delta T would have tripped after not being ok for %d seconds\r\n", TIME_BEFORE_DELTA_T_ALARM_SECS); |
andrewboyson | 105:1899f7ed17ec | 320 | } |
andrewboyson | 105:1899f7ed17ec | 321 | hadAlarm = haveAlarm; |
andrewboyson | 105:1899f7ed17ec | 322 | } |
andrewboyson | 105:1899f7ed17ec | 323 | #define NUMBER_OF_STEPS 10 |
andrewboyson | 105:1899f7ed17ec | 324 | static int16_t _returns16ths[NUMBER_OF_STEPS]; //0 is last, 9th is first |
andrewboyson | 105:1899f7ed17ec | 325 | static void delayLine() |
andrewboyson | 105:1899f7ed17ec | 326 | { |
andrewboyson | 105:1899f7ed17ec | 327 | static uint32_t msTimerDelay = 0; |
andrewboyson | 105:1899f7ed17ec | 328 | if (BoilerPump) |
andrewboyson | 105:1899f7ed17ec | 329 | { |
andrewboyson | 105:1899f7ed17ec | 330 | int msTotal = 1000 * fullSpeedSecs * MAX_SPEED / BoilerPumpSpeed; //speed 10 ==> 10000; speed 100 ==> 1000 |
andrewboyson | 105:1899f7ed17ec | 331 | int msPerStep = msTotal / NUMBER_OF_STEPS; |
andrewboyson | 105:1899f7ed17ec | 332 | if (MsTimerRelative(msTimerDelay, msPerStep)) |
andrewboyson | 105:1899f7ed17ec | 333 | { |
andrewboyson | 105:1899f7ed17ec | 334 | for (int i = 0; i < NUMBER_OF_STEPS - 1; i++) _returns16ths[i] = _returns16ths[i + 1]; |
andrewboyson | 105:1899f7ed17ec | 335 | _returns16ths[NUMBER_OF_STEPS - 1] = _boilerReturn16ths; |
andrewboyson | 105:1899f7ed17ec | 336 | msTimerDelay = MsTimerCount; |
andrewboyson | 105:1899f7ed17ec | 337 | //LogTimeF("Ms per step = %d, delayed boiler return = ", msPerStep); |
andrewboyson | 105:1899f7ed17ec | 338 | //DS18B20Log(_returns16ths[0]); |
andrewboyson | 105:1899f7ed17ec | 339 | //Log("\r\n"); |
andrewboyson | 105:1899f7ed17ec | 340 | } |
andrewboyson | 105:1899f7ed17ec | 341 | } |
andrewboyson | 105:1899f7ed17ec | 342 | else |
andrewboyson | 105:1899f7ed17ec | 343 | { |
andrewboyson | 105:1899f7ed17ec | 344 | msTimerDelay = MsTimerCount; |
andrewboyson | 105:1899f7ed17ec | 345 | for (int i = 0; i < NUMBER_OF_STEPS; i++) _returns16ths[i] = DS18B20_ERROR_VALUE_NOT_SET; |
andrewboyson | 105:1899f7ed17ec | 346 | } |
andrewboyson | 105:1899f7ed17ec | 347 | } |
andrewboyson | 105:1899f7ed17ec | 348 | |
andrewboyson | 35:bb8a6d1c034c | 349 | void BoilerMain() |
andrewboyson | 35:bb8a6d1c034c | 350 | { |
andrewboyson | 105:1899f7ed17ec | 351 | delayLine(); |
andrewboyson | 105:1899f7ed17ec | 352 | _boilerOutput16ths = DS18B20ValueFromRom(outputRom); |
andrewboyson | 105:1899f7ed17ec | 353 | _boilerReturn16ths = DS18B20ValueFromRom(returnRom); |
andrewboyson | 105:1899f7ed17ec | 354 | _boilerRtnDel16ths = _returns16ths[0]; |
andrewboyson | 105:1899f7ed17ec | 355 | _boilerDeltaTisValid = DS18B20IsValidValue(_boilerOutput16ths) && DS18B20IsValidValue(_boilerRtnDel16ths); |
andrewboyson | 105:1899f7ed17ec | 356 | if (_boilerDeltaTisValid) _boilerDeltaT16ths = _boilerOutput16ths - _boilerRtnDel16ths; |
andrewboyson | 105:1899f7ed17ec | 357 | else _boilerDeltaT16ths = DS18B20_ERROR_VALUE_NOT_SET; |
andrewboyson | 105:1899f7ed17ec | 358 | |
andrewboyson | 35:bb8a6d1c034c | 359 | controlBoilerCall(); |
andrewboyson | 35:bb8a6d1c034c | 360 | if (BoilerCall) BOILER_CALL_SET; |
andrewboyson | 35:bb8a6d1c034c | 361 | else BOILER_CALL_CLR; |
andrewboyson | 0:3c04f4b47041 | 362 | |
andrewboyson | 35:bb8a6d1c034c | 363 | controlBoilerPump(); |
andrewboyson | 5:82197a6997fd | 364 | if (BoilerPump) BOILER_PUMP_SET; |
andrewboyson | 5:82197a6997fd | 365 | else BOILER_PUMP_CLR; |
andrewboyson | 0:3c04f4b47041 | 366 | |
andrewboyson | 104:46ce1aaf8be7 | 367 | controlBoilerPumpSpeed(); |
andrewboyson | 105:1899f7ed17ec | 368 | flowToSpeed(); |
andrewboyson | 104:46ce1aaf8be7 | 369 | speedToPwm(); |
andrewboyson | 104:46ce1aaf8be7 | 370 | PwmSet(BoilerPumpPwm); |
andrewboyson | 104:46ce1aaf8be7 | 371 | |
andrewboyson | 104:46ce1aaf8be7 | 372 | tweakDeltaTs(); |
andrewboyson | 105:1899f7ed17ec | 373 | checkDeltaTs(); |
andrewboyson | 0:3c04f4b47041 | 374 | } |