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

Revision:
104:46ce1aaf8be7
Parent:
91:8b192efd0288
Child:
105:1899f7ed17ec
--- a/heating/boiler.c	Tue Jan 19 19:05:06 2021 +0000
+++ b/heating/boiler.c	Wed Feb 10 17:24:36 2021 +0000
@@ -6,6 +6,8 @@
 #include "mstimer.h"
 #include "ds18b20.h"
 #include "fram.h"
+#include "pwm.h"
+#include "log.h"
 
 #define BOILER_PUMP_DIR FIO2DIR(4) // P2.4 == p22
 #define BOILER_PUMP_PIN FIO2PIN(4)
@@ -21,26 +23,85 @@
 static char*   outputRom; static int iOutputRom;
 static char*   returnRom; static int iReturnRom;
 
-static int32_t tankSetPoint;       static int iTankSetPoint;
-static int32_t tankHysteresis;     static int iTankHysteresis;
-static int32_t runOnResidual16ths; static int iRunOnResidual;
-static int32_t runOnTime;          static int iRunOnTime;
+static int16_t tankSetPoint;       static int iTankSetPoint;
+static int16_t tankHysteresis;     static int iTankHysteresis;
+static int16_t runOnResidual16ths; static int iRunOnResidual;
+static uint8_t  runOnTime2s;       static int iRunOnTime;
+
+static int8_t  boilerTarget;       static int iBoilerTarget;
+static int8_t  pumpSpeedCalling;   static int iPumpSpeedCalling;
+static int8_t  pumpSpeedRunOn;     static int iPumpSpeedRunOn;
+
+static int16_t rise16thsAt0;       static int iRiseAt0;
+static int16_t rise16thsAt50;      static int iRiseAt50;
+static int16_t rise16thsAt100;     static int iRiseAt100;
 
 uint16_t BoilerGetTankDS18B20Value  () { return DS18B20ValueFromRom(tankRom);   } 
 uint16_t BoilerGetOutputDS18B20Value() { return DS18B20ValueFromRom(outputRom); } 
 uint16_t BoilerGetReturnDS18B20Value() { return DS18B20ValueFromRom(returnRom); } 
-int      BoilerGetTankSetPoint      () { return tankSetPoint;   } 
-int      BoilerGetTankHysteresis    () { return tankHysteresis; } 
-int      BoilerGetRunOnResidual16ths() { return runOnResidual16ths;  } 
-int      BoilerGetRunOnTime         () { return runOnTime;      } 
+int      BoilerGetTankSetPoint      () { return tankSetPoint;      }
+int      BoilerGetTankHysteresis    () { return tankHysteresis;    } 
+int      BoilerGetRunOnResidual16ths() { return runOnResidual16ths;}
+int      BoilerGetRunOnTime         () { return runOnTime2s << 1;  }
+int      BoilerGetPumpSpeedCalling  () { return pumpSpeedCalling;  }
+int      BoilerGetPumpSpeedRunOn    () { return pumpSpeedRunOn;    }
+int      BoilerGetOutputTarget      () { return boilerTarget;      }
+int      BoilerGetRise16thsAt0      () { return rise16thsAt0;      }
+int      BoilerGetRise16thsAt50     () { return rise16thsAt50;     }
+int      BoilerGetRise16thsAt100    () { return rise16thsAt100;    }
 
 static void setTankRom          (char* value) { memcpy(tankRom,      value, 8); FramWrite(iTankRom,         8,  tankRom            ); }
 static void setOutputRom        (char* value) { memcpy(outputRom,    value, 8); FramWrite(iOutputRom,       8,  outputRom          ); }
 static void setReturnRom        (char* value) { memcpy(returnRom,    value, 8); FramWrite(iReturnRom,       8,  returnRom          ); }
-void BoilerSetTankSetPoint      (int   value) { tankSetPoint       = value;     FramWrite(iTankSetPoint,    4, &tankSetPoint       ); }
-void BoilerSetTankHysteresis    (int   value) { tankHysteresis     = value;     FramWrite(iTankHysteresis,  4, &tankHysteresis     ); }
-void BoilerSetRunOnResidual16ths(int   value) { runOnResidual16ths = value;     FramWrite(iRunOnResidual,   4, &runOnResidual16ths ); }
-void BoilerSetRunOnTime         (int   value) { runOnTime          = value;     FramWrite(iRunOnTime,       4, &runOnTime          ); }
+void BoilerSetTankSetPoint      (int   value) { tankSetPoint       = value;     FramWrite(iTankSetPoint,    2, &tankSetPoint       ); }
+void BoilerSetTankHysteresis    (int   value) { tankHysteresis     = value;     FramWrite(iTankHysteresis,  2, &tankHysteresis     ); }
+void BoilerSetRunOnResidual16ths(int   value) { runOnResidual16ths = value;     FramWrite(iRunOnResidual,   2, &runOnResidual16ths ); }
+void BoilerSetRunOnTime         (int   value) { runOnTime2s        = value >> 1;FramWrite(iRunOnTime,       1, &runOnTime2s        ); }
+void BoilerSetPumpSpeedCalling  (int   value) { pumpSpeedCalling   = value;     FramWrite(iPumpSpeedCalling,1, &pumpSpeedCalling   ); }
+void BoilerSetPumpSpeedRunOn    (int   value) { pumpSpeedRunOn     = value;     FramWrite(iPumpSpeedRunOn,  1, &pumpSpeedRunOn     ); }
+void BoilerSetOutputTarget      (int   value) { boilerTarget       = value;     FramWrite(iBoilerTarget,    1, &boilerTarget       ); }
+void BoilerSetRise16thsAt0      (int   value) { rise16thsAt0       = value;     FramWrite(iRiseAt0,         2, &rise16thsAt0       ); }
+void BoilerSetRise16thsAt50     (int   value) { rise16thsAt50      = value;     FramWrite(iRiseAt50,        2, &rise16thsAt50      ); }
+void BoilerSetRise16thsAt100    (int   value) { rise16thsAt100     = value;     FramWrite(iRiseAt100,       2, &rise16thsAt100     ); }
+
+static int calculateBetweenTwoPoints(int x, int xA, int xB, int yA, int yB)
+{
+    float m = (float)(yB - yA) / (xB - xA);
+    return  yA + m * (x - xA);
+}
+static int oldcalculateBetweenTwoPoints(int point16ths, int pointBig16ths, int pointSmall16ths, int bigSpeed, int width) //width = 1 for 100; 2 for 50 and 4 for 25
+{
+    //Expected to have to compensate the slope for the reduced width but didn't need to.
+    int slope = pointBig16ths - pointSmall16ths;
+    int diff16ths = point16ths - pointSmall16ths;
+    int diffSpeed = (diff16ths * slope * width) >> 8; //points are in 16ths so multiplying them needs a division by 256
+    int requiredSpeed = bigSpeed - diffSpeed;
+    if (requiredSpeed > 100) requiredSpeed = 100;
+    if (requiredSpeed <   0) requiredSpeed = 0;
+    return requiredSpeed;
+}
+
+static int calculatePoint(int targetRise16ths)
+{
+    if (targetRise16ths > rise16thsAt0) //20
+    {
+        return 0;
+    }
+    else if (targetRise16ths > rise16thsAt50) //15
+    {
+        return calculateBetweenTwoPoints(targetRise16ths, rise16thsAt50, rise16thsAt0, 50, 0);
+        //return oldcalculateBetweenTwoPoints(targetRise16ths, rise16thsAt0, rise16thsAt50, 50, 2);
+    }
+    else if (targetRise16ths > rise16thsAt100) //10
+    {
+        return calculateBetweenTwoPoints(targetRise16ths, rise16thsAt100, rise16thsAt50, 100, 50);
+        //return oldcalculateBetweenTwoPoints(targetRise16ths, rise16thsAt50, rise16thsAt100, 100, 2);
+    }
+    else
+    {
+       return 100;
+    }
+}
 
 int BoilerInit()
 {
@@ -60,18 +121,33 @@
     DS18B20RomCount++;
     
     int address;
+    uint8_t def1;
+    int16_t def2;
     int32_t def4;
-                address = FramLoad( 8,  tankRom,                0); if (address < 0) return -1; iTankRom        = address;
-                address = FramLoad( 8,  outputRom,              0); if (address < 0) return -1; iOutputRom      = address;
-                address = FramLoad( 8,  returnRom,              0); if (address < 0) return -1; iReturnRom      = address;
-    def4 =  80; address = FramLoad( 4, &tankSetPoint,       &def4); if (address < 0) return -1; iTankSetPoint   = address; 
-    def4 =   5; address = FramLoad( 4, &tankHysteresis,     &def4); if (address < 0) return -1; iTankHysteresis = address; 
-    def4 =   2; address = FramLoad( 4, &runOnResidual16ths, &def4); if (address < 0) return -1; iRunOnResidual  = address; 
-    def4 = 360; address = FramLoad( 4, &runOnTime,          &def4); if (address < 0) return -1; iRunOnTime      = address; 
+                  address = FramLoad( 8,  tankRom,                0); if (address < 0) return -1; iTankRom          = address;
+                  address = FramLoad( 8,  outputRom,              0); if (address < 0) return -1; iOutputRom        = address;
+                  address = FramLoad( 8,  returnRom,              0); if (address < 0) return -1; iReturnRom        = address;
+    def2 =    65; address = FramLoad( 2, &tankSetPoint,       &def2); if (address < 0) return -1; iTankSetPoint     = address;
+    def2 =     5; address = FramLoad( 2, &tankHysteresis,     &def2); if (address < 0) return -1; iTankHysteresis   = address;
+    def2 =     2; address = FramLoad( 2, &runOnResidual16ths, &def2); if (address < 0) return -1; iRunOnResidual    = address;
+    def1 =   180; address = FramLoad( 1, &runOnTime2s,        &def1); if (address < 0) return -1; iRunOnTime        = address;
+    def1 =   100; address = FramLoad( 1, &pumpSpeedCalling,   &def1); if (address < 0) return -1; iPumpSpeedCalling = address;
+    def1 =    10; address = FramLoad( 1, &pumpSpeedRunOn,     &def1); if (address < 0) return -1; iPumpSpeedRunOn   = address;
+    def1 =    65; address = FramLoad( 1, &boilerTarget,       &def1); if (address < 0) return -1; iBoilerTarget     = address;
+    def2 = 10<<4; address = FramLoad( 2, &rise16thsAt0,       &def2); if (address < 0) return -1; iRiseAt0          = address;
+    def2 = 15<<4; address = FramLoad( 2, &rise16thsAt50,      &def2); if (address < 0) return -1; iRiseAt50         = address;
+    def2 = 20<<4; address = FramLoad( 2, &rise16thsAt100,     &def2); if (address < 0) return -1; iRiseAt100        = address;
     
     BOILER_PUMP_DIR = 1; //Set the direction to 1 == output
     BOILER_CALL_DIR = 1; //Set the direction to 1 == output
 
+    PwmInit(400, 100);
+
+    for (int deltaT = 30; deltaT > 0; deltaT--)
+    {
+        LogF("DeltaT %d ==> speed %d\r\n", deltaT, calculatePoint(deltaT << 4));
+    }
+
     return 0;
 }
 bool BoilerCall = false;
@@ -91,10 +167,10 @@
 bool BoilerPump = false;
 static void controlBoilerPump()
 {
-    int boilerOutput16ths   = DS18B20ValueFromRom(outputRom);
-    int boilerReturn16ths   = DS18B20ValueFromRom(returnRom);
-    int boilerResidual16ths = boilerOutput16ths - boilerReturn16ths;
-    int boilerTempsAreValid = DS18B20IsValidValue(boilerOutput16ths) && DS18B20IsValidValue(boilerReturn16ths);
+    int16_t boilerOutput16ths   = DS18B20ValueFromRom(outputRom);
+    int16_t boilerReturn16ths   = DS18B20ValueFromRom(returnRom);
+    int16_t boilerResidual16ths = boilerOutput16ths - boilerReturn16ths;
+    bool    boilerTempsAreValid = DS18B20IsValidValue(boilerOutput16ths) && DS18B20IsValidValue(boilerReturn16ths);
 
     static uint32_t msTimerBoilerPumpRunOn = 0;
     if (BoilerCall)
@@ -104,10 +180,107 @@
     }
     else
     {
-        if (MsTimerRelative(msTimerBoilerPumpRunOn,      runOnTime  * 1000)) BoilerPump = false;
-        if (boilerTempsAreValid && boilerResidual16ths < runOnResidual16ths) BoilerPump = false;
+        if (MsTimerRelative(msTimerBoilerPumpRunOn,      runOnTime2s * 2000)) BoilerPump = false;
+        if (boilerTempsAreValid && boilerResidual16ths < runOnResidual16ths ) BoilerPump = false;
+    }
+}
+int BoilerPumpSpeed = 0;
+int BoilerPumpPwm   = 0;
+static int _autoSpeed = 0;
+static void calculateAutoSpeed()
+{
+    int16_t boilerOutput16ths   = DS18B20ValueFromRom(outputRom);
+    int16_t boilerReturn16ths   = DS18B20ValueFromRom(returnRom);
+    int16_t boilerResidual16ths = boilerOutput16ths - boilerReturn16ths;
+    bool    boilerTempsAreValid = DS18B20IsValidValue(boilerOutput16ths) && DS18B20IsValidValue(boilerReturn16ths);
+    
+    if (!boilerTempsAreValid) return;
+    
+    int target16ths = (int)boilerTarget << 4;
+    int targetRise16ths = target16ths - boilerReturn16ths; //eg 65 - eg 45 = 20*16 16ths
+    
+    _autoSpeed = calculatePoint(targetRise16ths);
+}
+static void controlBoilerPumpSpeed()
+{
+    static uint32_t msTimerReduction = 0;
+    calculateAutoSpeed();
+    if (BoilerCall)
+    {
+        if (pumpSpeedCalling > 100 || pumpSpeedCalling < 0) BoilerPumpSpeed = _autoSpeed;        //Auto
+        else                                                BoilerPumpSpeed = pumpSpeedCalling;  //Manual
+        msTimerReduction = MsTimerCount;
+    }
+    else
+    {
+        if (BoilerPumpSpeed > pumpSpeedRunOn)
+        {
+            if (MsTimerRepetitive(&msTimerReduction, 250)) BoilerPumpSpeed--;
+        }
+        else
+        {
+            BoilerPumpSpeed = pumpSpeedRunOn;
+        }
     }
 }
+static void speedToPwm()
+{
+    /*
+    PWM input signal [%] Pump status
+    ≤ 10 Maximum speed
+    > 10 / ≤ 84 Variable speed from minimum to maximum
+    speed
+    > 84 / ≤ 91 Minimum speed
+    > 91/95 Hysteresis area: on/off
+    > 95 / ≤ 100 Standby mode: off
+    
+    Max speed 100 is at fitted = 74; pwm = 10
+    Min speed   0 is at fitted =  0; pwm = 84
+    */
+    int speed = BoilerPumpSpeed;
+    if (speed <   0) speed =   0;
+    if (speed > 100) speed = 100;
+    speed  *=  74;
+    speed <<=  16;
+    speed  /= 100;
+    speed >>=  16;
+    BoilerPumpPwm = 84 - speed;
+}
+#define TIME_BEFORE_TWEAK_SECS 120
+static void tweakDeltaTs()
+{
+    static uint32_t msTimerBoilerHeating = 0;
+    if (!BoilerCall) msTimerBoilerHeating = MsTimerCount;
+    if (!MsTimerRelative(msTimerBoilerHeating, TIME_BEFORE_TWEAK_SECS * 1000)) return;
+    
+    int16_t boilerOutput16ths   = DS18B20ValueFromRom(outputRom);
+    int16_t boilerReturn16ths   = DS18B20ValueFromRom(returnRom);
+    int16_t boilerResidual16ths = boilerOutput16ths - boilerReturn16ths;
+    bool    boilerTempsAreValid = DS18B20IsValidValue(boilerOutput16ths) && DS18B20IsValidValue(boilerReturn16ths);
+    if (!boilerTempsAreValid) return;
+    
+    static int speedLastScan = -1;
+    
+    if (speedLastScan == 0 && BoilerPumpSpeed > 0)
+    {
+        if (rise16thsAt0 > boilerResidual16ths) rise16thsAt0--;
+        if (rise16thsAt0 < boilerResidual16ths) rise16thsAt0++;
+    }
+    
+    else if (speedLastScan <= 50 && BoilerPumpSpeed > 50)
+    {
+        if (rise16thsAt50 > boilerResidual16ths) rise16thsAt50--;
+        if (rise16thsAt50 < boilerResidual16ths) rise16thsAt50++;
+    }
+    
+    else if (speedLastScan < 100 && BoilerPumpSpeed == 100)
+    {
+        if (rise16thsAt100 > boilerResidual16ths) rise16thsAt100--;
+        if (rise16thsAt100 < boilerResidual16ths) rise16thsAt100++;
+    }
+    
+    speedLastScan = BoilerPumpSpeed;
+}
 void BoilerMain()
 {
     controlBoilerCall();
@@ -118,4 +291,10 @@
     if (BoilerPump) BOILER_PUMP_SET;
     else            BOILER_PUMP_CLR;
     
+    controlBoilerPumpSpeed();
+    speedToPwm();
+    PwmSet(BoilerPumpPwm);
+    
+    tweakDeltaTs();
+    
 }
\ No newline at end of file