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/radiator.c@99:84c3273dc77f, 2020-11-05 (annotated)
- Committer:
- andrewboyson
- Date:
- Thu Nov 05 13:53:43 2020 +0000
- Revision:
- 99:84c3273dc77f
- Parent:
- 98:c75c959bcde3
- Child:
- 102:d7bc31f0ac6e
Corrected toggle on home page to show radiator state (as labelled) rather than the override state (which is what is toggled to change the radiator state).
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
andrewboyson | 0:3c04f4b47041 | 1 | #include <stdint.h> |
andrewboyson | 0:3c04f4b47041 | 2 | #include <string.h> |
andrewboyson | 0:3c04f4b47041 | 3 | #include <stdbool.h> |
andrewboyson | 0:3c04f4b47041 | 4 | |
andrewboyson | 35:bb8a6d1c034c | 5 | #include "gpio.h" |
andrewboyson | 35:bb8a6d1c034c | 6 | #include "program.h" |
andrewboyson | 35:bb8a6d1c034c | 7 | #include "ds18b20.h" |
andrewboyson | 35:bb8a6d1c034c | 8 | #include "fram.h" |
andrewboyson | 0:3c04f4b47041 | 9 | #include "radiator.h" |
andrewboyson | 95:97621bfbedfa | 10 | #include "clktime.h" |
andrewboyson | 95:97621bfbedfa | 11 | #include "clk.h" |
andrewboyson | 35:bb8a6d1c034c | 12 | #include "led.h" |
andrewboyson | 5:82197a6997fd | 13 | |
andrewboyson | 5:82197a6997fd | 14 | |
andrewboyson | 5:82197a6997fd | 15 | #define RADIATOR_PUMP_DIR FIO2DIR(03) // P2.03 == p23; |
andrewboyson | 5:82197a6997fd | 16 | #define RADIATOR_PUMP_PIN FIO2PIN(03) |
andrewboyson | 5:82197a6997fd | 17 | #define RADIATOR_PUMP_SET FIO2SET(03) |
andrewboyson | 5:82197a6997fd | 18 | #define RADIATOR_PUMP_CLR FIO2CLR(03) |
andrewboyson | 0:3c04f4b47041 | 19 | |
andrewboyson | 98:c75c959bcde3 | 20 | static bool htgOverride = false; |
andrewboyson | 95:97621bfbedfa | 21 | static char htgWinter; static int iWinter; |
andrewboyson | 95:97621bfbedfa | 22 | static char* hallRom; static int iHallRom; |
andrewboyson | 99:84c3273dc77f | 23 | static uint8_t overrideCancelHour; static int iOverrideCancelHour; |
andrewboyson | 99:84c3273dc77f | 24 | static uint8_t overrideCancelMinute; static int iOverrideCancelMinute; |
andrewboyson | 95:97621bfbedfa | 25 | static int16_t nightTemperature; static int iNightTemperature; |
andrewboyson | 95:97621bfbedfa | 26 | static int16_t frostTemperature; static int iFrostTemperature; |
andrewboyson | 0:3c04f4b47041 | 27 | |
andrewboyson | 95:97621bfbedfa | 28 | bool RadiatorGetWinter () { return (bool)htgWinter; } |
andrewboyson | 98:c75c959bcde3 | 29 | bool RadiatorGetOverride () { return htgOverride; } |
andrewboyson | 95:97621bfbedfa | 30 | uint16_t RadiatorGetHallDS18B20Value () { return DS18B20ValueFromRom(hallRom); } |
andrewboyson | 96:18a3813bb4b5 | 31 | int RadiatorGetOverrideCancelHour () { return (int)overrideCancelHour; } |
andrewboyson | 96:18a3813bb4b5 | 32 | int RadiatorGetOverrideCancelMinute() { return (int)overrideCancelMinute; } |
andrewboyson | 95:97621bfbedfa | 33 | int RadiatorGetNightTemperature () { return (int)nightTemperature; } |
andrewboyson | 95:97621bfbedfa | 34 | int RadiatorGetFrostTemperature () { return (int)frostTemperature; } |
andrewboyson | 0:3c04f4b47041 | 35 | |
andrewboyson | 97:84d58bf7a835 | 36 | static void setWinter ( bool v) { htgWinter = (char)v; FramWrite(iWinter, 1, &htgWinter ); } |
andrewboyson | 97:84d58bf7a835 | 37 | static void setHallRom ( char* v) { memcpy(hallRom, v, 8); FramWrite(iHallRom, 8, hallRom ); } |
andrewboyson | 97:84d58bf7a835 | 38 | void RadiatorSetOverrideCancelHour ( int v) { if (v > 23 || v < 0) v = 0; overrideCancelHour = (uint8_t)v, FramWrite(iOverrideCancelHour, 1, &overrideCancelHour ); } |
andrewboyson | 97:84d58bf7a835 | 39 | void RadiatorSetOverrideCancelMinute( int v) { if (v > 59 || v < 0) v = 0; overrideCancelMinute = (uint8_t)v, FramWrite(iOverrideCancelMinute, 1, &overrideCancelMinute); } |
andrewboyson | 97:84d58bf7a835 | 40 | void RadiatorSetNightTemperature ( int v) { if (v > 99 || v < 0) v = 0; nightTemperature = (int16_t)v; FramWrite(iNightTemperature, 2, &nightTemperature ); } |
andrewboyson | 97:84d58bf7a835 | 41 | void RadiatorSetFrostTemperature ( int v) { if (v > 99 || v < 0) v = 0; frostTemperature = (int16_t)v; FramWrite(iFrostTemperature, 2, &frostTemperature ); } |
andrewboyson | 0:3c04f4b47041 | 42 | |
andrewboyson | 0:3c04f4b47041 | 43 | static bool outputBeforeOverride = false; |
andrewboyson | 0:3c04f4b47041 | 44 | static void makeOutputBeforeOverride() |
andrewboyson | 0:3c04f4b47041 | 45 | { |
andrewboyson | 0:3c04f4b47041 | 46 | //See if the temperature is too low |
andrewboyson | 0:3c04f4b47041 | 47 | int hallTemp16ths = DS18B20ValueFromRom(hallRom); |
andrewboyson | 0:3c04f4b47041 | 48 | int nightTemp16ths = nightTemperature << 4; |
andrewboyson | 0:3c04f4b47041 | 49 | int frostTemp16ths = frostTemperature << 4; |
andrewboyson | 0:3c04f4b47041 | 50 | |
andrewboyson | 0:3c04f4b47041 | 51 | static bool tooCold = false; //This is static to ride through invalid temperature reads |
andrewboyson | 0:3c04f4b47041 | 52 | if (DS18B20IsValidValue(hallTemp16ths)) |
andrewboyson | 0:3c04f4b47041 | 53 | { |
andrewboyson | 0:3c04f4b47041 | 54 | tooCold = hallTemp16ths < frostTemp16ths; |
andrewboyson | 57:72c1c1357861 | 55 | if (htgWinter) tooCold |= hallTemp16ths < nightTemp16ths; |
andrewboyson | 0:3c04f4b47041 | 56 | } |
andrewboyson | 0:3c04f4b47041 | 57 | |
andrewboyson | 76:3ef2a46c8b1e | 58 | outputBeforeOverride = (htgWinter && ProgramTimerOutput) || tooCold; |
andrewboyson | 0:3c04f4b47041 | 59 | } |
andrewboyson | 96:18a3813bb4b5 | 60 | static void autoCancelOverride() |
andrewboyson | 0:3c04f4b47041 | 61 | { |
andrewboyson | 95:97621bfbedfa | 62 | |
andrewboyson | 95:97621bfbedfa | 63 | //Remove override at 11pm |
andrewboyson | 96:18a3813bb4b5 | 64 | if (ClkTimeIsSet()) |
andrewboyson | 95:97621bfbedfa | 65 | { |
andrewboyson | 95:97621bfbedfa | 66 | struct tm tm; |
andrewboyson | 95:97621bfbedfa | 67 | ClkNowTmLocal(&tm); |
andrewboyson | 96:18a3813bb4b5 | 68 | static bool cancelWasDue = false; |
andrewboyson | 96:18a3813bb4b5 | 69 | bool cancelIsDue = tm.tm_hour == overrideCancelHour && tm.tm_min == overrideCancelMinute; |
andrewboyson | 98:c75c959bcde3 | 70 | if (cancelIsDue && !cancelWasDue && htgOverride) htgOverride = false; |
andrewboyson | 96:18a3813bb4b5 | 71 | cancelWasDue = cancelIsDue; |
andrewboyson | 95:97621bfbedfa | 72 | } |
andrewboyson | 95:97621bfbedfa | 73 | |
andrewboyson | 95:97621bfbedfa | 74 | //Remove override if no longer required |
andrewboyson | 0:3c04f4b47041 | 75 | static bool previousOutput = false; |
andrewboyson | 98:c75c959bcde3 | 76 | if (previousOutput != outputBeforeOverride && htgOverride) htgOverride = false; |
andrewboyson | 0:3c04f4b47041 | 77 | previousOutput = outputBeforeOverride; |
andrewboyson | 0:3c04f4b47041 | 78 | } |
andrewboyson | 0:3c04f4b47041 | 79 | bool RadiatorPump = false; |
andrewboyson | 0:3c04f4b47041 | 80 | static void makeOutputWithOverride() |
andrewboyson | 0:3c04f4b47041 | 81 | { |
andrewboyson | 0:3c04f4b47041 | 82 | RadiatorPump = htgOverride ? !outputBeforeOverride : outputBeforeOverride ; |
andrewboyson | 0:3c04f4b47041 | 83 | } |
andrewboyson | 0:3c04f4b47041 | 84 | |
andrewboyson | 57:72c1c1357861 | 85 | void RadiatorSetWinter(bool value) //Summer is false, Winter is true |
andrewboyson | 0:3c04f4b47041 | 86 | { |
andrewboyson | 57:72c1c1357861 | 87 | if (htgWinter == (char)value) return; //Ignore no change |
andrewboyson | 57:72c1c1357861 | 88 | setWinter(value); //Change to the new value |
andrewboyson | 0:3c04f4b47041 | 89 | |
andrewboyson | 0:3c04f4b47041 | 90 | bool prevOutputBeforeOverride = outputBeforeOverride; |
andrewboyson | 0:3c04f4b47041 | 91 | makeOutputBeforeOverride(); |
andrewboyson | 0:3c04f4b47041 | 92 | |
andrewboyson | 0:3c04f4b47041 | 93 | if (htgOverride) //Only deal with an override that is already set; if it wasn't set don't change it |
andrewboyson | 0:3c04f4b47041 | 94 | { |
andrewboyson | 57:72c1c1357861 | 95 | if (htgWinter) //Summer -> Winter |
andrewboyson | 0:3c04f4b47041 | 96 | { |
andrewboyson | 98:c75c959bcde3 | 97 | if (outputBeforeOverride != prevOutputBeforeOverride) htgOverride = false; //Adjust the override to leave the heat as it was - off or on. |
andrewboyson | 0:3c04f4b47041 | 98 | } |
andrewboyson | 0:3c04f4b47041 | 99 | else //Winter -> Summer |
andrewboyson | 0:3c04f4b47041 | 100 | { |
andrewboyson | 98:c75c959bcde3 | 101 | htgOverride = false; //turn off the heat. |
andrewboyson | 0:3c04f4b47041 | 102 | } |
andrewboyson | 0:3c04f4b47041 | 103 | } |
andrewboyson | 0:3c04f4b47041 | 104 | |
andrewboyson | 0:3c04f4b47041 | 105 | makeOutputWithOverride(); |
andrewboyson | 0:3c04f4b47041 | 106 | } |
andrewboyson | 0:3c04f4b47041 | 107 | void RadiatorSetOverride(bool value) |
andrewboyson | 0:3c04f4b47041 | 108 | { |
andrewboyson | 98:c75c959bcde3 | 109 | htgOverride = value; |
andrewboyson | 0:3c04f4b47041 | 110 | makeOutputBeforeOverride(); |
andrewboyson | 0:3c04f4b47041 | 111 | makeOutputWithOverride(); } |
andrewboyson | 0:3c04f4b47041 | 112 | |
andrewboyson | 57:72c1c1357861 | 113 | void RadiatorChgWinter (){ RadiatorSetWinter (!RadiatorGetWinter ()); } |
andrewboyson | 0:3c04f4b47041 | 114 | void RadiatorChgOverride(){ RadiatorSetOverride(!RadiatorGetOverride()); } |
andrewboyson | 0:3c04f4b47041 | 115 | |
andrewboyson | 0:3c04f4b47041 | 116 | int RadiatorInit() |
andrewboyson | 0:3c04f4b47041 | 117 | { |
andrewboyson | 48:6eac12df3ad5 | 118 | hallRom = DS18B20Roms + 8 * DS18B20RomCount; |
andrewboyson | 48:6eac12df3ad5 | 119 | DS18B20RomSetters[DS18B20RomCount] = setHallRom; |
andrewboyson | 48:6eac12df3ad5 | 120 | DS18B20RomNames[DS18B20RomCount] = "Hall"; |
andrewboyson | 48:6eac12df3ad5 | 121 | DS18B20RomCount++; |
andrewboyson | 48:6eac12df3ad5 | 122 | |
andrewboyson | 0:3c04f4b47041 | 123 | int address; |
andrewboyson | 96:18a3813bb4b5 | 124 | int8_t def1; |
andrewboyson | 95:97621bfbedfa | 125 | int16_t def2; |
andrewboyson | 96:18a3813bb4b5 | 126 | def1 = 0; address = FramLoad( 1, &htgWinter, &def1); if (address < 0) return -1; iWinter = address; |
andrewboyson | 98:c75c959bcde3 | 127 | FramAllocate(1); //Spare byte |
andrewboyson | 96:18a3813bb4b5 | 128 | address = FramLoad( 8, hallRom, 0); if (address < 0) return -1; iHallRom = address; |
andrewboyson | 96:18a3813bb4b5 | 129 | def1 = 23; address = FramLoad( 1, &overrideCancelHour, &def1); if (address < 0) return -1; iOverrideCancelHour = address; |
andrewboyson | 96:18a3813bb4b5 | 130 | def1 = 0; address = FramLoad( 1, &overrideCancelMinute, &def1); if (address < 0) return -1; iOverrideCancelMinute = address; |
andrewboyson | 98:c75c959bcde3 | 131 | FramAllocate(2); //Spare two bytes |
andrewboyson | 96:18a3813bb4b5 | 132 | def2 = 15; address = FramLoad( 2, &nightTemperature, &def2); if (address < 0) return -1; iNightTemperature = address; |
andrewboyson | 96:18a3813bb4b5 | 133 | def2 = 8; address = FramLoad( 2, &frostTemperature, &def2); if (address < 0) return -1; iFrostTemperature = address; |
andrewboyson | 0:3c04f4b47041 | 134 | |
andrewboyson | 5:82197a6997fd | 135 | RADIATOR_PUMP_DIR = 1; //Set the direction to 1 == output |
andrewboyson | 0:3c04f4b47041 | 136 | |
andrewboyson | 0:3c04f4b47041 | 137 | return 0; |
andrewboyson | 0:3c04f4b47041 | 138 | } |
andrewboyson | 0:3c04f4b47041 | 139 | void RadiatorMain() |
andrewboyson | 0:3c04f4b47041 | 140 | { |
andrewboyson | 0:3c04f4b47041 | 141 | //Make the radiator output |
andrewboyson | 0:3c04f4b47041 | 142 | makeOutputBeforeOverride(); |
andrewboyson | 99:84c3273dc77f | 143 | autoCancelOverride(); //Do this after making the output as it uses that information |
andrewboyson | 0:3c04f4b47041 | 144 | makeOutputWithOverride(); |
andrewboyson | 0:3c04f4b47041 | 145 | |
andrewboyson | 0:3c04f4b47041 | 146 | //Pump output |
andrewboyson | 5:82197a6997fd | 147 | if (RadiatorPump) RADIATOR_PUMP_SET; |
andrewboyson | 5:82197a6997fd | 148 | else RADIATOR_PUMP_CLR; |
andrewboyson | 0:3c04f4b47041 | 149 | |
andrewboyson | 0:3c04f4b47041 | 150 | } |