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

Committer:
JonFreeman
Date:
Sat Dec 05 12:40:17 2020 +0000
Revision:
5:6ca3e7ffc553
Parent:
3:43cb067ecd00
Code for 'Smart Regulator' to August 2020, published as is. Basic low-level functions all thoroughly tested and debugged, top level algorithms have scope for further development - over to you! For help contact jon @ jons-workshop[.com

Who changed what in which revision?

UserRevisionLine numberNew contents of line
JonFreeman 3:43cb067ecd00 1 #ifdef INC_BARO
JonFreeman 3:43cb067ecd00 2
JonFreeman 3:43cb067ecd00 3 #include "mbed.h"
JonFreeman 3:43cb067ecd00 4 #include "baro.h"
JonFreeman 3:43cb067ecd00 5 #include "BufferedSerial.h"
JonFreeman 3:43cb067ecd00 6
JonFreeman 3:43cb067ecd00 7 //BufferedSerial pc (PA_2, PA_3, 512, 4, NULL); // Pins 16, 17 tx, rx to pc via usb lead
JonFreeman 3:43cb067ecd00 8 //I2C i2c (PB_7, PB_6); // Pins 58, 59 For 24LC64 eeprom
JonFreeman 3:43cb067ecd00 9 extern BufferedSerial pc;
JonFreeman 3:43cb067ecd00 10 extern I2C i2c;
JonFreeman 3:43cb067ecd00 11 const int ACK = 1;
JonFreeman 3:43cb067ecd00 12 const int NAK = 0;
JonFreeman 3:43cb067ecd00 13 const int NOM_PASCALS = 100000;
JonFreeman 3:43cb067ecd00 14 const int HYSTERESIS_PASCALS = 50;
JonFreeman 3:43cb067ecd00 15
JonFreeman 3:43cb067ecd00 16 MPL3115A2::MPL3115A2 () { // Constructor
JonFreeman 3:43cb067ecd00 17 good = true;
JonFreeman 3:43cb067ecd00 18 // mode = 0x39; // continuous convert
JonFreeman 3:43cb067ecd00 19 mode = 0x38; // one shot
JonFreeman 3:43cb067ecd00 20 Temp = Pres = Alti = Adju = 0.0;
JonFreeman 3:43cb067ecd00 21 if (!RegRd (0x0c, 1, dest))
JonFreeman 3:43cb067ecd00 22 good = false;
JonFreeman 3:43cb067ecd00 23 else if (dest[0] != 196)
JonFreeman 3:43cb067ecd00 24 good = false;
JonFreeman 3:43cb067ecd00 25 }
JonFreeman 3:43cb067ecd00 26
JonFreeman 3:43cb067ecd00 27 bool MPL3115A2::busy_check () {
JonFreeman 3:43cb067ecd00 28 char c;
JonFreeman 3:43cb067ecd00 29 RegRd (0x26, 1, &c);
JonFreeman 3:43cb067ecd00 30 c &= 2;
JonFreeman 3:43cb067ecd00 31 if (c == 0)
JonFreeman 3:43cb067ecd00 32 return false; // free, i.e. not busy
JonFreeman 3:43cb067ecd00 33 return true; // busy, conversion in progress
JonFreeman 3:43cb067ecd00 34 }
JonFreeman 3:43cb067ecd00 35
JonFreeman 3:43cb067ecd00 36 void MPL3115A2::reset_zero_inHg () {
JonFreeman 3:43cb067ecd00 37 double tmp;
JonFreeman 3:43cb067ecd00 38 Adju = 0.0;
JonFreeman 3:43cb067ecd00 39 tmp = inHg_vacuum (); // sets Adju
JonFreeman 3:43cb067ecd00 40 Adju = tmp;
JonFreeman 3:43cb067ecd00 41 }
JonFreeman 3:43cb067ecd00 42 double MPL3115A2::Temperature () { return Temp; }
JonFreeman 3:43cb067ecd00 43 double MPL3115A2::Pressure () { return Pres; }
JonFreeman 3:43cb067ecd00 44 double MPL3115A2::Altitude () { return Alti; }
JonFreeman 3:43cb067ecd00 45 double MPL3115A2::inHg_vacuum () {
JonFreeman 3:43cb067ecd00 46 double inHg = 0.0 - Pres; // one atmospheres worth of Pascals. Note 1 bar is not the same, 1 bar = 100000 Pa
JonFreeman 3:43cb067ecd00 47 inHg *= 0.000295299833;
JonFreeman 3:43cb067ecd00 48 return inHg - Adju;
JonFreeman 3:43cb067ecd00 49 }
JonFreeman 3:43cb067ecd00 50 void MPL3115A2::mode_alti () {
JonFreeman 3:43cb067ecd00 51 // mode = 0xb9;
JonFreeman 3:43cb067ecd00 52 mode = 0xb8;
JonFreeman 3:43cb067ecd00 53 }
JonFreeman 3:43cb067ecd00 54 void MPL3115A2::mode_pres () {
JonFreeman 3:43cb067ecd00 55 // mode = 0x39;
JonFreeman 3:43cb067ecd00 56 mode = 0x38;
JonFreeman 3:43cb067ecd00 57 }
JonFreeman 3:43cb067ecd00 58 /*********************************************************\
JonFreeman 3:43cb067ecd00 59 * IIC Write Register
JonFreeman 3:43cb067ecd00 60 \*********************************************************/
JonFreeman 3:43cb067ecd00 61 bool MPL3115A2::RegWr (int reg, char val)
JonFreeman 3:43cb067ecd00 62 {
JonFreeman 3:43cb067ecd00 63 bool rv = true;
JonFreeman 3:43cb067ecd00 64 i2c.start ();
JonFreeman 3:43cb067ecd00 65 if (i2c.write (0xc0) != ACK) rv = false; // Returns '0' - NAK was received '1' - ACK was received, '2' - timeout
JonFreeman 3:43cb067ecd00 66 if (i2c.write (reg) != ACK) rv = false;
JonFreeman 3:43cb067ecd00 67 if (i2c.write (val) != ACK) rv = false;
JonFreeman 3:43cb067ecd00 68 i2c.stop ();
JonFreeman 3:43cb067ecd00 69 return rv;
JonFreeman 3:43cb067ecd00 70 }
JonFreeman 3:43cb067ecd00 71
JonFreeman 3:43cb067ecd00 72 /*********************************************************\
JonFreeman 3:43cb067ecd00 73 * IIC Read One Or More Registers into array
JonFreeman 3:43cb067ecd00 74 \*********************************************************/
JonFreeman 3:43cb067ecd00 75 bool MPL3115A2::RegRd (int reg1, int len, char *array)
JonFreeman 3:43cb067ecd00 76 {
JonFreeman 3:43cb067ecd00 77 int acknak;
JonFreeman 3:43cb067ecd00 78 bool rv = true;
JonFreeman 3:43cb067ecd00 79 i2c.start ();
JonFreeman 3:43cb067ecd00 80 if (i2c.write (0xc0) != ACK) rv = false; // Returns '0' - NAK was received '1' - ACK was received, '2' - timeout
JonFreeman 3:43cb067ecd00 81 if (i2c.write (reg1) != ACK) rv = false;
JonFreeman 3:43cb067ecd00 82 i2c.start (); // Send Repeat Start
JonFreeman 3:43cb067ecd00 83 if (i2c.write (0xc1) != ACK) rv = false;
JonFreeman 3:43cb067ecd00 84 acknak = ACK;
JonFreeman 3:43cb067ecd00 85 while (len > 0) { // Read Register Values
JonFreeman 3:43cb067ecd00 86 len--;
JonFreeman 3:43cb067ecd00 87 if (len == 0) acknak = NAK;
JonFreeman 3:43cb067ecd00 88 *array++ = i2c.read (acknak);
JonFreeman 3:43cb067ecd00 89 }
JonFreeman 3:43cb067ecd00 90 i2c.stop ();
JonFreeman 3:43cb067ecd00 91 return rv;
JonFreeman 3:43cb067ecd00 92 }
JonFreeman 3:43cb067ecd00 93
JonFreeman 3:43cb067ecd00 94 bool MPL3115A2::Update () { // Returns true on apparent success
JonFreeman 3:43cb067ecd00 95 bool rv = true;
JonFreeman 3:43cb067ecd00 96 int32_t ta;
JonFreeman 3:43cb067ecd00 97 if (busy_check()) { // "User shall read the value of the OST bit before writing to this bit again." - done here.
JonFreeman 3:43cb067ecd00 98 pc.printf ("Call to Barometer Update while busy error\r\n");
JonFreeman 3:43cb067ecd00 99 return false; // Can not initiate new conversion, will not update Temp, Pres, Alti
JonFreeman 3:43cb067ecd00 100 }
JonFreeman 3:43cb067ecd00 101 Pres = Alti = -1.0; // Gives added clue if call to Update fails
JonFreeman 3:43cb067ecd00 102 if (!RegRd (1, 5, dest)) rv = false; // Read 3 pressure + 2 temperature registers, then kick-start new conversion
JonFreeman 3:43cb067ecd00 103 if (!RegWr (0x26, mode | 2)) rv = false; // bit 1 is OST one shot mode, bits 3-5 are 128x oversampling. This starts new conversion
JonFreeman 3:43cb067ecd00 104 if (!rv)
JonFreeman 3:43cb067ecd00 105 return false; // register read or write failed, Pres and Alti = -1.0 also
JonFreeman 3:43cb067ecd00 106 Temp = ((double) ((dest[3] << 4) | (dest[4] >> 4))) / 16.0; // Temperature
JonFreeman 3:43cb067ecd00 107 if (mode & 0x80) { // Altimeter mode
JonFreeman 3:43cb067ecd00 108 ta = (dest[0] << 24) | (dest[1] << 16) | ((dest[2] & 0xf0) << 8); // preserve sign bit
JonFreeman 3:43cb067ecd00 109 ta /= (1 << 12);
JonFreeman 3:43cb067ecd00 110 Alti = ((double) ta) / 16.0;
JonFreeman 3:43cb067ecd00 111 Pres = 0.0;
JonFreeman 3:43cb067ecd00 112 }
JonFreeman 3:43cb067ecd00 113 else { // Pressure mode
JonFreeman 3:43cb067ecd00 114 Pres = ((double) ((dest[0] << 12) | (dest[1] << 4) | (dest[2] >> 4))) / 4.0;
JonFreeman 3:43cb067ecd00 115 Alti = 0.0;
JonFreeman 3:43cb067ecd00 116 }
JonFreeman 3:43cb067ecd00 117 return true;
JonFreeman 3:43cb067ecd00 118 }
JonFreeman 3:43cb067ecd00 119
JonFreeman 3:43cb067ecd00 120
JonFreeman 3:43cb067ecd00 121 /*
JonFreeman 3:43cb067ecd00 122 int main()
JonFreeman 3:43cb067ecd00 123 {
JonFreeman 3:43cb067ecd00 124 double Pres, Alt, inHg, Heat;
JonFreeman 3:43cb067ecd00 125 i2c.frequency(400000); // Speed 400000 max.
JonFreeman 3:43cb067ecd00 126 class MPL3115A2 baro ;
JonFreeman 3:43cb067ecd00 127 int q; // Note address bits 3-1 to match addr pins on 24LC16 memory device
JonFreeman 3:43cb067ecd00 128 for (int i = 0; i < 255; i += 2) { // Search for devices at all possible i2c addresses
JonFreeman 3:43cb067ecd00 129 i2c.start();
JonFreeman 3:43cb067ecd00 130 wait_ms (1);
JonFreeman 3:43cb067ecd00 131 q = i2c.write(i); // may return error code 2 when no start issued
JonFreeman 3:43cb067ecd00 132 switch (q) {
JonFreeman 3:43cb067ecd00 133 case ACK:
JonFreeman 3:43cb067ecd00 134 pc.printf ("I2C device found at 0x%x\r\n", i);
JonFreeman 3:43cb067ecd00 135 case NAK: // Device not seen at this address
JonFreeman 3:43cb067ecd00 136 break;
JonFreeman 3:43cb067ecd00 137 case 2: // write reports timeout
JonFreeman 3:43cb067ecd00 138 pc.printf ("I2C Timeout at addr %2x\r\n", i);
JonFreeman 3:43cb067ecd00 139 break;
JonFreeman 3:43cb067ecd00 140 default:
JonFreeman 3:43cb067ecd00 141 pc.printf ("Unknown error %d in check_24LC64\r\n", q);
JonFreeman 3:43cb067ecd00 142 break;
JonFreeman 3:43cb067ecd00 143 }
JonFreeman 3:43cb067ecd00 144 }
JonFreeman 3:43cb067ecd00 145 i2c.stop();
JonFreeman 3:43cb067ecd00 146 baro.mode_pres ();
JonFreeman 3:43cb067ecd00 147 pc.printf ("baro good flag %s\r\n", baro.good ? "true":"false");
JonFreeman 3:43cb067ecd00 148 bool rv;
JonFreeman 3:43cb067ecd00 149 q = -3;
JonFreeman 3:43cb067ecd00 150 while(1) {
JonFreeman 3:43cb067ecd00 151 q++;
JonFreeman 3:43cb067ecd00 152 if (q == 0) baro.reset_zero_inHg();
JonFreeman 3:43cb067ecd00 153 myled = 1; // LED is ON
JonFreeman 3:43cb067ecd00 154 wait(0.3); // 200 ms
JonFreeman 3:43cb067ecd00 155 // pc.printf ("busy_check %s\r\n", baro.busy_check() ? "true":"false");
JonFreeman 3:43cb067ecd00 156 myled = 0; // LED is OFF
JonFreeman 3:43cb067ecd00 157 wait(0.8); // 1 sec
JonFreeman 3:43cb067ecd00 158 // pc.printf ("busy_check %s\r\n", baro.busy_check() ? "true":"false");
JonFreeman 3:43cb067ecd00 159 rv = baro.Update ();
JonFreeman 3:43cb067ecd00 160 Pres = baro.Pressure();
JonFreeman 3:43cb067ecd00 161 Alt = baro.Altitude();
JonFreeman 3:43cb067ecd00 162 inHg = baro.inHg_vacuum();
JonFreeman 3:43cb067ecd00 163 Heat = baro.Temperature();
JonFreeman 3:43cb067ecd00 164 const int NOM_PASCALS = 100000;
JonFreeman 3:43cb067ecd00 165 const int HYSTERESIS_PASCALS = 50;
JonFreeman 3:43cb067ecd00 166 if (Pres > (NOM_PASCALS + HYSTERESIS_PASCALS))
JonFreeman 3:43cb067ecd00 167 pump = 1;
JonFreeman 3:43cb067ecd00 168 if (Pres < (NOM_PASCALS - HYSTERESIS_PASCALS))
JonFreeman 3:43cb067ecd00 169 pump = 0;
JonFreeman 3:43cb067ecd00 170 // 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");
JonFreeman 3:43cb067ecd00 171 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");
JonFreeman 3:43cb067ecd00 172 // rv = baro.Update ();
JonFreeman 3:43cb067ecd00 173 }
JonFreeman 3:43cb067ecd00 174 }
JonFreeman 3:43cb067ecd00 175 */
JonFreeman 3:43cb067ecd00 176 #endif