Need help with a I2C-Sensor

Hello together.

I bought a special I2C pressure sensor and tried to run it on an arduino - but without any success.

With the I2C scanner sketch I found the device with address 0x6D.

The datasheet information:
Address: 0x6D (Write: 0xDA, read: 0xDB)
Data register: a 24bit signed integer, stored in 3 registers of address 0x06, 0x07, 0x08.

The example sketch on the datasheet is following:

iic_start(); //I2C start
iic_write(0xDA); //Device address, write operation
iic_write(0x06); //Write data start address
iic_start(); //Restart
iic_write(0xDA+1); //Device address (0xDB), read operation
dat=iic_readbyte(1); //Read first byte(0x06),ACK
dat <<= 8; //Shift
dat += iic_readbyte(1); //Read second byte(0x07),ACK
dat <<= 8; //Shift
dat += iic_readbyte(0); //Read third byte(0x08),NACK
iic_stop(); //Stop

I tried to translate it into arduino as following:

#include <Wire.h>
#define SENSOR_ADDRESS 0x6D
#define SENSOR_WRITE 0x00
#define SENSOR_READ 0x01
#define SENSOR_REG 0x06

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


void loop()
{
  uint32_t low, med, high;
  uint32_t wert;
  Wire.beginTransmission(SENSOR_ADDRESS);
  Wire.write(SENSOR_WRITE);
  Wire.endTransmission();
  delay(20);
  Wire.beginTransmission(SENSOR_ADDRESS);
  Wire.write(SENSOR_REG);
  Wire.endTransmission();
  delay(20);  
  Wire.requestFrom(SENSOR_ADDRESS, 3);
  low = Wire.read();
  med = Wire.read();
  high = Wire.read();
  wert = (high<<16) | (med<<8) | low;
  Serial.print("HEX: ");
  Serial.println(wert);

I tried many different options but still get the same value (4294967295) with connected sensor with different pressures and also when the sensor is disconnected. May anybody help me?

link to datasheet ?

This is the datasheet.

I2C Communication Protocol Specifications.pdf (395 KB)

Here is a photo of my arduino NodeMCU. SCL is connected to D3 and SDA to D2.

I think you may be confused about the function of the SENSOR_READ and _WRITE bits. These are the low bit of the device address and are handled automatically by the Wire library.

Try something like this:

#include <Wire.h>
#define SENSOR_ADDRESS 0x6D
#define SENSOR_REG 0x06

void setup()
{
  Serial.begin(9600);
  delay(5000);                 //?      
  Wire.begin();
  delay(100);
}


void loop()
{
  uint32_t low, med, high;
  uint32_t wert;
  Wire.beginTransmission(SENSOR_ADDRESS);
  Wire.write(SENSOR_REG);
  Wire.endTransmission();
  Wire.requestFrom(SENSOR_ADDRESS, 3);
  low = Wire.read();
  med = Wire.read();
  high = Wire.read();
  wert = (high<<16) | (med<<8) | low;
  Serial.print("Value read: ");
  Serial.println(wert);
}

Thank you for your help. I tried your code, but the problem is still the same. The value read is always "4294967295".

Do you have the required pullup resistors on SDA and SCL? What Arduino are you using?

jremington:
Wire.endTransmission();

endTransmission() has a return code that will tell you if the transmission was successful or not. It might be good to see if you are successfully talking to your sensor.

According to the data sheet, register 6 is the high byte of the pressure value. Your code treats it as the low byte.

But that won't make a difference if the result is 0xFFFFFFF, as you report.

I tend to avoid the Wire library, and use the basic I2C routines, which are similar to those used in the data sheet. I've attached a copy, if you want to try that approach.

I2C_lib.c (3.93 KB)

Thank you. I tried your I2C_lib.c, but there is an error message while compiling.

This is the sketch:

#include "I2C_lib.c"

float fadc;
float ADC;
int dat;
void setup()
{
  Serial.begin(9600);                       
  delay(100);
  I2C_Init();
  delay(100);
}

void loop()
{
I2C_Start();
I2C_Write(0xDA);
I2C_Write(0x06);
I2C_Start();
I2C_Write(0xDB);
dat=I2C_ReadACK(1); //Read first byte(0x06),ACK
dat <<= 8; //Shift
dat += I2C_ReadACK(1); //Read second byte(0x07),ACK
dat <<= 8; //Shift
dat += I2C_ReadNACK(0); //Read third byte(0x08),NACK
I2C_Stop(); //Stop
if(dat & 0x800000)
{
fadc= dat - 16777216.0;
}
else
{
fadc = dat;
}
ADC = 3.3* fadc /8388608.0;
P = 500 * (ADC-0.5)/2.0;
}

And this is the error message:

Arduino: 1.8.8 (Windows Store 1.8.19.0) (Windows 10), Board: "Arduino Leonardo"

sketch\I2C_lib.c: In function 'I2C_Init':

sketch\I2C_lib.c:23:5: error: 'TWSR' undeclared (first use in this function)

     TWSR = 0; // prescalar to zero

     ^

sketch\I2C_lib.c:23:5: note: each undeclared identifier is reported only once for each function it appears in

sketch\I2C_lib.c:24:5: error: 'TWBR' undeclared (first use in this function)

     TWBR = ((F_CPU/F_SCL)-16)/2; // set SCL frequency in TWI bit register

     ^

sketch\I2C_lib.c: In function 'I2C_Stop':

sketch\I2C_lib.c:29:2: error: 'TWCR' undeclared (first use in this function)

  TWCR=TW_STOP;

  ^

sketch\I2C_lib.c:32:20: error: 'TWSTO' undeclared (first use in this function)

   while(TWCR & _BV(TWSTO));

                    ^

sketch\I2C_lib.c: In function 'I2C_Detect':

sketch\I2C_lib.c:38:5: error: 'TWCR' undeclared (first use in this function)

     TWCR = TW_START; // send start condition

     ^

sketch\I2C_lib.c:40:2: error: 'TWDR' undeclared (first use in this function)

  TWDR = addr; // load device's bus address

  ^

sketch\I2C_lib.c:15:20: error: 'TWSR' undeclared (first use in this function)

 #define TW_STATUS (TWSR & 0xF8) // returns value of status register

                    ^

sketch\I2C_lib.c:43:13: note: in expansion of macro 'TW_STATUS'

     return (TW_STATUS==0x18); // return 1 if found; 0 otherwise

             ^

sketch\I2C_lib.c: In function 'I2C_Write':

sketch\I2C_lib.c:66:5: error: 'TWDR' undeclared (first use in this function)

     TWDR = data; // load data to be sent

     ^

sketch\I2C_lib.c:67:5: error: 'TWCR' undeclared (first use in this function)

     TWCR = TW_SEND; // and send it

     ^

sketch\I2C_lib.c:15:20: error: 'TWSR' undeclared (first use in this function)

 #define TW_STATUS (TWSR & 0xF8) // returns value of status register

                    ^

sketch\I2C_lib.c:69:13: note: in expansion of macro 'TW_STATUS'

     return (TW_STATUS!=0x28); //0 if successful, 1 if not

             ^

sketch\I2C_lib.c: In function 'I2C_ReadACK':

sketch\I2C_lib.c:76:5: error: 'TWCR' undeclared (first use in this function)

     TWCR = TW_ACK; // ack = will read more data

     ^

sketch\I2C_lib.c:78:12: error: 'TWDR' undeclared (first use in this function)

     return TWDR;

            ^

sketch\I2C_lib.c: In function 'I2C_ReadNACK':

sketch\I2C_lib.c:86:5: error: 'TWCR' undeclared (first use in this function)

     TWCR = TW_NACK; // nack = not reading more data

     ^

sketch\I2C_lib.c:88:12: error: 'TWDR' undeclared (first use in this function)

     return TWDR;

            ^

exit status 1
Fehler beim Kompilieren für das Board Arduino Leonardo.

I'm a beginner and I don't know, what I done wrong.

That I2C library is intended for the Arduino Uno or similar with an ATmega328 processor. Evidently it will not work on the Leonardo, with the 32U4 processor.

From the schematic diagram I examined, it does not appear that the Leonardo has the required pullup resistors on the I2C lines (SDA and SCL). So, if they are not present on the sensor, I2C won't work. You may need to add them -- try 4.7K to 5V on each line.

What Arduino did you use to run the I2C address scanner?

As a beginner, you have started a difficult project.

I used the NodeMCU v3.2 to run the scanner. This should be the final device for the sensor.

I thought, it would not be difficult. I did read and test some examples with libraries and with the code on the datasheet it looked not very difficult.

I used the NodeMCU v3.2 to run the scanner.

Try running the scanner on the Leonardo.

If it doesn't work there, the lack of pullup resistors could be the problem.

Most beginners think their first projects will be easy, and there is a name for the phenomenon: the Dunning-Kruger effect.

Diddi68:
Hello together.

I bought a special I2C pressure sensor and tried to run it on an arduino - but without any success.

With the I2C scanner sketch I found the device with address 0x6D.

The datasheet information:
Address: 0x6D (Write: 0xDA, read: 0xDB)
Data register: a 24bit signed integer, stored in 3 registers of address 0x06, 0x07, 0x08.

....

the I2C scanner returns an address so I guess it's safe to assume that your wiring is OK.

from what I can see, you have 0x6D as your device address and 0x06,0x07 and 0x08 are the internal register sub-addresses you want to access to read the pressure.

so using the standard Wire.h library, maybe try using this wire function which include the internal registers (untested):

#include <Wire.h>
#define SENSOR_ADDRESS 0x6D
#define PRESSURE_BYTES 3
const uint32_t PRESSURE_REG=0x00060708; //pressure registers 0x06 (MSB), 0x07, 0x08(LSB)


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


void loop()
{
  union {
    uint8_t bytes[4];
    uint32_t pressure;
  } in;

  //this is the function I was referring to...
  Wire.requestFrom(SENSOR_ADDRESS, PRESSURE_BYTES, PRESSURE_REG, PRESSURE_BYTES, true);

  if (Wire.available()) {
    for (uint8_t i = PRESSURE_BYTES; i > 0; --i) {
      in.bytes[i-1] = Wire.read();
    }
  }

  Serial.print("HEX: 0x");
  Serial.println(in.pressure,HEX);
  delay(1000); //polls approx every second
}

sorry, not sure if I got the byte order right but I hope that helps! :wink:

Small modification to jremington's code you might try:

void loop()
{
  uint32_t low, med, high;
  uint32_t wert;
  Wire.beginTransmission(SENSOR_ADDRESS);
  Wire.write(SENSOR_REG);
  Wire.endTransmission(false);
  Wire.requestFrom(SENSOR_ADDRESS, 3);
  if(Wire.available() == 3 )
  {

    low = Wire.read();
    med = Wire.read();
    high = Wire.read();

    wert = (high<<16) | (med<<8) | low;
    Serial.print("Value read: ");
    Serial.println(wert);
  }
  Wire.endTransmission();
}

Thank you all for your help - you are so great !!!! It looks like the only problem was the missing "false" in "Wire.endTransmission()".

The code from Blackfin works well.

Diddi68:
The code from Blackfin works well.

No, it doesn't. From the datasheet you can see, that the pressure is stored as a 24-bit signed integer. Blackfin's code will not account for that, thus returning false data. For example, a measurement value of -500, using the provided code, will be stored as 16776716.

The datasheet provides you with the correct conversion from a 24-bit signed integer to a 32-bit signed integer (or float).

if(dat & 0x800000)
{
    fadc= dat - 16777216;
}
else
{
    fadc = dat;
}

They check, if the most significant bit in the measurement is set (indicating a negative value) and subtract 2^24 = 16777216 from the result if true.

In addition to the above correction, the code that I and Blackfin posted, the byte order is handled incorrectly.

According to the data sheet, the byte in register 6 is the most significant byte of the pressure.

Also, you shouldn't need the Wire.available() call. Wire.requestFrom() is a complete transaction that either works, or it doesn't, and the program does nothing useful in the latter case.

I'm not shure, if I understand you. I saw, "low", "med" and "high" were in a wrong order. I also didn't insert the calculation in my posted sketch, because I wanted to keep the sketch as easy as possible.

Here is my code, that works and shows the preassure in "bar":

#include <Wire.h>
#define SENSOR_ADDRESS 0x6D
#define SENSOR_REG 0x06

float fadc;
float druck;

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

void loop()
{
  uint32_t low, med, high;
  uint32_t wert;
  Wire.beginTransmission(SENSOR_ADDRESS);
  Wire.write(SENSOR_REG);
  Wire.endTransmission(false);
  Wire.requestFrom(SENSOR_ADDRESS, 3);
  if(Wire.available() == 3 )
  {
    high = Wire.read();
    med = Wire.read();
    low = Wire.read();

    wert = (high<<16) | (med<<8) | low;
    Serial.print("Value read: ");
    Serial.println(wert);
  }
  Wire.endTransmission();

  if(wert & 0x800000)
  {
  fadc = wert - 16777216.0;
  }
  else
  {
  fadc = wert;
  }
  druck = 500 * ((3.3 * wert / 8388608.0)-0.5) / 200.0;
  Serial.print("Druck [bar]: ");
  Serial.println(druck);
  delay(5000);
}