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@104:46ce1aaf8be7, 2021-02-10 (annotated)
- Committer:
- andrewboyson
- Date:
- Wed Feb 10 17:24:36 2021 +0000
- Revision:
- 104:46ce1aaf8be7
- Parent:
- 91:8b192efd0288
- Child:
- 105:1899f7ed17ec
Added PWM speed control to the boiler pump.
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 | 48:6eac12df3ad5 | 22 | static char* tankRom; static int iTankRom; |
andrewboyson | 48:6eac12df3ad5 | 23 | static char* outputRom; static int iOutputRom; |
andrewboyson | 48:6eac12df3ad5 | 24 | static char* returnRom; static int iReturnRom; |
andrewboyson | 0:3c04f4b47041 | 25 | |
andrewboyson | 104:46ce1aaf8be7 | 26 | static int16_t tankSetPoint; static int iTankSetPoint; |
andrewboyson | 104:46ce1aaf8be7 | 27 | static int16_t tankHysteresis; static int iTankHysteresis; |
andrewboyson | 104:46ce1aaf8be7 | 28 | static int16_t runOnResidual16ths; static int iRunOnResidual; |
andrewboyson | 104:46ce1aaf8be7 | 29 | static uint8_t runOnTime2s; static int iRunOnTime; |
andrewboyson | 104:46ce1aaf8be7 | 30 | |
andrewboyson | 104:46ce1aaf8be7 | 31 | static int8_t boilerTarget; static int iBoilerTarget; |
andrewboyson | 104:46ce1aaf8be7 | 32 | static int8_t pumpSpeedCalling; static int iPumpSpeedCalling; |
andrewboyson | 104:46ce1aaf8be7 | 33 | static int8_t pumpSpeedRunOn; static int iPumpSpeedRunOn; |
andrewboyson | 104:46ce1aaf8be7 | 34 | |
andrewboyson | 104:46ce1aaf8be7 | 35 | static int16_t rise16thsAt0; static int iRiseAt0; |
andrewboyson | 104:46ce1aaf8be7 | 36 | static int16_t rise16thsAt50; static int iRiseAt50; |
andrewboyson | 104:46ce1aaf8be7 | 37 | static int16_t rise16thsAt100; static int iRiseAt100; |
andrewboyson | 0:3c04f4b47041 | 38 | |
andrewboyson | 48:6eac12df3ad5 | 39 | uint16_t BoilerGetTankDS18B20Value () { return DS18B20ValueFromRom(tankRom); } |
andrewboyson | 48:6eac12df3ad5 | 40 | uint16_t BoilerGetOutputDS18B20Value() { return DS18B20ValueFromRom(outputRom); } |
andrewboyson | 48:6eac12df3ad5 | 41 | uint16_t BoilerGetReturnDS18B20Value() { return DS18B20ValueFromRom(returnRom); } |
andrewboyson | 104:46ce1aaf8be7 | 42 | int BoilerGetTankSetPoint () { return tankSetPoint; } |
andrewboyson | 104:46ce1aaf8be7 | 43 | int BoilerGetTankHysteresis () { return tankHysteresis; } |
andrewboyson | 104:46ce1aaf8be7 | 44 | int BoilerGetRunOnResidual16ths() { return runOnResidual16ths;} |
andrewboyson | 104:46ce1aaf8be7 | 45 | int BoilerGetRunOnTime () { return runOnTime2s << 1; } |
andrewboyson | 104:46ce1aaf8be7 | 46 | int BoilerGetPumpSpeedCalling () { return pumpSpeedCalling; } |
andrewboyson | 104:46ce1aaf8be7 | 47 | int BoilerGetPumpSpeedRunOn () { return pumpSpeedRunOn; } |
andrewboyson | 104:46ce1aaf8be7 | 48 | int BoilerGetOutputTarget () { return boilerTarget; } |
andrewboyson | 104:46ce1aaf8be7 | 49 | int BoilerGetRise16thsAt0 () { return rise16thsAt0; } |
andrewboyson | 104:46ce1aaf8be7 | 50 | int BoilerGetRise16thsAt50 () { return rise16thsAt50; } |
andrewboyson | 104:46ce1aaf8be7 | 51 | int BoilerGetRise16thsAt100 () { return rise16thsAt100; } |
andrewboyson | 0:3c04f4b47041 | 52 | |
andrewboyson | 91:8b192efd0288 | 53 | static void setTankRom (char* value) { memcpy(tankRom, value, 8); FramWrite(iTankRom, 8, tankRom ); } |
andrewboyson | 91:8b192efd0288 | 54 | static void setOutputRom (char* value) { memcpy(outputRom, value, 8); FramWrite(iOutputRom, 8, outputRom ); } |
andrewboyson | 91:8b192efd0288 | 55 | static void setReturnRom (char* value) { memcpy(returnRom, value, 8); FramWrite(iReturnRom, 8, returnRom ); } |
andrewboyson | 104:46ce1aaf8be7 | 56 | void BoilerSetTankSetPoint (int value) { tankSetPoint = value; FramWrite(iTankSetPoint, 2, &tankSetPoint ); } |
andrewboyson | 104:46ce1aaf8be7 | 57 | void BoilerSetTankHysteresis (int value) { tankHysteresis = value; FramWrite(iTankHysteresis, 2, &tankHysteresis ); } |
andrewboyson | 104:46ce1aaf8be7 | 58 | void BoilerSetRunOnResidual16ths(int value) { runOnResidual16ths = value; FramWrite(iRunOnResidual, 2, &runOnResidual16ths ); } |
andrewboyson | 104:46ce1aaf8be7 | 59 | void BoilerSetRunOnTime (int value) { runOnTime2s = value >> 1;FramWrite(iRunOnTime, 1, &runOnTime2s ); } |
andrewboyson | 104:46ce1aaf8be7 | 60 | void BoilerSetPumpSpeedCalling (int value) { pumpSpeedCalling = value; FramWrite(iPumpSpeedCalling,1, &pumpSpeedCalling ); } |
andrewboyson | 104:46ce1aaf8be7 | 61 | void BoilerSetPumpSpeedRunOn (int value) { pumpSpeedRunOn = value; FramWrite(iPumpSpeedRunOn, 1, &pumpSpeedRunOn ); } |
andrewboyson | 104:46ce1aaf8be7 | 62 | void BoilerSetOutputTarget (int value) { boilerTarget = value; FramWrite(iBoilerTarget, 1, &boilerTarget ); } |
andrewboyson | 104:46ce1aaf8be7 | 63 | void BoilerSetRise16thsAt0 (int value) { rise16thsAt0 = value; FramWrite(iRiseAt0, 2, &rise16thsAt0 ); } |
andrewboyson | 104:46ce1aaf8be7 | 64 | void BoilerSetRise16thsAt50 (int value) { rise16thsAt50 = value; FramWrite(iRiseAt50, 2, &rise16thsAt50 ); } |
andrewboyson | 104:46ce1aaf8be7 | 65 | void BoilerSetRise16thsAt100 (int value) { rise16thsAt100 = value; FramWrite(iRiseAt100, 2, &rise16thsAt100 ); } |
andrewboyson | 104:46ce1aaf8be7 | 66 | |
andrewboyson | 104:46ce1aaf8be7 | 67 | static int calculateBetweenTwoPoints(int x, int xA, int xB, int yA, int yB) |
andrewboyson | 104:46ce1aaf8be7 | 68 | { |
andrewboyson | 104:46ce1aaf8be7 | 69 | float m = (float)(yB - yA) / (xB - xA); |
andrewboyson | 104:46ce1aaf8be7 | 70 | return yA + m * (x - xA); |
andrewboyson | 104:46ce1aaf8be7 | 71 | } |
andrewboyson | 104:46ce1aaf8be7 | 72 | static int oldcalculateBetweenTwoPoints(int point16ths, int pointBig16ths, int pointSmall16ths, int bigSpeed, int width) //width = 1 for 100; 2 for 50 and 4 for 25 |
andrewboyson | 104:46ce1aaf8be7 | 73 | { |
andrewboyson | 104:46ce1aaf8be7 | 74 | //Expected to have to compensate the slope for the reduced width but didn't need to. |
andrewboyson | 104:46ce1aaf8be7 | 75 | int slope = pointBig16ths - pointSmall16ths; |
andrewboyson | 104:46ce1aaf8be7 | 76 | int diff16ths = point16ths - pointSmall16ths; |
andrewboyson | 104:46ce1aaf8be7 | 77 | int diffSpeed = (diff16ths * slope * width) >> 8; //points are in 16ths so multiplying them needs a division by 256 |
andrewboyson | 104:46ce1aaf8be7 | 78 | int requiredSpeed = bigSpeed - diffSpeed; |
andrewboyson | 104:46ce1aaf8be7 | 79 | if (requiredSpeed > 100) requiredSpeed = 100; |
andrewboyson | 104:46ce1aaf8be7 | 80 | if (requiredSpeed < 0) requiredSpeed = 0; |
andrewboyson | 104:46ce1aaf8be7 | 81 | return requiredSpeed; |
andrewboyson | 104:46ce1aaf8be7 | 82 | } |
andrewboyson | 104:46ce1aaf8be7 | 83 | |
andrewboyson | 104:46ce1aaf8be7 | 84 | static int calculatePoint(int targetRise16ths) |
andrewboyson | 104:46ce1aaf8be7 | 85 | { |
andrewboyson | 104:46ce1aaf8be7 | 86 | if (targetRise16ths > rise16thsAt0) //20 |
andrewboyson | 104:46ce1aaf8be7 | 87 | { |
andrewboyson | 104:46ce1aaf8be7 | 88 | return 0; |
andrewboyson | 104:46ce1aaf8be7 | 89 | } |
andrewboyson | 104:46ce1aaf8be7 | 90 | else if (targetRise16ths > rise16thsAt50) //15 |
andrewboyson | 104:46ce1aaf8be7 | 91 | { |
andrewboyson | 104:46ce1aaf8be7 | 92 | return calculateBetweenTwoPoints(targetRise16ths, rise16thsAt50, rise16thsAt0, 50, 0); |
andrewboyson | 104:46ce1aaf8be7 | 93 | //return oldcalculateBetweenTwoPoints(targetRise16ths, rise16thsAt0, rise16thsAt50, 50, 2); |
andrewboyson | 104:46ce1aaf8be7 | 94 | } |
andrewboyson | 104:46ce1aaf8be7 | 95 | else if (targetRise16ths > rise16thsAt100) //10 |
andrewboyson | 104:46ce1aaf8be7 | 96 | { |
andrewboyson | 104:46ce1aaf8be7 | 97 | return calculateBetweenTwoPoints(targetRise16ths, rise16thsAt100, rise16thsAt50, 100, 50); |
andrewboyson | 104:46ce1aaf8be7 | 98 | //return oldcalculateBetweenTwoPoints(targetRise16ths, rise16thsAt50, rise16thsAt100, 100, 2); |
andrewboyson | 104:46ce1aaf8be7 | 99 | } |
andrewboyson | 104:46ce1aaf8be7 | 100 | else |
andrewboyson | 104:46ce1aaf8be7 | 101 | { |
andrewboyson | 104:46ce1aaf8be7 | 102 | return 100; |
andrewboyson | 104:46ce1aaf8be7 | 103 | } |
andrewboyson | 104:46ce1aaf8be7 | 104 | } |
andrewboyson | 0:3c04f4b47041 | 105 | |
andrewboyson | 0:3c04f4b47041 | 106 | int BoilerInit() |
andrewboyson | 0:3c04f4b47041 | 107 | { |
andrewboyson | 48:6eac12df3ad5 | 108 | tankRom = DS18B20Roms + 8 * DS18B20RomCount; |
andrewboyson | 48:6eac12df3ad5 | 109 | DS18B20RomSetters[DS18B20RomCount] = setTankRom; |
andrewboyson | 48:6eac12df3ad5 | 110 | DS18B20RomNames[DS18B20RomCount] = "Tank"; |
andrewboyson | 48:6eac12df3ad5 | 111 | DS18B20RomCount++; |
andrewboyson | 48:6eac12df3ad5 | 112 | |
andrewboyson | 48:6eac12df3ad5 | 113 | outputRom = DS18B20Roms + 8 * DS18B20RomCount; |
andrewboyson | 48:6eac12df3ad5 | 114 | DS18B20RomSetters[DS18B20RomCount] = setOutputRom; |
andrewboyson | 48:6eac12df3ad5 | 115 | DS18B20RomNames[DS18B20RomCount] = "BlrOut"; |
andrewboyson | 48:6eac12df3ad5 | 116 | DS18B20RomCount++; |
andrewboyson | 48:6eac12df3ad5 | 117 | |
andrewboyson | 48:6eac12df3ad5 | 118 | returnRom = DS18B20Roms + 8 * DS18B20RomCount; |
andrewboyson | 48:6eac12df3ad5 | 119 | DS18B20RomSetters[DS18B20RomCount] = setReturnRom; |
andrewboyson | 48:6eac12df3ad5 | 120 | DS18B20RomNames[DS18B20RomCount] = "BlrRtn"; |
andrewboyson | 48:6eac12df3ad5 | 121 | DS18B20RomCount++; |
andrewboyson | 48:6eac12df3ad5 | 122 | |
andrewboyson | 0:3c04f4b47041 | 123 | int address; |
andrewboyson | 104:46ce1aaf8be7 | 124 | uint8_t def1; |
andrewboyson | 104:46ce1aaf8be7 | 125 | int16_t def2; |
andrewboyson | 0:3c04f4b47041 | 126 | int32_t def4; |
andrewboyson | 104:46ce1aaf8be7 | 127 | address = FramLoad( 8, tankRom, 0); if (address < 0) return -1; iTankRom = address; |
andrewboyson | 104:46ce1aaf8be7 | 128 | address = FramLoad( 8, outputRom, 0); if (address < 0) return -1; iOutputRom = address; |
andrewboyson | 104:46ce1aaf8be7 | 129 | address = FramLoad( 8, returnRom, 0); if (address < 0) return -1; iReturnRom = address; |
andrewboyson | 104:46ce1aaf8be7 | 130 | def2 = 65; address = FramLoad( 2, &tankSetPoint, &def2); if (address < 0) return -1; iTankSetPoint = address; |
andrewboyson | 104:46ce1aaf8be7 | 131 | def2 = 5; address = FramLoad( 2, &tankHysteresis, &def2); if (address < 0) return -1; iTankHysteresis = address; |
andrewboyson | 104:46ce1aaf8be7 | 132 | def2 = 2; address = FramLoad( 2, &runOnResidual16ths, &def2); if (address < 0) return -1; iRunOnResidual = address; |
andrewboyson | 104:46ce1aaf8be7 | 133 | def1 = 180; address = FramLoad( 1, &runOnTime2s, &def1); if (address < 0) return -1; iRunOnTime = address; |
andrewboyson | 104:46ce1aaf8be7 | 134 | def1 = 100; address = FramLoad( 1, &pumpSpeedCalling, &def1); if (address < 0) return -1; iPumpSpeedCalling = address; |
andrewboyson | 104:46ce1aaf8be7 | 135 | def1 = 10; address = FramLoad( 1, &pumpSpeedRunOn, &def1); if (address < 0) return -1; iPumpSpeedRunOn = address; |
andrewboyson | 104:46ce1aaf8be7 | 136 | def1 = 65; address = FramLoad( 1, &boilerTarget, &def1); if (address < 0) return -1; iBoilerTarget = address; |
andrewboyson | 104:46ce1aaf8be7 | 137 | def2 = 10<<4; address = FramLoad( 2, &rise16thsAt0, &def2); if (address < 0) return -1; iRiseAt0 = address; |
andrewboyson | 104:46ce1aaf8be7 | 138 | def2 = 15<<4; address = FramLoad( 2, &rise16thsAt50, &def2); if (address < 0) return -1; iRiseAt50 = address; |
andrewboyson | 104:46ce1aaf8be7 | 139 | def2 = 20<<4; address = FramLoad( 2, &rise16thsAt100, &def2); if (address < 0) return -1; iRiseAt100 = address; |
andrewboyson | 0:3c04f4b47041 | 140 | |
andrewboyson | 5:82197a6997fd | 141 | BOILER_PUMP_DIR = 1; //Set the direction to 1 == output |
andrewboyson | 5:82197a6997fd | 142 | BOILER_CALL_DIR = 1; //Set the direction to 1 == output |
andrewboyson | 48:6eac12df3ad5 | 143 | |
andrewboyson | 104:46ce1aaf8be7 | 144 | PwmInit(400, 100); |
andrewboyson | 104:46ce1aaf8be7 | 145 | |
andrewboyson | 104:46ce1aaf8be7 | 146 | for (int deltaT = 30; deltaT > 0; deltaT--) |
andrewboyson | 104:46ce1aaf8be7 | 147 | { |
andrewboyson | 104:46ce1aaf8be7 | 148 | LogF("DeltaT %d ==> speed %d\r\n", deltaT, calculatePoint(deltaT << 4)); |
andrewboyson | 104:46ce1aaf8be7 | 149 | } |
andrewboyson | 104:46ce1aaf8be7 | 150 | |
andrewboyson | 0:3c04f4b47041 | 151 | return 0; |
andrewboyson | 0:3c04f4b47041 | 152 | } |
andrewboyson | 0:3c04f4b47041 | 153 | bool BoilerCall = false; |
andrewboyson | 35:bb8a6d1c034c | 154 | static void controlBoilerCall() |
andrewboyson | 0:3c04f4b47041 | 155 | { |
andrewboyson | 0:3c04f4b47041 | 156 | int tankTemp16ths = DS18B20ValueFromRom(tankRom); |
andrewboyson | 0:3c04f4b47041 | 157 | if (DS18B20IsValidValue(tankTemp16ths)) //Ignore values which are likely to be wrong |
andrewboyson | 0:3c04f4b47041 | 158 | { |
andrewboyson | 0:3c04f4b47041 | 159 | int tankUpper16ths = tankSetPoint << 4; |
andrewboyson | 0:3c04f4b47041 | 160 | int hysteresis16ths = tankHysteresis << 4; |
andrewboyson | 0:3c04f4b47041 | 161 | int tankLower16ths = tankUpper16ths - hysteresis16ths; |
andrewboyson | 0:3c04f4b47041 | 162 | |
andrewboyson | 0:3c04f4b47041 | 163 | if (tankTemp16ths >= tankUpper16ths) BoilerCall = false; |
andrewboyson | 0:3c04f4b47041 | 164 | if (tankTemp16ths <= tankLower16ths) BoilerCall = true; |
andrewboyson | 0:3c04f4b47041 | 165 | } |
andrewboyson | 35:bb8a6d1c034c | 166 | } |
andrewboyson | 35:bb8a6d1c034c | 167 | bool BoilerPump = false; |
andrewboyson | 35:bb8a6d1c034c | 168 | static void controlBoilerPump() |
andrewboyson | 35:bb8a6d1c034c | 169 | { |
andrewboyson | 104:46ce1aaf8be7 | 170 | int16_t boilerOutput16ths = DS18B20ValueFromRom(outputRom); |
andrewboyson | 104:46ce1aaf8be7 | 171 | int16_t boilerReturn16ths = DS18B20ValueFromRom(returnRom); |
andrewboyson | 104:46ce1aaf8be7 | 172 | int16_t boilerResidual16ths = boilerOutput16ths - boilerReturn16ths; |
andrewboyson | 104:46ce1aaf8be7 | 173 | bool boilerTempsAreValid = DS18B20IsValidValue(boilerOutput16ths) && DS18B20IsValidValue(boilerReturn16ths); |
andrewboyson | 0:3c04f4b47041 | 174 | |
andrewboyson | 35:bb8a6d1c034c | 175 | static uint32_t msTimerBoilerPumpRunOn = 0; |
andrewboyson | 0:3c04f4b47041 | 176 | if (BoilerCall) |
andrewboyson | 0:3c04f4b47041 | 177 | { |
andrewboyson | 0:3c04f4b47041 | 178 | BoilerPump = true; |
andrewboyson | 35:bb8a6d1c034c | 179 | msTimerBoilerPumpRunOn = MsTimerCount; |
andrewboyson | 0:3c04f4b47041 | 180 | } |
andrewboyson | 0:3c04f4b47041 | 181 | else |
andrewboyson | 0:3c04f4b47041 | 182 | { |
andrewboyson | 104:46ce1aaf8be7 | 183 | if (MsTimerRelative(msTimerBoilerPumpRunOn, runOnTime2s * 2000)) BoilerPump = false; |
andrewboyson | 104:46ce1aaf8be7 | 184 | if (boilerTempsAreValid && boilerResidual16ths < runOnResidual16ths ) BoilerPump = false; |
andrewboyson | 104:46ce1aaf8be7 | 185 | } |
andrewboyson | 104:46ce1aaf8be7 | 186 | } |
andrewboyson | 104:46ce1aaf8be7 | 187 | int BoilerPumpSpeed = 0; |
andrewboyson | 104:46ce1aaf8be7 | 188 | int BoilerPumpPwm = 0; |
andrewboyson | 104:46ce1aaf8be7 | 189 | static int _autoSpeed = 0; |
andrewboyson | 104:46ce1aaf8be7 | 190 | static void calculateAutoSpeed() |
andrewboyson | 104:46ce1aaf8be7 | 191 | { |
andrewboyson | 104:46ce1aaf8be7 | 192 | int16_t boilerOutput16ths = DS18B20ValueFromRom(outputRom); |
andrewboyson | 104:46ce1aaf8be7 | 193 | int16_t boilerReturn16ths = DS18B20ValueFromRom(returnRom); |
andrewboyson | 104:46ce1aaf8be7 | 194 | int16_t boilerResidual16ths = boilerOutput16ths - boilerReturn16ths; |
andrewboyson | 104:46ce1aaf8be7 | 195 | bool boilerTempsAreValid = DS18B20IsValidValue(boilerOutput16ths) && DS18B20IsValidValue(boilerReturn16ths); |
andrewboyson | 104:46ce1aaf8be7 | 196 | |
andrewboyson | 104:46ce1aaf8be7 | 197 | if (!boilerTempsAreValid) return; |
andrewboyson | 104:46ce1aaf8be7 | 198 | |
andrewboyson | 104:46ce1aaf8be7 | 199 | int target16ths = (int)boilerTarget << 4; |
andrewboyson | 104:46ce1aaf8be7 | 200 | int targetRise16ths = target16ths - boilerReturn16ths; //eg 65 - eg 45 = 20*16 16ths |
andrewboyson | 104:46ce1aaf8be7 | 201 | |
andrewboyson | 104:46ce1aaf8be7 | 202 | _autoSpeed = calculatePoint(targetRise16ths); |
andrewboyson | 104:46ce1aaf8be7 | 203 | } |
andrewboyson | 104:46ce1aaf8be7 | 204 | static void controlBoilerPumpSpeed() |
andrewboyson | 104:46ce1aaf8be7 | 205 | { |
andrewboyson | 104:46ce1aaf8be7 | 206 | static uint32_t msTimerReduction = 0; |
andrewboyson | 104:46ce1aaf8be7 | 207 | calculateAutoSpeed(); |
andrewboyson | 104:46ce1aaf8be7 | 208 | if (BoilerCall) |
andrewboyson | 104:46ce1aaf8be7 | 209 | { |
andrewboyson | 104:46ce1aaf8be7 | 210 | if (pumpSpeedCalling > 100 || pumpSpeedCalling < 0) BoilerPumpSpeed = _autoSpeed; //Auto |
andrewboyson | 104:46ce1aaf8be7 | 211 | else BoilerPumpSpeed = pumpSpeedCalling; //Manual |
andrewboyson | 104:46ce1aaf8be7 | 212 | msTimerReduction = MsTimerCount; |
andrewboyson | 104:46ce1aaf8be7 | 213 | } |
andrewboyson | 104:46ce1aaf8be7 | 214 | else |
andrewboyson | 104:46ce1aaf8be7 | 215 | { |
andrewboyson | 104:46ce1aaf8be7 | 216 | if (BoilerPumpSpeed > pumpSpeedRunOn) |
andrewboyson | 104:46ce1aaf8be7 | 217 | { |
andrewboyson | 104:46ce1aaf8be7 | 218 | if (MsTimerRepetitive(&msTimerReduction, 250)) BoilerPumpSpeed--; |
andrewboyson | 104:46ce1aaf8be7 | 219 | } |
andrewboyson | 104:46ce1aaf8be7 | 220 | else |
andrewboyson | 104:46ce1aaf8be7 | 221 | { |
andrewboyson | 104:46ce1aaf8be7 | 222 | BoilerPumpSpeed = pumpSpeedRunOn; |
andrewboyson | 104:46ce1aaf8be7 | 223 | } |
andrewboyson | 0:3c04f4b47041 | 224 | } |
andrewboyson | 35:bb8a6d1c034c | 225 | } |
andrewboyson | 104:46ce1aaf8be7 | 226 | static void speedToPwm() |
andrewboyson | 104:46ce1aaf8be7 | 227 | { |
andrewboyson | 104:46ce1aaf8be7 | 228 | /* |
andrewboyson | 104:46ce1aaf8be7 | 229 | PWM input signal [%] Pump status |
andrewboyson | 104:46ce1aaf8be7 | 230 | ≤ 10 Maximum speed |
andrewboyson | 104:46ce1aaf8be7 | 231 | > 10 / ≤ 84 Variable speed from minimum to maximum |
andrewboyson | 104:46ce1aaf8be7 | 232 | speed |
andrewboyson | 104:46ce1aaf8be7 | 233 | > 84 / ≤ 91 Minimum speed |
andrewboyson | 104:46ce1aaf8be7 | 234 | > 91/95 Hysteresis area: on/off |
andrewboyson | 104:46ce1aaf8be7 | 235 | > 95 / ≤ 100 Standby mode: off |
andrewboyson | 104:46ce1aaf8be7 | 236 | |
andrewboyson | 104:46ce1aaf8be7 | 237 | Max speed 100 is at fitted = 74; pwm = 10 |
andrewboyson | 104:46ce1aaf8be7 | 238 | Min speed 0 is at fitted = 0; pwm = 84 |
andrewboyson | 104:46ce1aaf8be7 | 239 | */ |
andrewboyson | 104:46ce1aaf8be7 | 240 | int speed = BoilerPumpSpeed; |
andrewboyson | 104:46ce1aaf8be7 | 241 | if (speed < 0) speed = 0; |
andrewboyson | 104:46ce1aaf8be7 | 242 | if (speed > 100) speed = 100; |
andrewboyson | 104:46ce1aaf8be7 | 243 | speed *= 74; |
andrewboyson | 104:46ce1aaf8be7 | 244 | speed <<= 16; |
andrewboyson | 104:46ce1aaf8be7 | 245 | speed /= 100; |
andrewboyson | 104:46ce1aaf8be7 | 246 | speed >>= 16; |
andrewboyson | 104:46ce1aaf8be7 | 247 | BoilerPumpPwm = 84 - speed; |
andrewboyson | 104:46ce1aaf8be7 | 248 | } |
andrewboyson | 104:46ce1aaf8be7 | 249 | #define TIME_BEFORE_TWEAK_SECS 120 |
andrewboyson | 104:46ce1aaf8be7 | 250 | static void tweakDeltaTs() |
andrewboyson | 104:46ce1aaf8be7 | 251 | { |
andrewboyson | 104:46ce1aaf8be7 | 252 | static uint32_t msTimerBoilerHeating = 0; |
andrewboyson | 104:46ce1aaf8be7 | 253 | if (!BoilerCall) msTimerBoilerHeating = MsTimerCount; |
andrewboyson | 104:46ce1aaf8be7 | 254 | if (!MsTimerRelative(msTimerBoilerHeating, TIME_BEFORE_TWEAK_SECS * 1000)) return; |
andrewboyson | 104:46ce1aaf8be7 | 255 | |
andrewboyson | 104:46ce1aaf8be7 | 256 | int16_t boilerOutput16ths = DS18B20ValueFromRom(outputRom); |
andrewboyson | 104:46ce1aaf8be7 | 257 | int16_t boilerReturn16ths = DS18B20ValueFromRom(returnRom); |
andrewboyson | 104:46ce1aaf8be7 | 258 | int16_t boilerResidual16ths = boilerOutput16ths - boilerReturn16ths; |
andrewboyson | 104:46ce1aaf8be7 | 259 | bool boilerTempsAreValid = DS18B20IsValidValue(boilerOutput16ths) && DS18B20IsValidValue(boilerReturn16ths); |
andrewboyson | 104:46ce1aaf8be7 | 260 | if (!boilerTempsAreValid) return; |
andrewboyson | 104:46ce1aaf8be7 | 261 | |
andrewboyson | 104:46ce1aaf8be7 | 262 | static int speedLastScan = -1; |
andrewboyson | 104:46ce1aaf8be7 | 263 | |
andrewboyson | 104:46ce1aaf8be7 | 264 | if (speedLastScan == 0 && BoilerPumpSpeed > 0) |
andrewboyson | 104:46ce1aaf8be7 | 265 | { |
andrewboyson | 104:46ce1aaf8be7 | 266 | if (rise16thsAt0 > boilerResidual16ths) rise16thsAt0--; |
andrewboyson | 104:46ce1aaf8be7 | 267 | if (rise16thsAt0 < boilerResidual16ths) rise16thsAt0++; |
andrewboyson | 104:46ce1aaf8be7 | 268 | } |
andrewboyson | 104:46ce1aaf8be7 | 269 | |
andrewboyson | 104:46ce1aaf8be7 | 270 | else if (speedLastScan <= 50 && BoilerPumpSpeed > 50) |
andrewboyson | 104:46ce1aaf8be7 | 271 | { |
andrewboyson | 104:46ce1aaf8be7 | 272 | if (rise16thsAt50 > boilerResidual16ths) rise16thsAt50--; |
andrewboyson | 104:46ce1aaf8be7 | 273 | if (rise16thsAt50 < boilerResidual16ths) rise16thsAt50++; |
andrewboyson | 104:46ce1aaf8be7 | 274 | } |
andrewboyson | 104:46ce1aaf8be7 | 275 | |
andrewboyson | 104:46ce1aaf8be7 | 276 | else if (speedLastScan < 100 && BoilerPumpSpeed == 100) |
andrewboyson | 104:46ce1aaf8be7 | 277 | { |
andrewboyson | 104:46ce1aaf8be7 | 278 | if (rise16thsAt100 > boilerResidual16ths) rise16thsAt100--; |
andrewboyson | 104:46ce1aaf8be7 | 279 | if (rise16thsAt100 < boilerResidual16ths) rise16thsAt100++; |
andrewboyson | 104:46ce1aaf8be7 | 280 | } |
andrewboyson | 104:46ce1aaf8be7 | 281 | |
andrewboyson | 104:46ce1aaf8be7 | 282 | speedLastScan = BoilerPumpSpeed; |
andrewboyson | 104:46ce1aaf8be7 | 283 | } |
andrewboyson | 35:bb8a6d1c034c | 284 | void BoilerMain() |
andrewboyson | 35:bb8a6d1c034c | 285 | { |
andrewboyson | 35:bb8a6d1c034c | 286 | controlBoilerCall(); |
andrewboyson | 35:bb8a6d1c034c | 287 | if (BoilerCall) BOILER_CALL_SET; |
andrewboyson | 35:bb8a6d1c034c | 288 | else BOILER_CALL_CLR; |
andrewboyson | 0:3c04f4b47041 | 289 | |
andrewboyson | 35:bb8a6d1c034c | 290 | controlBoilerPump(); |
andrewboyson | 5:82197a6997fd | 291 | if (BoilerPump) BOILER_PUMP_SET; |
andrewboyson | 5:82197a6997fd | 292 | else BOILER_PUMP_CLR; |
andrewboyson | 0:3c04f4b47041 | 293 | |
andrewboyson | 104:46ce1aaf8be7 | 294 | controlBoilerPumpSpeed(); |
andrewboyson | 104:46ce1aaf8be7 | 295 | speedToPwm(); |
andrewboyson | 104:46ce1aaf8be7 | 296 | PwmSet(BoilerPumpPwm); |
andrewboyson | 104:46ce1aaf8be7 | 297 | |
andrewboyson | 104:46ce1aaf8be7 | 298 | tweakDeltaTs(); |
andrewboyson | 104:46ce1aaf8be7 | 299 | |
andrewboyson | 0:3c04f4b47041 | 300 | } |