MS 4525DO

Hello community,

Has anyone used this differential pressure sensor to measure air speed?

I have been trying to program for it, there are limited sources online.

Here is the spec sheet:http://www.meas-spec.com/downloads/MS4525DO.pdf

There is some code I found for the sensor
here: Google Code Archive - Long-term storage for Google Code Project Hosting.

I am having trouble picking apart the code on here, I could really use some help.

If your interested in helping, I can post the code I am working with now. It's too long to post into one message.

Thanks for any and all help!

Sam

Try talk to your sensor..

The differential pressure can be made by eg. plastic tubes, open ends facing forward/backward.
(pitot-tube)
The code you have found contains useful information, too.

Using that pdf, I was just able to start communicating with the sensor. It does respond to changes in airflow.

However, I cannot get the values to come close to normal pressure reading. I tried to convert the values from the sensor using an equation given on the data sheet, page 4.
The eqn is A type Output (Decimal Counts)= ((.816383) / (Pmax-Pmin)) * (Papplied - Pmin) + (.116383)

However, I am not sure about a few things. Is the Pmax and Pmin a constant from the max range of the sensor? Then the value for Pmax - Pmin would be 1...for a 1psi range.

Or are those values variable readings?

I figured the Papplied is surely the variable. I solved the equation for Papplied, but I get an error message.

P_dat is my sensor output

Equation: Papplied = ((P_dat - (.116383))(1) / (.816383))

data sheet:http://www.meas-spec.com/downloads/MS4525DO.pdf

Here is the code I have written

#include <Wire.h> //I2C library 0x28H
  
byte fetch_pressure(unsigned int *p_Pressure); //convert value to byte data type


#define TRUE 1
#define FALSE 0

void setup(void)
{
   Serial.begin(9600);
   Wire.begin();
   pinMode(4, OUTPUT);
   pinMode(5, OUTPUT);
   digitalWrite(5, HIGH);  // SCL remains high
   digitalWrite(4, HIGH); // SDA transfers from high to low
   digitalWrite(4, LOW);  // this turns on the MS4525, I think
   delay(5000);
   Serial.println(">>>>>>>>>>>>>>>>>>>>>>>>");  // just to be sure things are working  
}

void loop()
{
  byte _status;
  unsigned int P_dat;
  float PR;
  
  while(1)
  {
    _status = fetch_pressure(&P_dat);
    
    switch(_status)
    {
      case 0: Serial.println("Read_MR.");
      break;
      case 1: Serial.println("Read_DF2.");
      break;
      case 2: Serial.println("Read_DF3.");
      break;
      default: Serial.println("Read_DF4.");
      break;
    }
    
    PR = (float)  ((P_dat - (.1*16383))(1) / (.8*16383)) ;
    
Serial.println(P_dat);
Serial.println(PR);
    Serial.print(" ");
    
    delay(1000);
  }
}
  
  byte fetch_pressure(unsigned int *p_P_dat)
  {
    
    
  byte address, Press_H, Press_L, _status;
  unsigned int P_dat;
  address= 0x28;;
  Wire.beginTransmission(address);  
  Wire.endTransmission();
  delay(100);
  
  Wire.requestFrom((int)address, (int) 4);
  Press_H = Wire.read();
  Press_L = Wire.read();
  Wire.endTransmission();
  
  
  _status = (Press_H >> 6) & 0x03;
      Press_H = Press_H & 0x3f;
      P_dat = (((unsigned int)Press_H) << 8) | Press_L;
      *p_P_dat = P_dat;
      return(_status);

  
  
  }
  
  /code]

No wonder you write.

Wire.requestFrom((int)address, (int) 4);//you request 4 bytes
But you read only 2 bytes.
Change the request to 2 and you see a reaction.
A little bit more commentary were be helpfully.
Then use the notation x.x and not .x that won't work.
()() do not work

//#include <WireMW.h>
#include <Wire.h>   //I2C library 0x28H 
byte fetch_pressure(unsigned int *p_Pressure); //convert value to byte data type


#define TRUE 1
#define FALSE 0

void setup(void)
{
   Serial.begin(9600);
   Wire.begin();
   delay(500);
   Serial.println(">>>>>>>>>>>>>>>>>>>>>>>>");  // just to be sure things are working  
}

void loop()
{
  byte _status;
  unsigned int P_dat;
  float PR;
  
  while(1)
  {
    _status = fetch_pressure(&P_dat);
    
    switch(_status)
    {
      case 0: Serial.println("Read_MR.");
      break;
      case 1: Serial.println("Read_DF2.");
      break;
      case 2: Serial.println("Read_DF3.");
      break;
      default: Serial.println("Read_DF4.");
      break;
    }
    
    
    PR = (float)((P_dat - (0.1*16383)) / (0.8*16383)) ;
    
Serial.println(P_dat);
Serial.println(PR);
    Serial.print(" ");
    
    delay(1000);
  }
}
  
  byte fetch_pressure(unsigned int *p_P_dat)
  {
    
    
  byte address, Press_H, Press_L, _status;
  unsigned int P_dat;
  address= 0x28;
  Wire.beginTransmission(address);  
  Wire.endTransmission();
  delay(100);
  
  Wire.requestFrom((int)address, (int) 4);//Request 4 bytes need 4 bytes are read
  Press_H = Wire.read();
  Press_L = Wire.read();
 byte Temp_H = Wire.read();
 byte  Temp_L = Wire.read();
  Wire.endTransmission();
  
  
  _status = (Press_H >> 6) & 0x03;
      Press_H = Press_H & 0x3f;
      P_dat = (((unsigned int)Press_H) << 8) | Press_L;
      *p_P_dat = P_dat;
      return(_status);

  
  
  }

Hi guy i had problems but you may want to see my code it works great !!

it was based on the codes here written but it needed a lil push

Please tell me if you would improve it

:slight_smile:

//#include <WireMW.h>
#include <Wire.h>   //I2C library 0x28H 
byte fetch_pressure(unsigned int *p_Pressure); //convert value to byte data type


#define TRUE 1
#define FALSE 0

void setup(void)
{
  Serial.begin(9600);
  Wire.begin();
  delay(500);
  Serial.println(">>>>>>>>>>>>>>>>>>>>>>>>");  // just to be sure things are working
}

void loop()
{
  byte _status;
  unsigned int P_dat;
  unsigned int T_dat;
  double PR;
  double TR;
  double V;
  double VV;
  while (1)
  {
    _status = fetch_pressure(&P_dat, &T_dat);

    switch (_status)
    {
      case 0: Serial.println("Ok ");
        break;
      case 1: Serial.println("Busy");
        break;
      case 2: Serial.println("Slate");
        break;
      default: Serial.println("Error");
        break;
    }


    PR = (double)((P_dat-819.15)/(14744.7)) ;
    PR = (PR - 0.49060678) ;
    PR = abs(PR);
     V = ((PR*13789.5144)/1.225);
    VV = (sqrt((V)));

    
    TR = (double)((T_dat*0.09770395701));
    TR = TR-50;
    
  
    
   Serial.print("raw Pressure:");
   Serial.println(P_dat);
   //Serial.println(P_dat,DEC);
   //Serial.println(P_dat,BIN);
   Serial.print("pressure psi:");
   Serial.println(PR,10);
   Serial.print(" ");
   Serial.print("raw Temp:");
   Serial.println(T_dat);
   Serial.print("temp:");
   Serial.println(TR);
   Serial.print("speed m/s :");
   Serial.println(VV,5);
  



    delay(1000);
  }
}

byte fetch_pressure(unsigned int *p_P_dat, unsigned int *p_T_dat)
{


  byte address, Press_H, Press_L, _status;
  unsigned int P_dat;
  unsigned int T_dat;

  address = 0x28;
  Wire.beginTransmission(address);
  Wire.endTransmission();
  delay(100);

  Wire.requestFrom((int)address, (int) 4);//Request 4 bytes need 4 bytes are read
  Press_H = Wire.read();
  Press_L = Wire.read();
  byte Temp_H = Wire.read();
  byte  Temp_L = Wire.read();
  Wire.endTransmission();


  _status = (Press_H >> 6) & 0x03;
  Press_H = Press_H & 0x3f;
  P_dat = (((unsigned int)Press_H) << 8) | Press_L;
  *p_P_dat = P_dat;

  Temp_L = (Temp_L >> 5);
  T_dat = (((unsigned int)Temp_H) << 3) | Temp_L;
  *p_T_dat = T_dat;
  return (_status);



}
1 Like

Background: Just before Christmas I had a massive tear of my rotator cuff. While waiting on surgery and recovery, I decided to take on a project that required me to learn arduino programming. Considering my only prior programming was basic on a Commodore 64 (many many years ago), I have done quite well with the effort. But I'm still struggling with certain aspects. Hence, this question.

While trying to extract the pressure and temperature data, via I2C, from a 86BSD-015PG-3AIC "gage" sensor - I became stumped. While searching for prior art, I might learn from, I found this thread using a similar (internally anyway) MS 4525DO "differential" sensor. I understand most of the code, but what I am learning is "bitmath and bit shifting" at the bottom of the code is beyond my current understanding.

Rather than output the differential pressure and calculate speed as in the original code, my goal is to output a single gage pressure and calculate water depth (vessel draft actually). But so far I have been unable to modify the code to get the raw pressure to zero. It currently hovers around 1590 digital counts, equating to 1.45psi and 3.36' deep.

Can anyone offer me some direction? Thanks, Steve.

PS: The temperature output seems to be working very well!

86BSD datasheet... http://www.te.com/commerce/DocumentDelivery/DDEController?Action=srchrtrv&DocNm=86BSD&DocType=Data+Sheet&DocLang=English&DocFormat=pdf&PartCntxt=CAT-MIPS0037

_4-21-17-pres-temp.ino (2.1 KB)

Sorry I missed the insert code in the prior post:

#include <Wire.h>   //I2C library 0x28H 
byte fetch_pressure(unsigned int *p_Pressure); //convert value to byte data type

#define TRUE 1
#define FALSE 0

void setup(void)
{
  Serial.begin(9600);
  Wire.begin();
  delay(500);
  Serial.println(">>>>>>>>>>>>>>>>>>>>>>>>");  // just to be sure things are working
}

void loop()
{
  byte _status;
  unsigned int P_dat;
  unsigned int T_dat;
  double P;
  double PR;
  double TR;
  double V;
  double VV;
  while (1)
  {
    _status = fetch_pressure(&P_dat, &T_dat);

    switch (_status)
    {
      case 0: Serial.println("Ok ");
        break;
      case 1: Serial.println("Busy");
        break;
      case 2: Serial.println("Slate");
        break;
      default: Serial.println("Error");
        break;
    }

    PR = (double)((P_dat-819.15)/(14744.7)) ;
    PR = (PR - 0.49060678) ;
    PR = abs(PR);
     P = (double) P_dat*.0009155;
     V = ((PR*13789.5144)/1.225);
    VV = (sqrt((V)));
  
    TR = (double)((T_dat*0.09770395701));
    TR = TR-50;

   Serial.print("raw Pressure:");  
   Serial.println(P_dat);
   Serial.print("pressure psi:");
   Serial.println(P,10);
   Serial.print("Draft:");
   Serial.println(P*2.3067);
   
   Serial.print(" ");
   Serial.print("raw Temp:");
   Serial.println(T_dat);
   Serial.print("tempC:");
   Serial.println(TR); 
   Serial.print("tempF:");
   Serial.println((TR*1.8)+32);
   Serial.println(" ");
  
    delay(3000);
  }
}

byte fetch_pressure(unsigned int *p_P_dat, unsigned int *p_T_dat)
{
  byte address, Press_H, Press_L, _status;
  unsigned int P_dat;
  unsigned int T_dat;

  address = 0x28;
  Wire.beginTransmission(address);
  Wire.endTransmission();
  delay(100);

  Wire.requestFrom((int)address, (int) 4);//Request 4 bytes need 4 bytes are read
  Press_H = Wire.read();
  Press_L = Wire.read();
  byte Temp_H = Wire.read();
  byte  Temp_L = Wire.read();
  Wire.endTransmission();

  _status = (Press_H >> 6) & 0x03;
  Press_H = Press_H & 0x3f;
  P_dat = (((unsigned int)Press_H) << 8) | Press_L;
  *p_P_dat = P_dat;

  Temp_L = (Temp_L >> 5);
  T_dat = (((unsigned int)Temp_H) << 3) | Temp_L;
  *p_T_dat = T_dat;
  return (_status);

}

I'm not familiar with that sensor, but looking at the datasheet, looks like zero PSI = 0x666 or 1638 decimal, close to your 1590, let's call 1590 zero and full scale is 0x399A or 14746, so subtracting 1590 you have a range of 0 - 13156 = 0 to 15PSI. Let's say, after subtracting your offset (1590) you have a remaining count of 5555, 5555 / 13156 * 15PSI = 6.333 * 2.307 = 14.61ft.
Keep checking back, I'm sure one of the "gurus" will stop by and help with your program.

Hmmm. Am I reading the datasheet wrong? I am new to all this, but from looking at figure 4 the 86BSD datasheet I thought the 0x0666 or 1638 decimal was 10% of the output. And I assumed 10% of my 15psi sensor would be 1.5psi.

You're probably right, guess the best approach is trial and error, do you have an air pump, accurate gauge and a way to tee in the sensor?

Yeah. I have it hooked up to a pump and 10psi gauge (good enough because my application will seldom go above 7psi). And I've been changing various areas of the code to see if I can accidentally get things working the way I expect - but have not stumbled onto the right solution yet. I'm really struggling understanding what the bit shifting is doing at the bottom of the code. Appreciate anyone else's input.
Thanks again, Steve.

The bit shifting is done because the reading from the sensor is a 16 bit integer (2 bytes) and Wire only transfers 1 byte at a time, the bit shifting assembles the 2 bytes back to the whole 16 bit integer.
What kind of counts do you get at zero, 5 and 10PSI?
EDIT: After thinking about it, I believe the 10-90% thing is about guaranteed accuracy between 2 known points and then extrapolating to zero and full range, so maybe you should calibrate at 1.5 and 13.5 PSI and just take what you get outside that range. I know load cells are not very accurate and linear at the lower 3 - 4% of their range, I always preloaded them to 5% then subtracted that reading and called it "zero".

Ok on the bit shifting. My current pressuring system is good, but not precision. Here are some readings.

0 PSI = 1590 digital counts
1.5 PSI = 3000 digital counts
5.0 PSI = 6250 digital counts
7.5 PSI = 8300 digital counts
10PSI= 10600 digital counts

Given 100% output (according to table in Figure-4) yields 16383 digital counts for my 15 PSI sensor. And the other percentages in the table are precisely 1092.2 digital counts per PSI. So I would expect 0 PSI to be zero digital counts - not 1590, and 1.5 PSI to be 1638 digital counts - not 3000. I almost feel like the sensor is working properly, and something in the program is skewing the count, but have yet to figure out what it is.

I understand your point on the load cells. If I get a sensor working in this application, it will never really be reading zero. It will start at about .5 PSI and vary to a max of 6-7 PSI. So hopefully I will be in a fairly precise zone of a 7.5 or 15 PSI sensor.

So it is not the program skewing the count. I did a very basic sketch to read bytes 1, 2 & 3. At zero PSI

byte1 = 6 (high byte)
byte2 = 54 (low byte)
byte3 = 97 (temperature)

If I then combine the two 8 bit integers into a 16 bit integer....((high byte*256)+low byte)....

Decimal count = 1590 ((6*256)+54)

My confusion is obviously in how I interpret these Digital counts into pressure.

NOTE: As I apply pressure to the sensor, bytes 1 & 2 go up and byte 3 remains static. If I blow hot air onto the sensor, byte 3 goes up and bytes 1 & 2 remain static.

I try to read inHg with this sensor. MS4525DO but i have the J model (0x36H) single port. It's a compound pressure types.

What's the ''P'' ? P = (double) P_dat*.0009155;

Hello Sam, if you solved the problem, can you share it with us?

can someone share worked code?

hello everybody,
this is my first time i m posting something in arduino forum.

(this is the same code taken from above actually)
Below is the code for MS 4525DO.
sensor i m using is for 1 psi pressure.this code reads pressure but the it can read up to 0.5 psi only.
do any one know why the 1 psi sensor is reading 0.5 psi only?

void process_calculations()
{
PR = (double)((P_dat - 819.15) / (14744.7)) ;
PR = (PR - 0.49060678) ;
// PR = abs(PR);
if (PR < 0)
{
PR = (PR * (-1));
}
V = ((PR * 13789.5144) / 1.225);
VV = (sqrt((V)));
TR = (double)((T_dat * 0.09770395701));
TR = TR - 50;
if (PR < 0.00145)//if less than 10 pascal make it zero
{
PR = 0;
}
pascal = PR * 6894.76;

}

byte fetch_pressure(unsigned int *p_P_dat, unsigned int *p_T_dat)
{
byte address, Press_H, Press_L, _status;
unsigned int P_dat;
unsigned int T_dat;

address = 0x28;
Wire.beginTransmission(address);
Wire.endTransmission();
//delay(100);

Wire.requestFrom((int)address, (int) 4);//Request 4 bytes need 4 bytes are read
Press_H = Wire.read();
Press_L = Wire.read();
byte Temp_H = Wire.read();
byte Temp_L = Wire.read();
Wire.endTransmission();

_status = (Press_H >> 6) & 0x03;
Press_H = Press_H & 0x3f;
P_dat = (((unsigned int)Press_H) << 8) | Press_L;
*p_P_dat = P_dat;

Temp_L = (Temp_L >> 5);
T_dat = (((unsigned int)Temp_H) << 3) | Temp_L;
*p_T_dat = T_dat;
return (_status);
}

I had some trouble with some of the examples for the MS4525DO pressure sensor. I modified the code and have no trouble with the code below. Tested on a Leonardo. I only read pressure, not temperature. I included a sensor definition section near the top of my code so several versions of the MS4525 can be used.
I used this part for a Raspberry Pi project here: PyFly HAT-ish Board

Feel free to use this code without any restrictions.

// File MS4525_Test
//
// A Arduino program to test the operation of pressure sensors in the TE Connectivity MS4525D series (I2C versions only)
//
// Written: 7/9/2019
// Rev.: 1.00
// Changes: First release back to the community. Started with bits of code downloaded from the Arduino forums.
//
// The sensor specific characteristics are setup with constants in the beginning of the program.
// The device page is https://www.te.com/usa-en/product-CAT-BLPS0002.html
// The device data sheet can be found at https://www.te.com/commerce/DocumentDelivery/DDEController?Action=showdoc&DocId=Data+SheetMS4525DOB10pdfEnglishENG_DS_MS4525DO_B10.pdfCAT-BLPS0002
//

#include <Wire.h> // Arduino I2C library
#include <stdint.h> // Standard C, Allows explicit data type declaration.

//////////////////////////////////////////////////////////////////////////////////////
// MS4525D sensor characteristics (from the 4/2019 version of the data sheet)
//////////////////////////////////////////////////////////////////////////////////////

// MS4525D sensor I2C address (uncomment the Interface Type of the device you are using)
// Interface Type I
const uint8_t MS4525DAddress = 0x28;
// Interface Type J
//const uint8_t MS4525DAddress = 0x36;
// Interface Type K
//const uint8_t MS4525DAddress = 0x46;
// Interface Type 0
//const uint8_t MS4525DAddress = 0x48;

// MS4525D sensor full scale range and units
const int16_t MS4525FullScaleRange = 1; // 1 psi
//const int16_t MS4525FullScaleRange = 0.0689476; // 1 psi in Bar
//const int16_t MS4525FullScaleRange = 6895; // 1 psi in Pascal
//const int16_t MS4525FullScaleRange = 2; // 2 psi
//const int16_t MS4525FullScaleRange = 5; // 5 psi

// MS4525D Sensor type (A or B) comment out the wrong type assignments
// Type A (10% to 90%)
const int16_t MS4525MinScaleCounts = 1638;
const int16_t MS4525FullScaleCounts = 14746;
// Type B (5% to 95%)
//const int16_t MS4525MinScaleCounts = 819;
//const int16_t MS4525FullScaleCounts = 15563;
const int16_t MS4525Span=MS4525FullScaleCounts-MS4525MinScaleCounts;

//MS4525D sensor pressure style, differential or otherwise. Comment out the wrong one.
//Differential
const int16_t MS4525ZeroCounts=(MS4525MinScaleCounts+MS4525FullScaleCounts)/2;
// Absolute, Gauge
//const int16_t MS4525ZeroCounts=MS4525MinScaleCounts;

//////////////////////////////////////////////////////////////////////////////////////
// end of MS4525D sensor characteristics
//////////////////////////////////////////////////////////////////////////////////////

// fetch_pressure is a function to do the I2C read and extraction of the three data fields
//
byte fetch_pressure(uint16_t &P_dat, uint16_t &T_dat)
{
byte _status;
byte Press_H;
byte Press_L;
byte Temp_H;
byte Temp_L;

Wire.requestFrom(MS4525DAddress, static_cast<uint8_t>(4), static_cast<uint8_t>(true)); //Request 4 bytes, 2 pressure/status and 2 temperature
Press_H = Wire.read();
Press_L = Wire.read();
Temp_H = Wire.read();
Temp_L = Wire.read();

_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;

}

// setup is the main function to setup the diagnostic serial port and the I2C port
void setup()
{

Serial.begin(115200);
Wire.begin();
// wait until serial port opens for native USB devices
while (! Serial)
{
delay(1);
}

Serial.println("MS4525DO test");

}

void loop()
{

byte _status; // A two bit field indicating the status of the I2C read
uint16_t P_dat; // 14 bit pressure data
uint16_t T_dat; // 11 bit temperature data
float psi;

_status = fetch_pressure(P_dat, T_dat);

switch (_status)
{
case 0:
//Serial.println("Ok ");
break;
case 1:
Serial.println("Busy");
break;
case 2:
Serial.println("Slate");
break;
default:
Serial.println("Error");
break;
}

psi=(static_cast(static_cast<int16_t>(P_dat)-MS4525ZeroCounts))/static_cast(MS4525Span)*static_cast(MS4525FullScaleRange);
Serial.print("psi:");
Serial.println(psi);

}

Good luck.

Update to MS4525_Test.

8 and right parentheses got converted to an emoji. Correct line:

P_dat = (((uint16_t)Press_H) << 8 ) | Press_L; // space added after '8' so code can be uploaded without emoji conversion!

Sorry,