Library to read from Keller Druck I2C Pressure sensors. Inputs are I2C object and address.

Dependents:   TestBenchSerenity-proto_F429ZI TestBenchFlow HSPFLOW1 TestBenchFlow1 ... more

keller_pressure.cpp

Committer:
dmwahl
Date:
2019-05-06
Revision:
9:8df18eb9c0af
Parent:
8:0d45e94faf0f

File content as of revision 9:8df18eb9c0af:

///-----------------------------------------------------------------
///   Description:      Read from Keller-Druck I2C pressure sensor
///   Author:           David Wahl
///   Date:             5-APR-2018
///   Notes:            Added readP function
///
///   Revision History:
///   Name:         Date:           Description:
///                 6-MAY-2019      Added check on startup to detect whether or not a sensor is plugged in (initFailed bool)
///-----------------------------------------------------------------


// Sample code
/*
#include <mbed.h>
#include "keller_pressure.h"

DigitalOut myled(LED1);
Serial pc(SERIAL_TX, SERIAL_RX);

// an I2C sub-class that provides a constructed default
class I2CPreInit : public I2C
{
public:
    I2CPreInit(PinName sda, PinName scl, int freq) : I2C(sda, scl) {
        frequency(freq);
    };
};
//I2CPreInit gI2C1(I2C_SDA, I2C_SCL, I2C frequency);
I2CPreInit i2c(PB_9, PB_8, 100000);
KELLER_PRESSURE pumpP(i2c, 0x40);

int main()
{
    pc.baud(115200);
    pc.printf("Starting up...\n\r");
    if (pumpP.isAvailable()) {
        pc.printf("ACK\r\n");
        pumpP.readPT();
        pc.printf("Pmin: %.03f Pmax: %.03f\r\n", pumpP.pmin, pumpP.pmax);
        pc.printf("Year: %d Month: %d Day: %d Mode: %d\r\n", pumpP.year, pumpP.month, pumpP.day, pumpP.mode);
        pc.printf("Status: 0x%x\r\n", pumpP.getStatus());
        pc.printf("%.02fkPa %.02fpsi %.02fC\r\n", pumpP.pressureKPA, pumpP.pressurePSI, pumpP.temperatureC);
    }
    while (1) {
        // Main loop
        if (pumpP.isAvailable()) {
            pumpP.readPT();
            pc.printf("%.02fkPa %.02fpsi %.02fC\r\n", pumpP.pressureKPA, pumpP.pressurePSI, pumpP.temperatureC);
        }
        wait(1);
    }
}
*/
// End sample code

#include "keller_pressure.h"
union {
    char c[4];
    float f;
} u;

//===========================================================================
// Default constructor, input is the I2C address followed by min/max pressures (psi)
KELLER_PRESSURE::KELLER_PRESSURE(I2C &i2c, int i2cAddress) : i2c(i2c), mi2cAddress(i2cAddress << 1)
//===========================================================================
{
    // Read scaling factors from sensor. If the sensor doesn't respond, set all outputs to unobtanium values
    if (readUserInfo() != 0) {
        initFailed = true;
        pressureBAR = -1;
        pressurePSI = -1;
        pressureKPA = -1;
        temperatureC = -273.15;
        temperatureF = -459.67;
    } else {
        initFailed = false;
    }
};

//===========================================================================
KELLER_PRESSURE::~KELLER_PRESSURE()
//===========================================================================
{
}

//===========================================================================
// Write out a single address byte to I2C bus, if the sensor returns an ACK the function returns true.
bool KELLER_PRESSURE::isAvailable()
//===========================================================================
{
    uint8_t i = false;
    i2c.start();
    i = i2c.write(mi2cAddress|I2C_WRITE);
    i2c.stop();
    if (i == 1) {
        return true;
    } else {
        return false;
    }
}

//===========================================================================
// Read out status byte from sensor. First byte after any read request is status,
// following bytes are pressure/temperature.
char KELLER_PRESSURE::getStatus()
//===========================================================================
{
    char result = 0xFF;
    i2c.start();
    i2c.write(mi2cAddress|I2C_READ);
    result = i2c.read(0);
    i2c.stop();
    return result;
}

//===========================================================================
// Read pressure and temperature. Return 1 if error, 0 if OK.
// Byte 1: status, Bytes 2-3: pressure, Bytes 4-5: temperature
char KELLER_PRESSURE::readPT()
//===========================================================================
{
    char error = 0;
    char data[5];

    error |= _read_multibyte(KELLER_PRESSURE_REQUEST_MEASUREMENT, data, 5);
    status = data[0];
    pressure = (data[1] << 8) | data[2];
    temperature = (data[3] << 8) | data[4];

    pressureBAR = ((pressure - 16384)*(pmax-pmin))/32768+pmin;
    pressurePSI = pressureBAR*14.5038;
    pressureKPA = pressureBAR*100;

    temperatureC = (temperature - 384)*0.003125-50;
    temperatureF = (temperatureC*1.8+32);
    return error;
}

//===========================================================================
// Read pressure only. Return 1 if error, 0 if OK.
// Byte 1: status, Bytes 2-3: pressure
char KELLER_PRESSURE::readP()
//===========================================================================
{
    char error = 0;
    char data[3];

    error |= _read_multibyte(KELLER_PRESSURE_REQUEST_MEASUREMENT, data, 3);
    status = data[0];
    pressure = (data[1] << 8) | data[2];

    pressureBAR = ((pressure - 16384)*(pmax-pmin))/32768+pmin;
    pressurePSI = pressureBAR*14.5038;
    pressureKPA = pressureBAR*100;

    return error;
}

//===========================================================================
char KELLER_PRESSURE::readUserInfo()
//===========================================================================
{
    char error = 0;
    char data[3];

    error |= _read_multibyte(KELLER_PRESSURE_CUST_ID0, data, 3);
    Cust_ID0 = (data[1] << 8) | data[2];

    error |= _read_multibyte(KELLER_PRESSURE_CUST_ID1, data, 3);
    Cust_ID1 = (data[1] << 8) | data[2];

    // Scaling0 contains date/mode information
    error |= _read_multibyte(KELLER_PRESSURE_SCALING0, data, 3);
    Scaling0 = (data[1] << 8) | data[2];

    //Scaling1 and Scaling2 contain lower pressure limit
    error |= _read_multibyte(KELLER_PRESSURE_SCALING1, data, 3);
    Scaling1 = (data[1] << 8) | data[2];
    u.c[3] = data[1];
    u.c[2] = data[2];

    error |= _read_multibyte(KELLER_PRESSURE_SCALING2, data, 3);
    Scaling2 = (data[1] << 8) | data[2];
    u.c[1] = data[1];
    u.c[0] = data[2];
    pmin = u.f;

    //Scaling3 and Scaling4 contain upper pressure limit
    error |= _read_multibyte(KELLER_PRESSURE_SCALING3, data, 3);
    Scaling3 = (data[1] << 8) | data[2];
    u.c[3] = data[1];
    u.c[2] = data[2];

    error |= _read_multibyte(KELLER_PRESSURE_SCALING4, data, 3);
    Scaling4 = (data[1] << 8) | data[2];
    u.c[1] = data[1];
    u.c[0] = data[2];
    pmax = u.f;

    // Read out date of manufacture information and sensor mode
    year = ((Scaling0 & KELLER_PRESSURE_SCALING0_YEAR_MASK) >> 11) + 2010;
    month = (Scaling0 & KELLER_PRESSURE_SCALING0_MONTH_MASK) >> 7;
    day = (Scaling0 & KELLER_PRESSURE_SCALING0_DAY_MASK) >> 2;
    mode = (Scaling0 & KELLER_PRESSURE_SCALING0_MODE_MASK);

    return error;
}

//===========================================================================
char KELLER_PRESSURE::_write(char regAddress, char data)
//===========================================================================
{
    char error = 0;
    char data_write[2] = {regAddress, data};
    error |= i2c.write(mi2cAddress|I2C_WRITE, data_write, 1, false);
    return error;
}

//===========================================================================
char KELLER_PRESSURE::_read_multibyte(char regAddress, char* data, char count)
//===========================================================================
{
    char error = 0;
    error |= i2c.write(mi2cAddress|I2C_WRITE, &regAddress, 1, false);
    for (int i = 0; i < 50; i++) {
        if(getStatus() == KELLER_PRESSURE_MEASUREMENT_DONE) {
            break;
        }
        wait_us(200);
        if (i == 49) {
            error |= 1; // Timout after 50 attempts
        }
    }
    error |= i2c.read(mi2cAddress|I2C_READ, data, count, false);
    return error;
}