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-07-27
- Revision:
- 3:43cb067ecd00
File content as of revision 3:43cb067ecd00:
#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