TC74 (I2C Temp. Sensor) giving very wrong readings?

Hey guys. I am just learning to use I2C and the Wire library and am starting with the Microchip TC74 temperature sensor. It has 2 registers. One is a config register which allows you to put the sensor into a low-power standby mode. The other is the temperature reading output as 8 bits in degrees Celsius.

Board: Arduino Uno Rev. 3
Sensor Part #: TC74A0-5.0VCT and TC74A2-5.0VCT
Packaging: TO-220 (through-hole)
Sensor datasheet link: Microchip TC74 Datasheet

Note that right now I am in a cold area with with temps ranging from 0 to 32 deg F (-17 to 0 deg C) and I’m measuring the temps in my room with the heat off.

I have everything connected on a breadboard (so I’ve considered parasitic capacitance as a possible issue). Connecting SDA to pin A4 and SCL to pin 5, I’m able to get readings on the Serial Monitor. I get readings around 22-24. That translates to ~75 deg F which unless I’ve got mad cow disease is a reading much higher than expected.

Remember I’m brand new to I2C and Wire so if it ends up being something dumb then please excuse my dumbness :drooling_face:. Also forgive me as it’s my 1st post to these forums :grin:

Here is a list of all the things I’ve tried and have not fixed the issue:

  • I have a 4.7k pull-up resistor on both the SDA and SCL lines
  • I have a 0.1uF film capacitor for decoupling at the sensor’s VDD pin
  • I have tried using both 5.0V and 3.3V as VDD. For some reason, the reading goes up by ~4 degrees when using 3.3V which is even worse
  • I initially used TC74A0-5.0VAT and assumed I may have damaged it or it just isn’t working. I bought TC74A2-5.0VAT, which has a different address, but nothing changed.
  • The TC74 datasheet shows a limit clock speed of 100 kHz, therefore I added Wire.SetClock(10000);
  • I increased the delay between readings to as much as 5 seconds
  • Pg. 9 of the datasheet shows all the addresses for the the respective temperature part #'s. I have tried all of these addresses, including the default address it gives.
  • Yes, I even made sure the sensor was oriented properly and not backwards :confused:
#include <Wire.h>

int reading = 0;
int address = 77; //refer to pg. 9 in the datasheet
                  //TC74A0-5.0VCT --> 1001 000 --> 72
                  //TC74A1-5.0VCT --> 1001 001 --> 73
                  //TC74A2-5.0VCT --> 1001 010 --> 74
                  //TC74A3-5.0VCT --> 1001 011 --> 75
                  //TC74A4-5.0VCT --> 1001 100 --> 76
                  //TC74A5-5.0VCT --> 1001 101 --> 77
                  //TC74A6-5.0VCT --> 1001 110 --> 78
                  //TC74A7-5.0VCT --> 1001 111 --> 79

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

  Wire.setClock(10000);

  Wire.beginTransmission(address); 
  Wire.write(byte(0x01));
  Wire.write(byte(0x00));     //This points to the config register and writes to it to ensure it is in normal mode and not standby mode
  Wire.endTransmission();

  delay(150); //delay between transmissions
  
  Wire.beginTransmission(address); 
  Wire.write(byte(0x00));   //Point to the temperature register to prepare for a reading
  Wire.endTransmission();
  
}

void loop() {

  Wire.requestFrom(address,1);    
  if (Wire.available() == true) {
    int AvailableBytes = Wire.available();
    Serial.print("Bus available! Available bytes: ");
    Serial.println(AvailableBytes); 
    reading = Wire.read();          //Temp reading in degrees Celsius as a decimal
    Serial.print("Temp reading: ");   
    Serial.print(reading);
    Serial.print(", ");
    Serial.println(reading,BIN);  //Temp reading in degrees Celsius in binary
    
  }
  else {
    int AvailableBytes = Wire.available();
    Serial.print("Bus NOT available! ");
    Serial.print("Temp reading: ");   // print the reading (though probably pointless as Wire.available() == false)
    Serial.print(reading);
    Serial.print(", ");
    Serial.println(reading,BIN);
  }

  delay(1000);    //delay in between readings
}

One of the forum members wrote a "How to" for I2C on the Arduino.

Well worth a read, because you are making some common mistakes. Hint: consult the common mistakes section. Additional hint: use the I2C address scanner program to verify I2C communications and the proper device address.

Please post a link to product page for the exact sensor chip/module you have.

Thanks for the link, didn't know about it.

Will read it and update once I've corrected my mistakes and tried other fixes

My reading of the data sheet suggests that you should be using address 74 (decimal) and 5.0V for the TC74A2-5.0VAT part. The I2C address scanner will report any address discovered.

Further, you should be able to get and report the temperature directly in Celsius. What follows is one complete cycle of data acquisition:

 Wire.beginTransmission(address);
  Wire.write(0);  // get data starting with register 0
  Wire.endTransmission(false);
  Wire.requestFrom(address, 1, true); // EDIT(2): "true to STOP bus", request a total of 1 register
  signed char t = Wire.read();
  Serial.print("T = ");
  Serial.println(t);

Yep I tried all the addresses and correct, 72 is for the TC74A0-5.0VAT and 74 is for the TC74A2-5.0VAT. Still no dice

So looked over that article. I reduced the SDA/SCL wire jumper lengths down to 1". Still getting high temp readings.

They also say to have a max of 3mA sink current. I already have 5/4700 + 5/4700 = 2.1mA sink current.

I checked the 'Common Mistakes' section too but I don't seem to be doing any of those mistakes in my code.

Also tried your code as well but it returns the same high readings.

I'm stumped :confused:

Please post the result of using the I2C address scanner.

You don't need to call Wire.available() after Wire.requestFrom().

Also tried your code as well but it returns the same high readings.

Please post the revised code, and note that I edited the third argument of .requestFrom() to false (stop the bus after reading the byte).

I used the Wire.available() to see how many bytes are able to be read, but I don’t need it

Here’s the i2c scanner result:

I2C Scanner
Scanning...
I2C device found at address 0x4A  !
done

The TC74A2-5.0VAT is connected, and 4A corresponds to 74 which is it’s proper address

Here’s your code:

#include <Wire.h>

int reading = 0;
int address = 74; //refer to pg. 9 in the datasheet
                  //TC74A0-5.0VCT --> 1001 000 --> 72
                  //TC74A0-5.0VCT --> 1001 001 --> 73
                  //TC74A0-5.0VCT --> 1001 010 --> 74
                  //TC74A0-5.0VCT --> 1001 011 --> 75
                  //TC74A0-5.0VCT --> 1001 100 --> 76
                  //TC74A0-5.0VCT --> 1001 101 --> 77
                  //TC74A0-5.0VCT --> 1001 110 --> 78
                  //TC74A0-5.0VCT --> 1001 111 --> 79

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

  Wire.setClock(10000);

  Wire.beginTransmission(address); 
  Wire.write(byte(0x01));
  Wire.write(byte(0x00));     //This points to the config register and writes to it to ensure it is in normal mode and not standby mode
  Wire.endTransmission();

  delay(150); //delay between transmissions
  
  Wire.beginTransmission(address); 
  Wire.write(byte(0x00));   //Point to the temperature register to prepare for a reading
  Wire.endTransmission();
  
}

void loop() {
  Wire.beginTransmission(address);
  Wire.write(0);  // get data starting with register 0
  Wire.endTransmission(false);
  Wire.requestFrom(address, 1, false); 
  signed char t = Wire.read();
  Serial.print("T = ");
  Serial.println(t);

  delay(1000);    //delay in between readings
}

And it’s result:

T = 27
T = 28
T = 27
T = 27
T = 27
T = 28
T = 27
T = 28

Which are the same values I got before.

Very strange! If you heat or cool the sensor do the values go up and down?

This code is not needed in setup(), but I don't think it matters.

  delay(150); //delay between transmissions
 
  Wire.beginTransmission(address);
  Wire.write(byte(0x00));   //Point to the temperature register to prepare for a reading
  Wire.endTransmission();

Yep, when I breathe slowly onto the sensor the value goes up about 1 or 2 deg C then goes back down

You have a 5V Arduino board and a 5V sensor. You didn't have to read my page on Github. That is to scare new users who think that I2C an be used for anything without thinking.

The sensor has 8-bit signed data. You need to get that into a 8-bit signed integer.
jremington used a 'signed char', or you can use a 'int8_t'.
It might be good to convert that into a integer, otherwise the Serial.print() might think it is a ASCII character.

@jremington, the datasheet shows a repeated start, but the 'false' as third parameter for Wire.requestFrom() omits the last STOP. We need that last STOP of course.

I2C Scanner sketch.
It is in the Arduino IDE menu: File / Examples / Wire / i2c_scanner
Or use Nick Gammon's I2C Scanner sketch.
It show the I2C address in hexadecimal format. Can you use that hexadecimal number in the sketch ? We prefer that.
I think it is between 0x48 and 0x4F.

According to the datasheet, Figure 3-1 on page 7, there are three ways to communicate with the sensor.
You could make three functions.

// -----------------------------------------------------
// datasheet calls this "Write Byte Format"
// -----------------------------------------------------
Wire.beginTransmission( address);
Wire.write( command);  // register address, 0 or 1
Wire.write( data);
int error = Wire.endTransmission();
if( error != 0)
{
 Serial.println( "Where is the sensor");
}

// -----------------------------------------------------
// datasheet calls this "Read Byte Format"
// -----------------------------------------------------
Wire.beginTransmission(address);
Wire.write(0);  // register address, 0 or 1
Wire.endTransmission(false);  // false for a "repeated start"
int n = Wire.requestFrom(address, 1); // request 1 byte
if( n == 1)        // 1 bytes requested, was 1 byte received ?
{
 // The lowest 8 bits contains the signed temperature in Celsius
 int8_t = Wire.read() & 0xFF;   // or signed char = Wire.read();
 int myCelsius = (int) int8_t;   // convert it to integer (easier to print)
}
else
{
 Serial.println( "Something wrong");
}


// -----------------------------------------------------
// datasheet calls this "Receive Byte Format"
// -----------------------------------------------------
int n = Wire.requestFrom(address, 1); // request 1 byte
if( n == 1)        // 1 bytes requested, was 1 byte received ?
{
 // The lowest 8 bits contains the signed temperature in Celsius
 int8_t = Wire.read() & 0xFF;   // or signed char = Wire.read();
 int myCelsius = (int) int8_t;   // convert it to integer (easier to print)
}
else
{
 Serial.println( "Something wrong");
}

[Update] Don't use 10000 for the clock speed, there is a bug in Wire.setClock(); The default is 100000UL, often 400000UL is possible, you can try 50000UL. The 'UL' is from Unsigned Long to tell the compiler it is a large number.

[Update 2] So I'm reading the datasheet, it needs at least 250ms to get ready. Can you make that delay of 150ms after taking it out of standby in setup() larger, for example 500ms.

[Update 3] I'm very sorry, the forum did not post my well-written message, so I posted my draft (the forum stores 'drafts' when writing a post), It had the wrong code, I will check my post once more... done.

Hi, Koepel:

Your wiki is very helpful, but I think it would even better if you would update the page on "Explanation of the functions" to include the function parameters, and an explanation about what they do.

In this thread, I was temporarily confused about the third parameter in .requestFrom() and as you know, it is very difficult to find ANY clear explanation of the parameter meanings.

Here’s what the i2c_scanner gives me:

I2C Scanner
Scanning...
I2C device found at address 0x4A  !
done

I changed the address to be that hex code, increased the setup delay time to 500ms. Please check to make sure I did it right, particularly with the myCelsius variable.

#include <Wire.h>
int8_t reading;
int address = byte(0x4a); //refer to pg. 9 in the datasheet
                  //TC74A0-5.0VCT --> 1001 000 --> 72
                  //TC74A0-5.0VCT --> 1001 001 --> 73
                  //TC74A0-5.0VCT --> 1001 010 --> 74
                  //TC74A0-5.0VCT --> 1001 011 --> 75
                  //TC74A0-5.0VCT --> 1001 100 --> 76
                  //TC74A0-5.0VCT --> 1001 101 --> 77
                  //TC74A0-5.0VCT --> 1001 110 --> 78
                  //TC74A0-5.0VCT --> 1001 111 --> 79

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

  Wire.setClock(50000UL);

   // -----------------------------------------------------
  // datasheet calls this "Write Byte Format"
  // -----------------------------------------------------
  Wire.beginTransmission(address);
  Wire.write(byte(0x01));  // register address, 0 or 1
  Wire.write(byte(0x00)); //This points to the config register and writes to it to ensure it is in normal mode and not standby mode
  int error = Wire.endTransmission();
  if( error != 0)
  {
   Serial.println( "Where is the sensor");
  }

  delay(500); //delay between transmissions
  
  Wire.beginTransmission(address);
  Wire.write(0);  // register address, 0 or 1
  Wire.endTransmission(false);  // false for a "repeated start"
  
}

void loop() {


  int n = Wire.requestFrom(address, 1); // request 1 byte
  if( n == 1)        // 1 bytes requested, was 1 byte received ?
  {
   // The lowest 8 bits contains the signed temperature in Celsius
   int8_t reading = Wire.read() & 0xFF;   // or signed char = Wire.read();
   int myCelsius = int(reading);   // convert it to integer (easier to print)
   Serial.println(myCelsius);
  }
  else
  {
   Serial.println( "Something wrong");
  }

  
    delay(1000);    //delay in between readings
  }

As of now, it’s still giving me readings of 28 deg C

jremington:
I think it would even better if you would update the page on "Explanation of the functions" to include the function parameters, and an explanation about what they do.

Your wish is my command: Explanation of the functions of the Wire library · Koepel/How-to-use-the-Arduino-Wire-library Wiki · GitHub.
It is explained in the Arduino reference, so I made my own alternative explanation. The explanation for the third parameter of Wire.requestFrom() is easy, no one needs it :wink:

decipheredenigma:
As of now, it's still giving me readings of 28 deg C

Ouch ! Could the sensor be damaged ?
You have two variables called 'reading' and you don't get a warning from the compiler, because that is allowed in the 'C' language. The compiler uses the most local one. Nevertheless, it is confusing, you can remove the global one.

In your first tests, when the real temperature is below 0°C, you should have read a value of above 127°C (treating the signed 8-bits as a unsigned part of a larger integer). I hoped that problem would be solved with that extra delay. Since you always read that temperature in all these tests, the TC74 could be damaged. You can try to put it in ice and it hot water. But I have no more ideas.

I'll keep trying and see what I can do and update the thread if anything comes up.

Really appreciate the help, though! :smiley:

Could be worth checking your TC74 is working properly by testing with the Arduino TC74_I2C Library.

srnet:
the Arduino TC74_I2C Library.

Link please !

This one ? https://github.com/Mario-H/TC74_I2C/blob/master/TC74_I2C.cpp [EDIT] The repository was not available at 22 April 2021 anymore.

It has a weird way to deal with a 8-bit signed value:

if(rdata & NEGATIVE){
  rdata = -1*((rdata ^ 0xFF )+1);
}

It also does not use a repeated start, which is in the datasheet. The rest of the code is the same that decipheredenigma already has.

Koepel:
Link please !

You posted it.

As for it being weird, no comment, but it does work.

Hi, do you have another link, it says that this one doesn’t exists.

Hi, i’m working also with this sensor, can you please tell me if it worked for you?

That repository has been removed !
I can not find other Arduino code, but it is only two registers.