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
baro.cpp
- Committer:
- JonFreeman
- Date:
- 2020-12-05
- Revision:
- 5:6ca3e7ffc553
- Parent:
- 3:43cb067ecd00
File content as of revision 5:6ca3e7ffc553:
#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