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@0:5965bf423184, 2019-09-13 (annotated)
- Committer:
- epremeaux
- Date:
- Fri Sep 13 08:41:37 2019 +0000
- Revision:
- 0:5965bf423184
initial commit. I dont trust the output values yet
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
epremeaux | 0:5965bf423184 | 1 | |
epremeaux | 0:5965bf423184 | 2 | #include "mbed.h" |
epremeaux | 0:5965bf423184 | 3 | #include "MS4525DO.h" |
epremeaux | 0:5965bf423184 | 4 | |
epremeaux | 0:5965bf423184 | 5 | |
epremeaux | 0:5965bf423184 | 6 | MS4525DO::MS4525DO(PinName sda, PinName scl, char slave_adr) |
epremeaux | 0:5965bf423184 | 7 | : |
epremeaux | 0:5965bf423184 | 8 | i2c_p(new I2C(sda, scl)), |
epremeaux | 0:5965bf423184 | 9 | i2c(*i2c_p), |
epremeaux | 0:5965bf423184 | 10 | address(slave_adr<<1) |
epremeaux | 0:5965bf423184 | 11 | { |
epremeaux | 0:5965bf423184 | 12 | initialize(); |
epremeaux | 0:5965bf423184 | 13 | } |
epremeaux | 0:5965bf423184 | 14 | |
epremeaux | 0:5965bf423184 | 15 | MS4525DO::MS4525DO(I2C &i2c_obj, char slave_adr) |
epremeaux | 0:5965bf423184 | 16 | : |
epremeaux | 0:5965bf423184 | 17 | i2c_p(NULL), |
epremeaux | 0:5965bf423184 | 18 | i2c(i2c_obj), |
epremeaux | 0:5965bf423184 | 19 | address(slave_adr<<1) |
epremeaux | 0:5965bf423184 | 20 | { |
epremeaux | 0:5965bf423184 | 21 | initialize(); |
epremeaux | 0:5965bf423184 | 22 | } |
epremeaux | 0:5965bf423184 | 23 | |
epremeaux | 0:5965bf423184 | 24 | MS4525DO::~MS4525DO() |
epremeaux | 0:5965bf423184 | 25 | { |
epremeaux | 0:5965bf423184 | 26 | if (NULL != i2c_p) |
epremeaux | 0:5965bf423184 | 27 | delete i2c_p; |
epremeaux | 0:5965bf423184 | 28 | } |
epremeaux | 0:5965bf423184 | 29 | |
epremeaux | 0:5965bf423184 | 30 | |
epremeaux | 0:5965bf423184 | 31 | /* public functions |
epremeaux | 0:5965bf423184 | 32 | void initialize(void); |
epremeaux | 0:5965bf423184 | 33 | int measure(void); // returns status of measurement |
epremeaux | 0:5965bf423184 | 34 | float getPSI(void); // returns the PSI of last measurement |
epremeaux | 0:5965bf423184 | 35 | float getTemperature(void); // returns temperature of last measurement |
epremeaux | 0:5965bf423184 | 36 | float getAirSpeed(void); // calculates and returns the airspeed |
epremeaux | 0:5965bf423184 | 37 | int calibrate(void); // attempts to calibrate and returns a status code |
epremeaux | 0:5965bf423184 | 38 | */ |
epremeaux | 0:5965bf423184 | 39 | |
epremeaux | 0:5965bf423184 | 40 | void MS4525DO::initialize() |
epremeaux | 0:5965bf423184 | 41 | { |
epremeaux | 0:5965bf423184 | 42 | // i2c writes to set up addresses, etc. |
epremeaux | 0:5965bf423184 | 43 | |
epremeaux | 0:5965bf423184 | 44 | } |
epremeaux | 0:5965bf423184 | 45 | |
epremeaux | 0:5965bf423184 | 46 | // combine measure and collect into one function that returns the status code only, and holds the results in variables |
epremeaux | 0:5965bf423184 | 47 | // other subroutines for returning clean values should be get functions |
epremeaux | 0:5965bf423184 | 48 | |
epremeaux | 0:5965bf423184 | 49 | |
epremeaux | 0:5965bf423184 | 50 | int MS4525DO::measure() |
epremeaux | 0:5965bf423184 | 51 | { |
epremeaux | 0:5965bf423184 | 52 | char ret; |
epremeaux | 0:5965bf423184 | 53 | ret = fetch_pressure(P_dat, T_dat); |
epremeaux | 0:5965bf423184 | 54 | return ret; |
epremeaux | 0:5965bf423184 | 55 | } |
epremeaux | 0:5965bf423184 | 56 | |
epremeaux | 0:5965bf423184 | 57 | |
epremeaux | 0:5965bf423184 | 58 | char MS4525DO::fetch_pressure(uint16_t &P_dat, uint16_t &T_dat) |
epremeaux | 0:5965bf423184 | 59 | { |
epremeaux | 0:5965bf423184 | 60 | char _status; |
epremeaux | 0:5965bf423184 | 61 | char Press_H; |
epremeaux | 0:5965bf423184 | 62 | char Press_L; |
epremeaux | 0:5965bf423184 | 63 | char Temp_H; |
epremeaux | 0:5965bf423184 | 64 | char Temp_L; |
epremeaux | 0:5965bf423184 | 65 | |
epremeaux | 0:5965bf423184 | 66 | char cmd[1]; |
epremeaux | 0:5965bf423184 | 67 | cmd[0] = 0x00; |
epremeaux | 0:5965bf423184 | 68 | // 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). |
epremeaux | 0:5965bf423184 | 69 | // MS4525DAddress |
epremeaux | 0:5965bf423184 | 70 | i2c.write(address, cmd, 1, true); // select the register, no I2C Stop |
epremeaux | 0:5965bf423184 | 71 | |
epremeaux | 0:5965bf423184 | 72 | |
epremeaux | 0:5965bf423184 | 73 | char data[4]; |
epremeaux | 0:5965bf423184 | 74 | // i2c.read(MS4525DAddress, static_cast<uint8_t>(4), static_cast<uint8_t>(true)); //Request 4 bytes, 2 pressure/status and 2 temperature |
epremeaux | 0:5965bf423184 | 75 | i2c.read(address, data, 4); |
epremeaux | 0:5965bf423184 | 76 | |
epremeaux | 0:5965bf423184 | 77 | |
epremeaux | 0:5965bf423184 | 78 | Press_H = data[0]; |
epremeaux | 0:5965bf423184 | 79 | Press_L = data[1]; |
epremeaux | 0:5965bf423184 | 80 | Temp_H = data[2]; |
epremeaux | 0:5965bf423184 | 81 | Temp_L = data[3]; |
epremeaux | 0:5965bf423184 | 82 | |
epremeaux | 0:5965bf423184 | 83 | _status = (Press_H >> 6) & 0x03; |
epremeaux | 0:5965bf423184 | 84 | Press_H = Press_H & 0x3f; |
epremeaux | 0:5965bf423184 | 85 | P_dat = (((uint16_t)Press_H) << 8) | Press_L; |
epremeaux | 0:5965bf423184 | 86 | |
epremeaux | 0:5965bf423184 | 87 | Temp_L = (Temp_L >> 5); |
epremeaux | 0:5965bf423184 | 88 | T_dat = (((uint16_t)Temp_H) << 3) | Temp_L; |
epremeaux | 0:5965bf423184 | 89 | |
epremeaux | 0:5965bf423184 | 90 | return _status; |
epremeaux | 0:5965bf423184 | 91 | } |
epremeaux | 0:5965bf423184 | 92 | |
epremeaux | 0:5965bf423184 | 93 | |
epremeaux | 0:5965bf423184 | 94 | |
epremeaux | 0:5965bf423184 | 95 | float MS4525DO::getPSI(void){ // returns the PSI of last measurement |
epremeaux | 0:5965bf423184 | 96 | // convert and store PSI |
epremeaux | 0:5965bf423184 | 97 | psi=(static_cast<float>(static_cast<int16_t>(P_dat)-MS4525ZeroCounts))/static_cast<float>(MS4525Span)*static_cast<float>(MS4525FullScaleRange); |
epremeaux | 0:5965bf423184 | 98 | // apply PSI calibration data |
epremeaux | 0:5965bf423184 | 99 | // psi = psi + 0.007f; |
epremeaux | 0:5965bf423184 | 100 | |
epremeaux | 0:5965bf423184 | 101 | /* Below code is Pixhawk code which doesnt seem to work correctly */ |
epremeaux | 0:5965bf423184 | 102 | // Calculate differential pressure. As its centered around 8000 |
epremeaux | 0:5965bf423184 | 103 | // and can go positive or negative |
epremeaux | 0:5965bf423184 | 104 | /* |
epremeaux | 0:5965bf423184 | 105 | const float P_min = -1.0f; |
epremeaux | 0:5965bf423184 | 106 | const float P_max = 1.0f; |
epremeaux | 0:5965bf423184 | 107 | const float PSI_to_Pa = 6894.757f; |
epremeaux | 0:5965bf423184 | 108 | */ |
epremeaux | 0:5965bf423184 | 109 | /* |
epremeaux | 0:5965bf423184 | 110 | this equation is an inversion of the equation in the |
epremeaux | 0:5965bf423184 | 111 | pressure transfer function figure on page 4 of the datasheet |
epremeaux | 0:5965bf423184 | 112 | We negate the result so that positive differential pressures |
epremeaux | 0:5965bf423184 | 113 | are generated when the bottom port is used as the static |
epremeaux | 0:5965bf423184 | 114 | port on the pitot and top port is used as the dynamic port |
epremeaux | 0:5965bf423184 | 115 | */ |
epremeaux | 0:5965bf423184 | 116 | /* |
epremeaux | 0:5965bf423184 | 117 | float diff_press_PSI = -((T_dat - 0.1f * 16383) * (P_max - P_min) / (0.8f * 16383) + P_min); |
epremeaux | 0:5965bf423184 | 118 | float diff_press_pa_raw = diff_press_PSI * PSI_to_Pa; |
epremeaux | 0:5965bf423184 | 119 | */ |
epremeaux | 0:5965bf423184 | 120 | |
epremeaux | 0:5965bf423184 | 121 | |
epremeaux | 0:5965bf423184 | 122 | return psi; |
epremeaux | 0:5965bf423184 | 123 | } |
epremeaux | 0:5965bf423184 | 124 | |
epremeaux | 0:5965bf423184 | 125 | float MS4525DO::getTemperature(void){ // returns temperature of last measurement |
epremeaux | 0:5965bf423184 | 126 | // convert and store Temperature |
epremeaux | 0:5965bf423184 | 127 | temperature= (static_cast<float>(static_cast<int16_t>(T_dat))); |
epremeaux | 0:5965bf423184 | 128 | temperature = (temperature / 10); // now in deg F |
epremeaux | 0:5965bf423184 | 129 | temperature = ((temperature -32) / 1.8f); // now in deg C |
epremeaux | 0:5965bf423184 | 130 | |
epremeaux | 0:5965bf423184 | 131 | /* Below code is pixhawk version which DOES work correctly */ |
epremeaux | 0:5965bf423184 | 132 | /* |
epremeaux | 0:5965bf423184 | 133 | PX4temperature = ((200.0f * T_dat) / 2047) - 50; |
epremeaux | 0:5965bf423184 | 134 | terminal.printf("PX4 Temperature: "); |
epremeaux | 0:5965bf423184 | 135 | terminal.printf("%0.1f\n", PX4temperature); |
epremeaux | 0:5965bf423184 | 136 | */ |
epremeaux | 0:5965bf423184 | 137 | |
epremeaux | 0:5965bf423184 | 138 | return temperature; |
epremeaux | 0:5965bf423184 | 139 | } |
epremeaux | 0:5965bf423184 | 140 | |
epremeaux | 0:5965bf423184 | 141 | float MS4525DO::getAirSpeed(void){ // calculates and returns the airspeed |
epremeaux | 0:5965bf423184 | 142 | /* Velocity calculation from a pitot tube explanation */ |
epremeaux | 0:5965bf423184 | 143 | /* +/- 1PSI, approximately 100 m/s */ |
epremeaux | 0:5965bf423184 | 144 | float rho = 1.225; // density of air |
epremeaux | 0:5965bf423184 | 145 | // velocity = squareroot( (2*differential) / rho ) |
epremeaux | 0:5965bf423184 | 146 | float velocity; |
epremeaux | 0:5965bf423184 | 147 | if (psi<0) { |
epremeaux | 0:5965bf423184 | 148 | velocity = -sqrt(-(2*psi) / rho); |
epremeaux | 0:5965bf423184 | 149 | }else{ |
epremeaux | 0:5965bf423184 | 150 | velocity = sqrt((2*psi) / rho); |
epremeaux | 0:5965bf423184 | 151 | } |
epremeaux | 0:5965bf423184 | 152 | velocity = velocity*10; |
epremeaux | 0:5965bf423184 | 153 | |
epremeaux | 0:5965bf423184 | 154 | return velocity; |
epremeaux | 0:5965bf423184 | 155 | } |
epremeaux | 0:5965bf423184 | 156 | |
epremeaux | 0:5965bf423184 | 157 | |
epremeaux | 0:5965bf423184 | 158 | int MS4525DO::calibrate(void){ // attempts to calibrate and returns a status code |
epremeaux | 0:5965bf423184 | 159 | |
epremeaux | 0:5965bf423184 | 160 | } |