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
Diff: baro.cpp
- 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