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

Discussion in 'Embedded Systems and Microcontrollers' started by Ryan Jones, Feb 11, 2017.

  1. Ryan Jones

    Thread Starter Member

    Aug 27, 2016
    35
    4
    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

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

    Code (C):
    1.  
    2. #include <Wire.h>
    3.  
    4. #define DEV_ID 0x4A >> 1                        // shift required by wire.h
    5.  
    6.  
    7. void setup()
    8. {
    9.   Serial.begin(9600);
    10.   Wire.begin();
    11. }
    12.  
    13. void loop()
    14. {
    15.  
    16.   Wire.beginTransmission(DEV_ID);             // connect to Dev
    17.   Wire.write(0);
    18.   Wire.endTransmission();
    19.   Wire.write(0x2C);                            //request proper bits
    20.   Wire.write(0x06);
    21.   Wire.endTransmission();
    22.   Serial.println("write");
    23.  
    24.   delay(1000);                                // give time for measurement
    25.   Serial.println("delay");
    26.  
    27.   Wire.beginTransmission(DEV_ID);
    28.   Wire.requestFrom(DEV_ID, 2);    // request two bytes
    29.   Serial.println("receiving");
    30.  
    31.   while (Wire.available()) {
    32.     char c = Wire.read();
    33.     Serial.println(c);
    34.   }
    35.   delay (500);
    36. }
    Mod edit: moved to Embedded Systems. Added code tags
     
    Last edited by a moderator: Feb 11, 2017
  2. Mark Hughes

    Member

    Jun 14, 2016
    295
    28
    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
     
  3. Ryan Jones

    Thread Starter Member

    Aug 27, 2016
    35
    4
    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
     
  4. RK37

    Administrator

    Jun 26, 2015
    645
    41
    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).
     
  5. Ryan Jones

    Thread Starter Member

    Aug 27, 2016
    35
    4
    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.
     
  6. Mark Hughes

    Member

    Jun 14, 2016
    295
    28
    Hi @Ryan Jones,
    Let's take a step back from things and see if we're even addressing the sensor.
    Code (C):
    1. // --------------------------------------
    2. // i2c_scanner
    3. //
    4. // Version 1
    5. //    This program (or code that looks like it)
    6. //    can be found in many places.
    7. //    For example on the Arduino.cc forum.
    8. //    The original author is not know.
    9. // Version 2, Juni 2012, Using Arduino 1.0.1
    10. //     Adapted to be as simple as possible by Arduino.cc user Krodal
    11. // Version 3, Feb 26  2013
    12. //    V3 by louarnold
    13. // Version 4, March 3, 2013, Using Arduino 1.0.3
    14. //    by Arduino.cc user Krodal.
    15. //    Changes by louarnold removed.
    16. //    Scanning addresses changed from 0...127 to 1...119,
    17. //    according to the i2c scanner by Nick Gammon
    18. //    http://www.gammon.com.au/forum/?id=10896
    19. // Version 5, March 28, 2013
    20. //    As version 4, but address scans now to 127.
    21. //    A sensor seems to use address 120.
    22. // Version 6, November 27, 2015.
    23. //    Added waiting for the Leonardo serial communication.
    24. //
    25. //
    26. // This sketch tests the standard 7-bit addresses
    27. // Devices with higher bit address might not be seen properly.
    28. //
    29. #include <Wire.h>
    30. void setup()
    31. {
    32.   Wire.begin();
    33.   Serial.begin(9600);
    34.   Serial.println("\nI2C Scanner");
    35. }
    36. void loop()
    37. {
    38.   byte error, address;
    39.   int nDevices;
    40.   Serial.println("Scanning...");
    41.   nDevices = 0;
    42.   for(address = 1; address < 127; address++ )
    43.   {
    44.     // The i2c_scanner uses the return value of
    45.     // the Write.endTransmisstion to see if
    46.     // a device did acknowledge to the address.
    47.     Wire.beginTransmission(address);
    48.     error = Wire.endTransmission();
    49.     if (error == 0)
    50.     {
    51.       Serial.print("I2C device found at address 0x");
    52.       if (address<16)
    53.         Serial.print("0");
    54.       Serial.print(address,HEX);
    55.       Serial.println("  !");
    56.       nDevices++;
    57.     }
    58.     else if (error==4)
    59.     {
    60.       Serial.print("Unknow error at address 0x");
    61.       if (address<16)
    62.         Serial.print("0");
    63.       Serial.println(address,HEX);
    64.     }  
    65.   }
    66.   if (nDevices == 0)
    67.     Serial.println("No I2C devices found\n");
    68.   else
    69.     Serial.println("done\n");
    70.   delay(500);           // wait 5 seconds for next scan
    71. }
    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: Feb 12, 2017
  7. Ryan Jones

    Thread Starter Member

    Aug 27, 2016
    35
    4
    Good call, @Mark Hughes,

    I received, "No I2C Devices Found"
     
  8. Mark Hughes

    Member

    Jun 14, 2016
    295
    28
    @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.
    Code (C):
    1. #include <Wire.h>
    2. #define DEV_ID 0x4A                
    3.  
    4. void setup()
    5. {
    6.   Serial.begin(9600);
    7.   Wire.begin(DEV_ID);
    8.   Wire.write(byte(0x00));
    9.   Wire.write(byte(0x2C));
    10.   Wire.write(byte(0x06));
    11.   Wire.endTransmission();
    12.   Serial.println("write");
    13. }
    14. void loop()
    15. {
    16.   delay(1000);                                // give time for measurement
    17.   Serial.println("delay");
    18.   Wire.requestFrom(DEV_ID, 3);    // request two bytes
    19.  
    20.   while (Wire.available()) {
    21.    Serial.println("receiving");
    22.     char c = Wire.read();
    23.     Serial.println(c);
    24.   }
    25.  
    26. }
    Moderators note: changed code tags to C
     
    Last edited by a moderator: Feb 12, 2017
  9. Mark Hughes

    Member

    Jun 14, 2016
    295
    28
    @Ryan Jones
    Woohoo! You sir have just identified a wiring issue of some sort.
    Are you sure you have not swapped the SDA and SCL pins on the arduino? (Are you using the SDA/SCL pins or 4/5 on the uno?)
     
  10. Ryan Jones

    Thread Starter Member

    Aug 27, 2016
    35
    4
    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!
     
  11. djsfantasi

    AAC Fanatic!

    Apr 11, 2010
    3,543
    1,288
    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?
     
  12. Ryan Jones

    Thread Starter Member

    Aug 27, 2016
    35
    4
    @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.

    Code (C):
    1.  
    2. *************************************************************
    3. #include <Wire.h>
    4. #define DEV_ID 0x4A    
    5.  
    6. byte rbuffer[2];       // store data from sensor read registers
    7.  
    8. byte slow[] = {byte(0x20),byte(0x2F)};
    9. byte medium[] = {0x21,0x2D};
    10. byte fast[] = {0x27,0x2A};
    11.  
    12. void setup()
    13. {
    14.   Serial.begin(9600);
    15.   Serial.println("write");
    16.   Wire.beginTransmission(DEV_ID);
    17.   for (int i = 0; i < sizeof(slow) - 1; i +=1)
    18.   { Wire.write(slow); }
    19.   Wire.endTransmission();
    20.  
    21. }
    22. void loop()
    23. {
    24.   Serial.println("Delay 1s");
    25.   delay(1000);                                // give time for measurement
    26.  
    27.   Wire.requestFrom(DEV_ID,sizeof(rbuffer));
    28.   for(int i=0; i < sizeof(rbuffer)-1; i++){
    29.     rbuffer = Wire.read();
    30.     Serial.println(rbuffer,DEC);
    31.     }
    32.  
    33. }
    34.  
    Moderators note: used code tags for C
     
    Last edited by a moderator: Feb 12, 2017
  13. djsfantasi

    AAC Fanatic!

    Apr 11, 2010
    3,543
    1,288
    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?
     
  14. djsfantasi

    AAC Fanatic!

    Apr 11, 2010
    3,543
    1,288
  15. Ryan Jones

    Thread Starter Member

    Aug 27, 2016
    35
    4
    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 likes this.
  16. djsfantasi

    AAC Fanatic!

    Apr 11, 2010
    3,543
    1,288
    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);
     
  17. Mark Hughes

    Member

    Jun 14, 2016
    295
    28
    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
     
  18. Ryan Jones

    Thread Starter Member

    Aug 27, 2016
    35
    4
    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
     
  19. Ryan Jones

    Thread Starter Member

    Aug 27, 2016
    35
    4
    Here is a photo of the numbers changing, I commented out all of the Serial.println except for the Wire.read() Screen Shot 2017-02-13 at 10.03.34 PM.png
     
  20. djsfantasi

    AAC Fanatic!

    Apr 11, 2010
    3,543
    1,288
    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°
     
    Ryan Jones likes this.
Loading...