Code for 'Smart Regulator' featured in 'Model Engineer', November 2020 on. Contains all work to August 2020 including all code described. Top level algorithm development is quite spares, leaving some work for you! Any questions - jon@jons-workshop.com

Dependencies:   mbed BufferedSerial Servo2 PCT2075 I2CEeprom FastPWM

Revision:
3:43cb067ecd00
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/baro.cpp	Mon Jul 27 08:44:59 2020 +0000
@@ -0,0 +1,176 @@
+#ifdef  INC_BARO
+
+#include "mbed.h"
+#include "baro.h"
+#include "BufferedSerial.h"
+
+//BufferedSerial  pc          (PA_2, PA_3, 512, 4, NULL);    //  Pins 16, 17    tx, rx to pc via usb lead
+//I2C i2c                     (PB_7, PB_6);   //  Pins 58, 59 For 24LC64 eeprom
+extern  BufferedSerial  pc;
+extern  I2C i2c;
+const int ACK     = 1;
+const int NAK     = 0;
+const int NOM_PASCALS   = 100000;
+const int HYSTERESIS_PASCALS = 50;
+
+MPL3115A2::MPL3115A2    ()  {   //  Constructor
+        good = true;
+//        mode = 0x39;  //  continuous convert
+        mode = 0x38;    //  one shot
+        Temp = Pres = Alti = Adju = 0.0;
+        if  (!RegRd (0x0c, 1, dest))
+            good = false;
+        else if (dest[0] != 196)
+            good = false;
+}
+
+bool    MPL3115A2::busy_check  ()  {
+    char    c;
+    RegRd   (0x26, 1, &c);
+    c &= 2;
+    if  (c == 0)
+        return  false;  //  free, i.e. not busy
+    return  true;       //  busy, conversion in progress
+}
+
+void    MPL3115A2::reset_zero_inHg  ()  {
+    double tmp;
+    Adju = 0.0;
+    tmp = inHg_vacuum (); //  sets Adju
+    Adju = tmp;
+}
+double  MPL3115A2::Temperature ()  {    return  Temp;   }
+double  MPL3115A2::Pressure    ()  {    return  Pres;   }
+double  MPL3115A2::Altitude    ()  {    return  Alti;   }
+double  MPL3115A2::inHg_vacuum ()  {
+    double  inHg = 0.0 - Pres;   //  one atmospheres worth of Pascals. Note 1 bar is not the same, 1 bar = 100000 Pa
+    inHg *= 0.000295299833;
+    return  inHg - Adju;
+}
+void    MPL3115A2::mode_alti   ()  {
+//    mode = 0xb9;
+    mode = 0xb8;
+}
+void    MPL3115A2::mode_pres   ()  {
+//    mode = 0x39;
+    mode = 0x38;
+}
+/*********************************************************\
+* IIC Write Register
+\*********************************************************/
+bool MPL3115A2::RegWr  (int reg, char val)
+{
+    bool    rv = true;
+    i2c.start   ();
+    if  (i2c.write   (0xc0)     != ACK) rv = false;  //  Returns '0' - NAK was received '1' - ACK was received, '2' - timeout
+    if  (i2c.write   (reg)      != ACK) rv = false;
+    if  (i2c.write   (val)      != ACK) rv = false;
+    i2c.stop    ();
+    return  rv;
+}
+
+/*********************************************************\
+* IIC Read One Or More Registers into array
+\*********************************************************/
+bool MPL3115A2::RegRd  (int reg1, int len, char *array)
+{
+    int acknak;
+    bool    rv = true;
+    i2c.start   ();
+    if  (i2c.write   (0xc0) != ACK)     rv = false;  //  Returns '0' - NAK was received '1' - ACK was received, '2' - timeout
+    if  (i2c.write   (reg1) != ACK)     rv = false;
+    i2c.start   ();             // Send Repeat Start
+    if  (i2c.write   (0xc1) != ACK)     rv = false;
+    acknak = ACK;
+    while (len > 0) {                                 // Read Register Values
+        len--;
+        if  (len == 0)    acknak = NAK;
+        *array++ = i2c.read    (acknak);
+    }
+    i2c.stop    ();
+    return  rv;
+}
+
+bool    MPL3115A2::Update    ()   {   //  Returns true on apparent success
+    bool    rv = true;
+    int32_t ta;
+    if  (busy_check())  {   //  "User shall read the value of the OST bit before writing to this bit again." - done here.
+        pc.printf   ("Call to Barometer Update while busy error\r\n");
+        return  false;  //  Can not initiate new conversion, will not update Temp, Pres, Alti
+    }
+    Pres = Alti = -1.0; //  Gives added clue if call to Update fails
+    if  (!RegRd (1, 5, dest))       rv = false;    //  Read 3 pressure + 2 temperature registers, then kick-start new conversion
+    if  (!RegWr (0x26, mode | 2))   rv = false;    //  bit 1 is OST one shot mode, bits 3-5 are 128x oversampling. This starts new conversion
+    if  (!rv)
+        return  false;  //  register read or write failed, Pres and Alti = -1.0 also
+    Temp = ((double) ((dest[3] << 4) | (dest[4] >> 4))) / 16.0; //  Temperature
+    if  (mode & 0x80)  {    //  Altimeter mode
+        ta = (dest[0] << 24) | (dest[1] << 16) | ((dest[2] & 0xf0) << 8);   //  preserve sign bit
+        ta /= (1 << 12);
+        Alti = ((double) ta) / 16.0;
+        Pres = 0.0;
+    }
+    else    {   //  Pressure mode
+        Pres = ((double) ((dest[0] << 12) | (dest[1] << 4) | (dest[2] >> 4))) / 4.0;
+        Alti = 0.0;
+    }
+    return  true;
+}
+
+
+/*
+int main()
+{
+    double  Pres, Alt, inHg, Heat;
+    i2c.frequency(400000);      //  Speed 400000 max.
+    class   MPL3115A2   baro    ;
+    int q;      //  Note address bits 3-1 to match addr pins on 24LC16 memory device
+    for (int i = 0; i < 255; i += 2)    {   //  Search for devices at all possible i2c addresses
+        i2c.start();
+        wait_ms (1);
+        q = i2c.write(i);   //  may return error code 2 when no start issued
+        switch  (q) {
+            case    ACK:
+                pc.printf   ("I2C device found at 0x%x\r\n", i);
+            case    NAK:      //  Device not seen at this address
+                break;
+            case    2:      //  write reports timeout
+                pc.printf   ("I2C Timeout at addr %2x\r\n", i);
+                break;
+            default:
+                pc.printf   ("Unknown error %d in check_24LC64\r\n", q);
+                break;
+        }
+    }
+    i2c.stop();
+    baro.mode_pres  ();
+    pc.printf   ("baro good flag %s\r\n", baro.good ? "true":"false");
+    bool    rv;
+    q = -3;
+    while(1) {
+        q++;
+        if  (q == 0)    baro.reset_zero_inHg();
+        myled = 1; // LED is ON
+        wait(0.3); // 200 ms
+//        pc.printf   ("busy_check %s\r\n", baro.busy_check() ? "true":"false");
+        myled = 0; // LED is OFF
+        wait(0.8); // 1 sec
+//        pc.printf   ("busy_check %s\r\n", baro.busy_check() ? "true":"false");
+        rv  = baro.Update ();
+        Pres = baro.Pressure();
+        Alt = baro.Altitude();
+        inHg = baro.inHg_vacuum();
+        Heat = baro.Temperature();
+const int NOM_PASCALS   = 100000;
+const int HYSTERESIS_PASCALS = 50;
+        if  (Pres > (NOM_PASCALS + HYSTERESIS_PASCALS))
+            pump = 1;
+        if  (Pres < (NOM_PASCALS - HYSTERESIS_PASCALS))
+            pump = 0;
+//        pc.printf   ("Pres\t%.2f Pa\tAlt\t%.1f m\t%+000.1f inHg\tTemp\t%.1f C, %s\r\n", baro.Pressure(), baro.Altitude(), baro.inHg_vacuum (), baro.Temperature(), rv ? "true":"false");
+        pc.printf   ("Pres\t%.2f Pa\tAlt\t%.1f m\t%+000.1f inHg\tTemp\t%.1f C, %s\r\n", Pres, Alt, inHg, Heat, rv ? "true":"false");
+//        rv  = baro.Update ();
+    }
+}
+*/
+#endif