Library and demo program for MS4525DO differential pressure sensor based pitot tube, using I2C interface
Temperature values are correct. But I dont trust the PSI and airspeed (especially airspeed).
Code blended and ported from a combination of the following sources:
- https://forum.arduino.cc/index.php?topic=309653.0
- https://github.com/PX4/Firmware/blob/master/src/modules/commander/airspeed_calibration.cpp
- https://github.com/PX4/Firmware/tree/master/src/drivers/differential_pressure/ms4525
MS4525DO/MS4525DO.cpp
- Committer:
- epremeaux
- Date:
- 2019-09-13
- Revision:
- 0:5965bf423184
File content as of revision 0:5965bf423184:
#include "mbed.h" #include "MS4525DO.h" MS4525DO::MS4525DO(PinName sda, PinName scl, char slave_adr) : i2c_p(new I2C(sda, scl)), i2c(*i2c_p), address(slave_adr<<1) { initialize(); } MS4525DO::MS4525DO(I2C &i2c_obj, char slave_adr) : i2c_p(NULL), i2c(i2c_obj), address(slave_adr<<1) { initialize(); } MS4525DO::~MS4525DO() { if (NULL != i2c_p) delete i2c_p; } /* public functions void initialize(void); int measure(void); // returns status of measurement float getPSI(void); // returns the PSI of last measurement float getTemperature(void); // returns temperature of last measurement float getAirSpeed(void); // calculates and returns the airspeed int calibrate(void); // attempts to calibrate and returns a status code */ void MS4525DO::initialize() { // i2c writes to set up addresses, etc. } // combine measure and collect into one function that returns the status code only, and holds the results in variables // other subroutines for returning clean values should be get functions int MS4525DO::measure() { char ret; ret = fetch_pressure(P_dat, T_dat); return ret; } char MS4525DO::fetch_pressure(uint16_t &P_dat, uint16_t &T_dat) { char _status; char Press_H; char Press_L; char Temp_H; char Temp_L; char cmd[1]; cmd[0] = 0x00; // So a device with a 'physical' address of 0x28, will need 'address bytes' of 0x50 for a write (R/W low), and 0x51 for a read (R/W high). // MS4525DAddress i2c.write(address, cmd, 1, true); // select the register, no I2C Stop char data[4]; // i2c.read(MS4525DAddress, static_cast<uint8_t>(4), static_cast<uint8_t>(true)); //Request 4 bytes, 2 pressure/status and 2 temperature i2c.read(address, data, 4); Press_H = data[0]; Press_L = data[1]; Temp_H = data[2]; Temp_L = data[3]; _status = (Press_H >> 6) & 0x03; Press_H = Press_H & 0x3f; P_dat = (((uint16_t)Press_H) << 8) | Press_L; Temp_L = (Temp_L >> 5); T_dat = (((uint16_t)Temp_H) << 3) | Temp_L; return _status; } float MS4525DO::getPSI(void){ // returns the PSI of last measurement // convert and store PSI psi=(static_cast<float>(static_cast<int16_t>(P_dat)-MS4525ZeroCounts))/static_cast<float>(MS4525Span)*static_cast<float>(MS4525FullScaleRange); // apply PSI calibration data // psi = psi + 0.007f; /* Below code is Pixhawk code which doesnt seem to work correctly */ // Calculate differential pressure. As its centered around 8000 // and can go positive or negative /* const float P_min = -1.0f; const float P_max = 1.0f; const float PSI_to_Pa = 6894.757f; */ /* this equation is an inversion of the equation in the pressure transfer function figure on page 4 of the datasheet We negate the result so that positive differential pressures are generated when the bottom port is used as the static port on the pitot and top port is used as the dynamic port */ /* float diff_press_PSI = -((T_dat - 0.1f * 16383) * (P_max - P_min) / (0.8f * 16383) + P_min); float diff_press_pa_raw = diff_press_PSI * PSI_to_Pa; */ return psi; } float MS4525DO::getTemperature(void){ // returns temperature of last measurement // convert and store Temperature temperature= (static_cast<float>(static_cast<int16_t>(T_dat))); temperature = (temperature / 10); // now in deg F temperature = ((temperature -32) / 1.8f); // now in deg C /* Below code is pixhawk version which DOES work correctly */ /* PX4temperature = ((200.0f * T_dat) / 2047) - 50; terminal.printf("PX4 Temperature: "); terminal.printf("%0.1f\n", PX4temperature); */ return temperature; } float MS4525DO::getAirSpeed(void){ // calculates and returns the airspeed /* Velocity calculation from a pitot tube explanation */ /* +/- 1PSI, approximately 100 m/s */ float rho = 1.225; // density of air // velocity = squareroot( (2*differential) / rho ) float velocity; if (psi<0) { velocity = -sqrt(-(2*psi) / rho); }else{ velocity = sqrt((2*psi) / rho); } velocity = velocity*10; return velocity; } int MS4525DO::calibrate(void){ // attempts to calibrate and returns a status code }