Code help to receive data from I2C vacuum pressure sensor

Hello,

I'm trying to interface with an I2C pressure sensor (Amphenol NPI-19J-030A2). Using the "i2C_scanner" example from Wire.h, I verified that my sensor is connected to my Arduino (Uno) on register 0x28. Using the code below, I am able to get 6 pieces of data that seem to change as I change the pressure, but I don't understand how to interpret this data. The code comes from an IMU example I found and modified but I think some values probably don't make sense for my device like the "configure registers", "data output rate", etc.

Can someone help me interpret the i2c portion of the sensor's data sheet and modify the code to collect data from the sensor? How do I implement the information on the data sheet that describes the i2c comms? Would I need to create a custom library?

Thank you!!

Here's a sample of the below code's serial output:
16:18:42.198 -> total:832, d[0]:159, d[1]:146, d[2]:95, d[3]:115, d[4]:242, d[5]:75
16:18:42.992 -> total:832, d[0]:159, d[1]:146, d[2]:95, d[3]:115, d[4]:242, d[5]:75
16:18:43.788 -> total:832, d[0]:159, d[1]:146, d[2]:95, d[3]:115, d[4]:242, d[5]:75
16:18:44.630 -> total:688, d[0]:31, d[1]:146, d[2]:95, d[3]:99, d[4]:242, d[5]:75
16:18:45.421 -> total:832, d[0]:159, d[1]:146, d[2]:95, d[3]:115, d[4]:242, d[5]:75
16:18:46.216 -> total:832, d[0]:159, d[1]:146, d[2]:95, d[3]:115, d[4]:242, d[5]:75
16:18:47.012 -> total:688, d[0]:31, d[1]:146, d[2]:95, d[3]:99, d[4]:242, d[5]:75
16:18:47.855 -> total:832, d[0]:159, d[1]:146, d[2]:95, d[3]:115, d[4]:242, d[5]:75
16:18:48.652 -> total:800, d[0]:159, d[1]:146, d[2]:95, d[3]:83, d[4]:242, d[5]:75

#include <Wire.h>

#define Addr 0x28
void setup()
{  
  
Wire.begin(); // Initialise I2C communication as MASTER
 
  
Serial.begin(9600);    // Initialise Serial Communication, set baud rate = 9600
Wire.beginTransmission(Addr);  // Start I2C Transmission 
Wire.write(0x00);  // Select configure register A    
Wire.write(0x70); // Set normal measurement configuration, data output rate = 0.75Hz
Wire.endTransmission();  // Stop I2C Transmission   
Wire.beginTransmission(Addr);  // Start I2C Transmission  
Wire.write(0x02);  // Select Mode register  
Wire.write(0x00);  // Set continuous measurement 
Wire.endTransmission();  // Stop I2C Transmission 

delay(300);
}
void loop()
{  
unsigned int data[6];  
  
Wire.beginTransmission(Addr);  // Start I2C Transmission
Wire.write(0x03);  // Select data register 
Wire.endTransmission();// Stop I2C Transmission
Wire.requestFrom(Addr, 6);    // Request 6 bytes of data
 
if(Wire.available() == 6) // Read 6 bytes of data  
{    
data[0] = Wire.read();    
data[1] = Wire.read();    
data[2] = Wire.read();    
data[3] = Wire.read();   
data[4] = Wire.read();    
data[5] = Wire.read();  

}  
delay(300);            
// Output data to serial monitor  
Serial.print("total:");  
Serial.print(data[0]+data[1]+data[2]+data[3]+data[4]+data[5]);
Serial.print(", d[0]:");  
Serial.print(data[0]);
Serial.print(", d[1]:");  
Serial.print(data[1]);   
Serial.print(", d[2]:");  
Serial.print(data[2]);
Serial.print(", d[3]:");  
Serial.print(data[3]);
Serial.print(", d[4]:");  
Serial.print(data[4]);
Serial.print(", d[5]:");  
Serial.println(data[5]);  

delay(500);
}

Please post the code, using code tags, a link to the sensor data sheet, and a sample of the data. Explain the difficulty in data interpretation.

See the "How to get the best out of the forum" post for instructions.

Thanks for updating your post.

Here is a link to the actual data sheet, which is slightly better than useless: https://www.amphenol-sensors.com/hubfs/Documents/AAS-920-699D-NovaSensor-NPI-19-I2C-102419-web.pdf

This is not a vacuum pressure sensor. Please state the exact model number you have.

It looks like you send command 0xAC to make the measurement, then read out four bytes (two 16 bit integers that encode the pressure and the temperature).

With zero applied pressure, the first integer result should correspond to approximately 1638. The data sheet doesn't seem to say anything about the temperature result.

1 Like

Thank for your reply!!

per your comment in the void loop(), I updated the "wire.write(0x03);" to

Wire.write(0xAC);

Not sure if it changed anything. I am still getting data in the format I showed above. Sorry if it's obvious (I'm a novice). Could you suggest a way to modify my code so I get a single useful value instead of 6 values?

The exact model number I have is the one in the origianl message (NPI-19J-030A2). The sensor makes "absolute" readings and I am using it in a vacuum (sub atmospheric) application.

According to my reading the sensor data sheet I linked, I don't see how that can work. Absolute sensors are for 15 psi (atmospheric pressure) and above. Yours is 30 psi full scale.

But given the minimalist nature of the data sheet, the actual sensor operation is anyone's guess.

Here is a rough guess for how to read out the data.

#include <Wire.h>

#define Addr 0x28
void setup()
{  
Wire.begin(); // Initialise I2C communication as MASTER
Serial.begin(9600);    // Initialise Serial Communication, set baud rate = 9600
Serial.println("Starting");
}

void loop()
{  

unsigned int data, pressure, temp;
  
Wire.beginTransmission(Addr);  // Start I2C Transmission
Wire.write(0xAC);  // Command full measurement 
Wire.endTransmission(false); // repeated start
Wire.requestFrom(Addr, 4);    // Request 4 bytes of data
 
data = Wire.read();    
pressure = (data<<8) | Wire.read();    
data = Wire.read();    
temp = (data<<8) | Wire.read();   
            
// Output data to serial monitor  
Serial.print("pressure: ");
Serial.println(pressure);  
Serial.print("temp: ");
Serial.println(temp);  

delay(500);
}
2 Likes

That seems to mostly be working! Wow! Thank you so much, jremington!

Slight issue- the pressure output is continuously 40,852 +/- 10 in the serial monitor which is significantly above the "decimal count" value of 14,746 specified for max pressure in the data sheet. Any thoughts on why this could be? I see you implemented a shift register in your code. Could it maybe be off by 1?

In terms of the absolute/atmospheric/vacuum pressure sensor labels and applications, I believe it should work for pressures below atmosphere but I will find out soon when I hook it up to the system (if I can get the code working) and report back. Here is an article about Absolute Pressure sensors and their applications:
https://blog.wika.us/products/pressure-products/absolute-pressure-sensors-work-needed/#:~:text=An%20absolute%20pressure%20sensor%20is,the%20effect%20of%20atmospheric%20pressure.

As I said, it is anyone's guess how to interpret the raw data from that sensor.

The only way to know for sure is to expose the sensor to several values covering the full range of pressure inputs, and correlate those values with the raw output results.

I see you implemented a shift register in your code. Could it maybe be off by 1?

No. The shift is a byte shift, use to merge two bytes to create the 16 bit integer result. The data sheet is pretty clear on that.

I've used a lot of pressure sensors, and after looking at that data sheet, I will avoid Amphenol. Omega Engineering is where I usually shop.

Sorry, I just realized there is an error in the code, that possibly leads to randomized low order measurement values.

Change this line:

unsigned int data, pressure, temp;

to:

unsigned int data=0, pressure=0, temp=0;

Note: 40852 is not a terribly unreasonable value for an open port at 1 ATM, considering that the full range of an unsigned 16 bit integer is 0 to 65535. For full scale of 0 to 30 psi, 15 psi would be roughly in the middle, or about 32768.

1 Like

Hi, i am currently facing the same problem. Did you manage to solve that issue? How did you do it?

Hello,

Yes, I did get it to work. I used the code from the post above: jremington Aug '22 post #5

Have you tried that code? What is your sensor?

My sensor is NPI-19 series 300A2. My problem is knowing what bytes to read in order to get pressure. I get a decimal output higher than the maximum value presented in the datasheet. How do you calculate pressure?

I believe I used a secondary pressure measurement to do a linear regression. For example, at atmospheric pressure the sensor output value is A and at another random pressure the sensor output is B. You can then corelate the pressure to the bit value linearly.

Not sure if that helps or if I'm following exactly what your issue is. Can you explain in more detail?

The NPI-19-I2C Application Guide (Dec 2022) contains critical information that describes the communication between the host and sensor.

LINK to Amphenol-Sensors.com:
https://www.amphenol-sensors.com/hubfs/I2C%20NPI-19%20product%20application%20Note.pdf

To read the pressure and temperature:

NPI-19-I2C Address = 0x28

  1. Master sends I2C address (7-bits) + bit=1 to indicate read
    0x28 = 40 decimal, then shift left (2X) = 80, then add 1 for read = 81 decimal = 0x51
    Send 0x51 to initiate a read

  2. Slave (sensor) responds with Bridge Data [13:8], Master sends ACK to get next byte

  3. Slave (sensor) responds with Bridge Data [7:0], Master sends ACK to get next byte

  4. Slave (sensor) responds with Temperature Data [10:3], Master sends ACK to get next byte

  5. Slave (sensor) responds with Temperature Data [2:0], Master sends NACK to end communication
    ============================================================================

1 Like

@bull-moose Thank you, I could not find that document.

That changes things. There is no status byte, no commands to send, no initialization, no selection of a register. Just read 4 bytes, that's all.

Is the pressure and temperature signed or unsigned data ?

In Arduino code, it becomes this:

#include <Wire.h>

#define NovaAddr 0x28

void setup()
{
  Serial.begin(115200);
  Serial.println("The sketch has started");
  
  Wire.begin();
}

void loop()
{
  byte data[4];

  int n = Wire.requestFrom(NovaAddr, 4);
  if(n == 4)
  {
    data[0] = Wire.read();    
    data[1] = Wire.read();    
    data[2] = Wire.read();    
    data[3] = Wire.read();

    // I'm not sure that this is the best code for the conversion:
    unsigned int status = (data[0] >> 6) & 0x03;
    unsigned int pressure = (((unsigned int)data[0] & 0x3F) << 8) | (unsigned int) data[1];
    unsigned int temperature = ((unsigned int) data[2] >> 2) | (unsigned int) data[3] >> 6;

    Serial.print("status: ");
    Serial.print(status);
    Serial.print(", pressure: ");
    Serial.print(pressure);
    Serial.print(", temperature");
    Serial.print(temperature);
    Serial.println();
  }
  else
  {
    Serial.println("I2C communication error");
  }

  delay(1000);
} 

This topic was started a year ago, but I hope this is useful when someone searches for it.

Just wanted to confirm your code works perfectly for model NPI-19J-200A2. Thank you @Koepel and @bull-moose !

1 Like

I should clarify for future readers: you do still need to command the sensor the do a measurement before reading it, I used @jremington 's example plus @Koepel 's to get it working. Here is the meat and potatoes of the final code that I'm using to read the device:

#include <Wire.h>

#define SENSOR_ADDR 0x28
#define FULL_MEASURE_CMND 0xAC
#define SENSOR_STATUS_MASK 0xC0000000
#define SENSOR_PRESSURE_MASK 0x3FFF0000
#define SENSOR_TEMPERATURE_MASK 0xFFFF

unsigned long ps_data;

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

void loop() {
    ps_data = 0;
    Wire.beginTransmission(SENSOR_ADDR);
    Wire.write(FULL_MEASURE_CMND);
    Wire.endTransmission(false);
    unsigned char n = Wire.requestFrom(SENSOR_ADDR, 4);
    for (n; n > 0; n--) {
        ps_data = (ps_data << 8) | Wire.read();
    }

    Serial.print("Status: ");
    Serial.println((ps_data & SENSOR_STATUS_MASK) >> 30);
    Serial.print("Pressure: ");
    Serial.println((ps_data & SENSOR_PRESSURE_MASK) >> 16);
    Serial.print("Temperature: ");
    Serial.println(ps_data & SENSOR_TEMPERATURE_MASK);
    Serial.println("=============");
    delay(1000);
}

Basically you need to combine the solutions of jreminington and Koepel. The documentation provided by @bull-moose describes the return data as "two bytes" of pressure but the pictures show that the two most significant bits of that data is labeled as "STATUS" bits. This weekend I plan on hooking it up to an air compressor that will get within 80% of the sensor's max, so hopefully I will be able to determine then if the STATUS bits are labeled correctly.

2 Likes

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