MIT-i Programming Help with Arduino I2C & Sensirion Temp Sensor

Thread Starter

Ryan Jones

Joined Aug 27, 2016
35
Ryan here from the MIT-i video series! I am having some trouble with programming (I think) and was hoping I could find some help in here like I have in the past. For this months video we are using the Sensirion STS3X Temperature Sensor (datasheet). We have surface mounted the IC to a breakout board, ran a successful continuity test, and wired the circuit according to the sensors datasheet, with ADDR tied to ground. We will be using Single Shot mode.

My current issue is that I am unable to receive information from the sensor and, not being a programmer, believe I am doing something wrong. I have attempted to follow the directions on the datasheet but never receive bytes in return from the sensor. Following the serial monitor, the loop makes it down to the "Serial.println("receiving");" line but never properly prints the returning bytes in the Wire.read(); command.

The code can be found below. Thanks in advance for the help!
Ryan

***************************************************************

C:
#include <Wire.h>

#define DEV_ID 0x4A >> 1                        // shift required by wire.h


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

void loop()
{

  Wire.beginTransmission(DEV_ID);             // connect to Dev
  Wire.write(0);
  Wire.endTransmission();
  Wire.write(0x2C);                            //request proper bits
  Wire.write(0x06);
  Wire.endTransmission();
  Serial.println("write");

  delay(1000);                                // give time for measurement
  Serial.println("delay");

  Wire.beginTransmission(DEV_ID);
  Wire.requestFrom(DEV_ID, 2);    // request two bytes
  Serial.println("receiving");

  while (Wire.available()) {
    char c = Wire.read();
    Serial.println(c);
  }
  delay (500);
}
Mod edit: moved to Embedded Systems. Added code tags
 
Last edited by a moderator:

Mark Hughes

Joined Jun 14, 2016
409
Hi @Ryan Jones,
A couple quick things
1) Can you include a photograph of your sensor hookup and wiring?
2) Try removing the bit-shift operator in line #4. Arduino's wire.h library can read to Dec 127 (0x7F) without needing a bitshift.
0x4A is 0b01001010
0X4A >> 1 is 0b00100101 (which is 0x25 or Dec 37)
Thanks,
Mark
 

Thread Starter

Ryan Jones

Joined Aug 27, 2016
35
Hi @Mark Hughes !

I should have known I could rely on your help, thanks for the response! The breadboard is hard to see so I drew a quick picture of my setup. I have removed the bit-shift operator.IMG_0833.JPG
 

RK37

Joined Jun 26, 2015
677
That I2C code looks more like what you would need if you were not using the sensor's clock-stretching mode. Try writing 0x24 for the first byte, then 0x00 for the second byte; this tells the sensor to use non-clock-stretching mode. Also, read three bytes instead of two (then ignore the third byte).
 

Thread Starter

Ryan Jones

Joined Aug 27, 2016
35
Thank you, @RK37!

I have given it a shot but it unfortunately seems to be doing the same thing. I am still trying to find some other examples now.
 

Mark Hughes

Joined Jun 14, 2016
409
Hi @Ryan Jones,
Let's take a step back from things and see if we're even addressing the sensor.
C:
// --------------------------------------
// i2c_scanner
//
// Version 1
//    This program (or code that looks like it)
//    can be found in many places.
//    For example on the Arduino.cc forum.
//    The original author is not know.
// Version 2, Juni 2012, Using Arduino 1.0.1
//     Adapted to be as simple as possible by Arduino.cc user Krodal
// Version 3, Feb 26  2013
//    V3 by louarnold
// Version 4, March 3, 2013, Using Arduino 1.0.3
//    by Arduino.cc user Krodal.
//    Changes by louarnold removed.
//    Scanning addresses changed from 0...127 to 1...119,
//    according to the i2c scanner by Nick Gammon
//    http://www.gammon.com.au/forum/?id=10896
// Version 5, March 28, 2013
//    As version 4, but address scans now to 127.
//    A sensor seems to use address 120.
// Version 6, November 27, 2015.
//    Added waiting for the Leonardo serial communication.
//
//
// This sketch tests the standard 7-bit addresses
// Devices with higher bit address might not be seen properly.
//
#include <Wire.h>
void setup()
{
  Wire.begin();
  Serial.begin(9600);
  Serial.println("\nI2C Scanner");
}
void loop()
{
  byte error, address;
  int nDevices;
  Serial.println("Scanning...");
  nDevices = 0;
  for(address = 1; address < 127; address++ )
  {
    // The i2c_scanner uses the return value of
    // the Write.endTransmisstion to see if
    // a device did acknowledge to the address.
    Wire.beginTransmission(address);
    error = Wire.endTransmission();
    if (error == 0)
    {
      Serial.print("I2C device found at address 0x");
      if (address<16)
        Serial.print("0");
      Serial.print(address,HEX);
      Serial.println("  !");
      nDevices++;
    }
    else if (error==4)
    {
      Serial.print("Unknow error at address 0x");
      if (address<16)
        Serial.print("0");
      Serial.println(address,HEX);
    }  
  }
  if (nDevices == 0)
    Serial.println("No I2C devices found\n");
  else
    Serial.println("done\n");
  delay(500);           // wait 5 seconds for next scan
}
If it works, you'll get positive feedback on the Serial Monitor and we can eliminate a wiring issue and focus on the code. (Note the I2C address it gives you).

Moderators note: changed code tags to C
 
Last edited by a moderator:

Mark Hughes

Joined Jun 14, 2016
409
@Ryan Jones,
I also believe you should wrap your hex values in the byte() wrapper and move your initialization code up into setup instead of continually resending your initialization code to the sensor. I'm not saying this will work -- just reusing bits of your code as an example of how to recode it.
C:
#include <Wire.h>
#define DEV_ID 0x4A                 

void setup()
{
  Serial.begin(9600);
  Wire.begin(DEV_ID);
  Wire.write(byte(0x00));
  Wire.write(byte(0x2C));
  Wire.write(byte(0x06));
  Wire.endTransmission();
  Serial.println("write");
}
void loop()
{
  delay(1000);                                // give time for measurement
  Serial.println("delay");
  Wire.requestFrom(DEV_ID, 3);    // request two bytes

  while (Wire.available()) {
   Serial.println("receiving");
    char c = Wire.read();
    Serial.println(c);
  }

}
Moderators note: changed code tags to C
 
Last edited by a moderator:

Thread Starter

Ryan Jones

Joined Aug 27, 2016
35
Update: We have re-soldered the sensor and now finally get a reading using the I2C Device Search sketch. The next step still is getting values to return from the sensor reading. But we have made progress!
 

djsfantasi

Joined Apr 11, 2010
9,156
Your comment on the Wire.requestFrom line states that you are requesting two bytes. However, the function's parameter is requesting three bytes. If the sensor only responds with two bytes, perhaps it is waiting for the third byte?
 

Thread Starter

Ryan Jones

Joined Aug 27, 2016
35
@Mark Hughes was kind enough to give me a hand via Skype for quite some time. Using a previous sketch of his, Mark was able to come up with the following program and it is the closest we have gotten yet. Now, we receive a continuous reading of "255" from the Wire.read() function. I will continue playing with it, and as always, the datasheet can be found here. Now, if only we could get it to read the proper value.

C:
*************************************************************
#include <Wire.h>
#define DEV_ID 0x4A     

byte rbuffer[2];       // store data from sensor read registers

byte slow[] = {byte(0x20),byte(0x2F)};
byte medium[] = {0x21,0x2D};
byte fast[] = {0x27,0x2A};

void setup()
{
  Serial.begin(9600);
  Serial.println("write");
  Wire.beginTransmission(DEV_ID);
  for (int i = 0; i < sizeof(slow) - 1; i +=1)
  { Wire.write(slow); }
  Wire.endTransmission();

}
void loop()
{
  Serial.println("Delay 1s");
  delay(1000);                                // give time for measurement

  Wire.requestFrom(DEV_ID,sizeof(rbuffer));
  for(int i=0; i < sizeof(rbuffer)-1; i++){
    rbuffer = Wire.read();
    Serial.println(rbuffer,DEC);
    }
 
}
Moderators note: used code tags for C
 
Last edited by a moderator:

djsfantasi

Joined Apr 11, 2010
9,156
255 from a Wire.read() call is an error value (search for this on the Arduino site). It usually means there is no response back from the device. This happens when you use the wrong device address or the device is not receiving power.

I did note that in your first posted sketch, you defined DEV_ID as 0x4A, shifted right. Then in you last sketch, you use 0x4A without shifting. As Mark pointed out, the shifted value is 0x25.

Which value is the actual address of your sensor?
 

Thread Starter

Ryan Jones

Joined Aug 27, 2016
35
Thank you for your responses, @djsfantasi !

The proper address for the device is 0x4A. I know that the device is receiving power because I am able to successfully read the device address from an I2C Address Search sketch. It seems as though we aren't calling the function properly based off of the datasheet.
 

djsfantasi

Joined Apr 11, 2010
9,156
I am curious about your Wire.write(slow) statement. That will write the address (or part thereof) of the array slow. I would index it with the variable I like this:
Wire.write(slow);
 

Mark Hughes

Joined Jun 14, 2016
409
I am curious about your Wire.write(slow) statement. That will write the address (or part thereof) of the array slow. I would index it with the variable I like this:
Wire.write(slow);
Hey ya' @Ryan Jones ,@djsfantasi ,
Feel free to remove that. After I helped Ryan work through the connectivity issues I began to rewrite the original code, but had to abandon it mid-job because it was time for lunch with my wife. Feel free to rework it if you see any errors, it'll be quite some time before I can get back to it.
Mark
 

Thread Starter

Ryan Jones

Joined Aug 27, 2016
35
Hey, everyone!

Just wanted to give you an update. I was finally able to get a real reading from the sensor! I'm not sure what I did, it's the same thing I've been trying for the last couple of days. But anyway, now, at room temperature, the Wire.read function returns a number around 99-100. This number increases or decreases as I add and remove heat, so I know it is working.

Now to convert this arbitrary number into a real temperature. What I am stumped on is that the formula in the datasheet says to utilize the first two bits for the equation, but if my number starts fluctuates around 100 then my first two bits will most always be "1" and "0." A strange bug I notice is that, although the program works, if I change the number of bytes requested from the address, I still return the same reading with the same amount of numbers.

********************************************

/* source of code:
http://www.electroschematics.com/9798/reading-temperatures-i2c-arduino/ */
#include <Wire.h>
int address1 = 0x4A; //decimal address of sensor 1

void setup() {
Serial.begin(9600);
Wire.begin(); // create a wire object
}

void loop() {

//start the communication with IC with the address xx
Wire.beginTransmission(address1);
Serial.println("begin");
//send a bit and ask for register zero
Wire.write(byte(0x24));
Wire.write(byte(0x00));
Serial.println("write");
//end transmission
Wire.endTransmission();
Serial.println("end");


delay(1000);
Serial.println("wait");
//request 1 byte from address xx
Wire.requestFrom(address1, 3);
Serial.println("request");
//wait for response
while (Wire.available() == 0); {
Serial.println("read");
//put the temperature in variable c
int c = Wire.read();
Serial.println(c);
}
}

*************************And a look at my serial monitor....*******************
Screen Shot 2017-02-13 at 9.51.33 PM.png
 

djsfantasi

Joined Apr 11, 2010
9,156
Hello!

With with regard to converting the sensor values to the actual temperature in either F° or C°, I don't see where it used individual bits. What I did find on the datssheet was the following formula:
IMG_3019.JPG
Applying this equation to a decimal value of 101, returns a temperature of 49.5°
 
Top