Comunicating with I2C with a relative pressure sensor

Hello!

I just got this relative pressure sensor that communicates through I2C protocol and I am having some issues:

https://www.mouser.es/ProductDetail/683-ELVHMF25DHDCN2A4

After doing the connections as seen on the image (3.3v sensor), the blue orange, and red are just logic analyzer cables:

and using the following code, where I get 4 bytes that represent the current pressure and temperature values as the datasheet says :


#include <Wire.h>

int ELVHAddress = 0x28;

byte byte1,byte2,byte3,byte4;

void setup() {
  Wire.begin();
  Serial.begin(9600);

}

void loop() {  
  
  Wire.beginTransmission(ELVHAddress);  
  Wire.requestFrom(ELVHAddress,4);
  
  if(Wire.available()<=4){
    byte1 = Wire.read();
    byte2 = Wire.read();
    byte3 = Wire.read();
    byte4 = Wire.read();
  }
  Wire.endTransmission();
  
  Serial.print("   byte1 = ");
  Serial.print(byte1);
  Serial.print("   byte2 = ");
  Serial.print(byte2);
  Serial.print("   byte3 = ");
  Serial.print(byte3);
  Serial.print("   byte4 = ");
  Serial.print(byte4);
  Serial.println();

  delay(2000);
}

And I get the following messages from arduino:

12:32:15.889 -> byte1 = 31 byte2 = 166 byte3 = 101 byte4 = 195
12:32:17.913 -> byte1 = 31 byte2 = 164 byte3 = 101 byte4 = 195
12:32:19.912 -> byte1 = 31 byte2 = 166 byte3 = 101 byte4 = 195
12:32:21.887 -> byte1 = 31 byte2 = 170 byte3 = 101 byte4 = 195
12:32:23.907 -> byte1 = 31 byte2 = 164 byte3 = 101 byte4 = 195
12:32:25.923 -> byte1 = 31 byte2 = 168 byte3 = 101 byte4 = 195
12:32:27.918 -> byte1 = 31 byte2 = 161 byte3 = 101 byte4 = 195
12:32:29.902 -> byte1 = 31 byte2 = 162 byte3 = 101 byte4 = 195
12:32:31.929 -> byte1 = 31 byte2 = 164 byte3 = 101 byte4 = 195
12:32:33.916 -> byte1 = 31 byte2 = 168 byte3 = 101 byte4 = 195
12:32:35.908 -> byte1 = 31 byte2 = 164 byte3 = 101 byte4 = 195
12:32:37.933 -> byte1 = 31 byte2 = 166 byte3 = 101 byte4 = 195
12:32:39.899 -> byte1 = 31 byte2 = 162 byte3 = 101 byte4 = 195
12:32:41.923 -> byte1 = 31 byte2 = 170 byte3 = 101 byte4 = 195
12:32:43.898 -> byte1 = 31 byte2 = 170 byte3 = 101 byte4 = 195

The problem I have is that from reading the datasheet I don't understand how to interpret these 4 bytes of information. Here are the 2 pages of information on all the datasheet about the I2C communication:

From this last image, I can understand that the pressure measurement is 14bits long and the temperature measurement is 11bits long... this means that I should get the first 14 bits of bytes 1 and 2 to form the pressure measurement and the first 11 bits of bytes 3 and 4 to form the temperature measurement? if so, how could I do so?

Yes.

No, not the first 14 bits but the last. The first two bits show the status.

uint16_t temp = byte3;
temp <<= 8;
temp |= byte4;
temp >>= 5;
uint16_t pres = byte1 & 0x3f;
pres <<= 8;
pres |= byte2;

Bad code style and logically incorrect (what if the available number of bytes is only 2?).

You should make the if around the Wire.requestFrom():

  if (Wire.requestFrom(ELVHAddress, 4) == 4) {
    byte1 = Wire.read();
    byte2 = Wire.read();
    byte3 = Wire.read();
    byte4 = Wire.read();
  }

and remove the Wire.beginTransmission() and Wire.endTransmission() calls, they are not needed here.

The value returned by requestFrom() method is always equal to the bytes requested; then, why not simply --

byte m = Wire.requestFrom(ELVHAddress, 4);

Hello,

I just modified the code as recommended, and I guess there is something missing such as conversion factor or so... Here are both code and results:


#include <Wire.h>

int ELVHAddress = 0x28;

byte byte1,byte2,byte3,byte4;
int pressure,temperature;

void setup() {
  Wire.begin();
  Serial.begin(9600);

}

void loop() {  
  
  Wire.requestFrom(ELVHAddress,4);
  
    byte1 = Wire.read();
    byte2 = Wire.read();
    byte3 = Wire.read();
    byte4 = Wire.read();  
    
  Serial.print("   byte1 = ");
  Serial.print(byte1);
  Serial.print("   byte2 = ");
  Serial.print(byte2);
  Serial.print("   byte3 = ");
  Serial.print(byte3);
  Serial.print("   byte4 = ");
  Serial.print(byte4);
  Serial.println();
  uint16_t temp = byte3;
  temp <<= 8;
  temp |= byte4;
  temp >>= 5;
  uint16_t pres = byte1 & 0x3f;
  pres <<= 8;
  pres |= byte2;

  Serial.print("   PRESSURE = ");
  Serial.print(pres);
  Serial.print("   TEMPERATURE = ");  
  Serial.print(temp);
  Serial.println();

  delay(2000);
}

RESULTS:
17:43:48.339 -> PRESSURE = 8091 TEMPERATURE = 818
17:43:50.350 -> byte1 = 31 byte2 = 155 byte3 = 102 byte4 = 67
17:43:50.396 -> PRESSURE = 8091 TEMPERATURE = 818
17:43:52.368 -> byte1 = 31 byte2 = 159 byte3 = 102 byte4 = 67
17:43:52.412 -> PRESSURE = 8095 TEMPERATURE = 818
17:43:54.391 -> byte1 = 31 byte2 = 155 byte3 = 102 byte4 = 67
17:43:54.438 -> PRESSURE = 8091 TEMPERATURE = 818

Upload the following sketch (your one is slightly modified) and report what you are getting for Temperature. Check data sheet of your sensor if there is any scaling factor for the raw value of temp.

#include <Wire.h>
int ELVHAddress = 0x28;
byte myData[4];

void setup()
{
  Wire.begin();
  Serial.begin(9600);
}

void loop()
{
  byte m = Wire.requestFrom(ELVHAddress, 4);
  for (int i = 0; i < m; i++)
  {
    myData[i] = Wire.read();
  }

  unsigned myTemp = (myData[2] << 3) | (myData[3] >> 5); //D15, ..., D5
  Seral.println(myTemp, DEC);
  delay(2000);
}

This is wrong! The return value is the number of bytes actually read. In case of a wrong wiring you get 0.

My code just gets the raw value.

According to the datasheet:

ELVH Output Performance Specification Notes
Note 5: Full Scale Span (FSS) is the algebraic difference between the output signal for the highest and lowest specfied
pressure.

so you have to look at your specific type and 0 will be the lowest pressure specified, 16383 will be the upper limit. Unfortunately I didn't find any such information about the temperature.

1 Like

18:20:34.328 -> 820

I messaged the company to see if they have an answer for the temperature. I will post it if they answer back.

so you have to look at your specific type and 0 will be the lowest pressure specified, 16383 will be the upper limit. Unfortunately I didn't find any such information about the temperature.

Thank you very much! @pylon

What is this 820? does it change when you change temperature by heating up/cooling down the sensor?

Do a print command on a healthy I2C system.
When there is wrong wiring; there is no I2C Bus; then, from where will you get 0?

yes, this is the temperature output. If I heat it up by putting it in the hot air fan output of my laptop the value goes up to 974.

So it may be the temperature in Fahrenheit * 10.

That's what the code returns if there is a hardware problem, so it's from the library.
There is also the possibility that the I2C slave device only returns one byte per cycle but your code ask for 3, the Wire.requestFrom() will not return what you provided as a parameter (3) but what it actually read (1).

So, the sketch is working. Now, calibrate this raw reading into actual temperature. Give a link to the data sheets of your temp sensor.

It looks like that fit perfectly. The temperature sensor is in the same pressure sensor.

Library gives the ready-made routines/function that are integrated with sketch during compilation/linking. It does not give the data. Data comes from the real hardware -- the sensor/register/memory.

GolamMostafa please stop posting such nonsense. The return value of a method doesn't have to originate from a sensor or device register. Of course it is written to a CPU register when returned but nevertheless the origin of a 0 value in the case of Wire.requestFrom may be the code you'll find in the corresponding library. If there is a problem in the communication with the addressed I2C device the library returns 0 (and not the parameter provided that represents the number of bytes to read).

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.