Learn Arduino with Olympia Circuits
Learn Arduino
  • Home
    • Get Started
    • How to Use This Site
  • Electronics
    • The Basics
    • Electricity Flows like Water
    • Electronic Components
    • The Arno Board
  • Programming
    • The Basics
    • setup and loop Blocks
    • Variables and Arrays
    • Connecting with the Pins
    • Flow Control >
      • if Statement
      • Loops
      • Delays
    • Functions
    • Serial Communication
    • USB
    • Some Thoughts
  • Projects
    • Projects 1 >
      • 1.01: Blink
      • 1.02 Blink x2
      • 1.03 Blink Faster
      • 1.04 LED Chase!
      • 1.05 Wait To Blink
      • 1.06 Blink a Little Faster Now
      • 1.07 LED Fade
      • 1.08 RGB Blink
      • 1.09 Change RGB Color with SW1
      • 1.10 Fade RGB Colors
      • 1.11 Reaction Time Game
    • Projects 2 >
      • 2.01 Hello World
      • 2.02 Talk Back
      • 2.03 ASCII Values
      • 2.04 Ski Game
      • 2.05 Demonstration of the String Object
    • Projects 3 >
      • 3.01 Read the Potentiometer
      • 3.02 ASCIIbet Soup
      • 3.03 Potentiometer sets LED Brightness
      • 3.04 Potentiometer Sets Blink Rate
      • 3.05 LED Chase, Part II
    • Projects 4 >
      • 4.01 Bringing the Piezo to Life
      • 4.02 Controlling the Piezo with a Function
      • 4.03 Piezo C Major
      • 4.04 Piezo Greensleaves
      • 4.05 Piezo Metronome
      • 4.06 Piezo as an Input
      • 4.07 Piezo as an Input 2
      • 4.08 Metronome II
      • 4.09 Piezo Playback
      • 4.10 Piezo Fireworks
      • 4.11 Piezo Mosquito
    • Projects 5 >
      • 5.01 The Phototransistor
      • 5.02 Light and Sound
      • 5.03 Light and Sound II
    • Projects 6 >
      • 6.01 EEPROM
      • 6.02 I2C Address Scan
      • 6.03 Read the I2C Temperature Sensor
      • 6.04 High Temperature Alarm
    • Projects 7 >
      • 7.01 Arno Phone Home
      • 7.02 Keyboard Alphabet
      • 7.03 Move Mouse
      • 7.04 Draw Squares
    • Special Projects >
      • Bike Light Demo
  • References
    • Arno Pin Key
    • Arno Schematic
    • Project Index

Project 6.03 Read the I2C Temperature Sensor

Project 6.03 Read the I2C Temperature Sensor In the previous project, we “discovered” the temperature sensor on the I2C bus.  In this project, we actually read the temperature from the sensor.  There are a lot of I2C devices and they are setup in different ways.  As you move into more complex projects, you will need to look at the datasheets for your I2C devices.  Datasheets are easy to find on the web.  The datasheets will tell you how to setup the device in different ways and how to read and write to the device.

Most I2C devices will have multiple registers.  A register is a one or more bytes of memory that can be read, written, or both.  On the TCN75A, register 0 holds the temperature reading. This is a read-only register.  Each time the device makes a reading, it loads the results to register 0. Register 1 holds configuration information.  The device can be setup to encode the temperature with different numbers of bits.  In this project, we set register 1 to encode with the maximum of 12 bits.  This gives us the maximum available resolution.

It’s fun to look at the datasheets for different devices to learn about all of their functions.  The devices are often quite sophisticated. There are two additional register in the TCN75A where you can set “alarm” values.  These can be configured to trigger an alarm when the temperature is higher or lower that the values set in the registers. We don’t use the alarm functions with the Arno since we did not connect the IC’s alarm pin to one of the I/O pins on the microcontroller.  You might decide to use the alarm when you design your own circuits.

If you haven’t done project 6.01, you should do it now to become familiar with bit shifting.  We use bit shifting to read the temperature sensor in this project.

Concepts: I2C communication, Wire library

Circuits:
  • Circuit 8


  • Select Sketch

    ///////////////////////////////////////////////////
    //Project 6.03 Read TCN75A Temperature Sensor
    int tempreg = 0;
    float temperature = 0;
    byte address = 72;
    void setup(){
    Serial.begin(9600);
    Wire.begin();
    //Do some setup for the sensor
    // Set the resolution of the measurement
    Wire.beginTransmission(address);
    // point to Configuration Register
    Wire.write(0x01);
    // set the resolution
    Wire.write(0x60);
    // ends the command
    Wire.endTransmission();
    // points to the Temperature Register
    Wire.beginTransmission(address);
    Wire.write(0x00);
    Wire.endTransmission();
    }
    void loop(){
    // Receives data from the Temperature Register
    Wire.requestFrom(address,byte(2));
    tempreg = Wire.read();
    tempreg= tempreg << 8;
    tempreg |= Wire.read();
    tempreg = tempreg >> 4;
    // Calculate the temperature
    temperature =( float ) tempreg / 16;
    // Display the temperature in the Serial Monitor
    Serial.print(Temp F = );
    Serial.print(temperature*9/5 + 32,2);
    Serial.print( );
    Serial.print(Temp C = );
    Serial.println(temperature, 2);
    delay(500);
    }
    ///////////////////////////////////////////////////

    Since we want to use I2C communication, we need to include the Wire library in the program:

    #include <Wire.h>

    The reading from the sensor will initially be stored as int but later converted to a float:

    int tempreg = 0;        

    float temperature = 0;   

    The IC address needs to be encoded as a single byte:

    byte address = 72;

    In the loop() block, we create an instance of a Wire object:

    Wire.begin();

    Now we setup the sensor’s resolution by writing to register 1.  We start the communication session with the wire.beginTransmission statement with the IC’s address:

      // Set the resolution of the measurement

      Wire.beginTransmission(address);

    The next communication that the sensor expects is a pointer to a register.  We point to the configuration register using the hexadecimal value for the register:

      // point to Configuration Register

      Wire.write(0x01);  

    We now write a value to the register.  The value represents 8 bits.  Each of these bits does something different.  Only bits 6 and 5 set the temperature resolution.  The other bits set up other parameters.  We won’t get into all of the parameters here, but it’s not really complicated.  You can look at the datasheet and decide whether each bit of the register should be a 1 or 0 based on the configuration that you want.  You can then enter the bits into an online binary-to-hexadecimal converter to find the equivalent hexadecimal value.  In our case it’s 0x60.

      // set the resolution 

      Wire.write(0x60);  

    With the resolution set, we end the transmission:

      // ends the command 

      Wire.endTransmission(); 

    Before the end of the setup() block, we set a pointer to register 0.  Register 0 holds the temperature reading.  This sets us up to read the temperature register in the loop() block:

    // points to the Temperature Register 

      Wire.beginTransmission(address); 

      Wire.write(0x00);           

      Wire.endTransmission(); 

    In the loop() block, we begin to read the temperature sensor.  The Wire.requestFrom function has two arguments.  The first argument is the device’s address.  The second argument if the number of bytes requested.  This argument needs to be a byte value, so we cast the number ‘2’ to a byte variable within the function call.  The device knows that we want the value of register 1 since we pointed to it in our previous transmission:

      // Receives data from the Temperature Register

      Wire.requestFrom(address,byte(2));

    The two bytes are now stored in a buffer in the microcontroller.  The Wire.read() function reads one byte and loads it into the variable tempreg:

      tempreg = Wire.read();  

    Remember tempreg is a 16-bit int variable.  The temperature value is encoded as a 12 bit number.  The first byte includes the 8 left-most (highest) bits of the temperature value.  We need to move these all the way to the left-hand side of the bits that make up tempreg:

       

      tempreg= tempreg << 8; 

    We use the or operator, |, to load the remaining bits:   

      tempreg |= Wire.read(); 

    We’ve now loaded 16 bits into tempreg.  But remember that the temperature value is only coded in 12 bits. The second byte we read only contained information in the 4 left-most bits.  The rest were zeros.  We don’t need them, but they will mess up our temperature value since the bits we do need are shifted too far to the left.  Now we need to shift all of the bits back right:

      tempreg = tempreg >> 4; 

    The right-shit operator is a little different than the left-shift operator.  The left-most bit of an int is the sign bit.  It indicates whether the value is positive or negative.  The right-shift operator is smart enough to leave that bit in its place and shift the rest.

    Now for some math.  We have a 12-bit integer value that represents a temperature between -40 and +125 °C.  The datasheet provides the conversion equation.  The resulting value is cast to a float to retain the decimal part:

      temperature =( float ) tempreg / 16;

    We’re almost there!  Now we just need to output our results in both Fahrenheit and Celsius.  The second argument in some of the Serial.print statements below sets the number of decimals to include:

      // Display the temperature in the Serial Monitor

      Serial.print("Temp F = ");

      Serial.print(temperature*9/5 + 32,2);

      Serial.print("   ");

      Serial.print("Temp C = ");

      Serial.println(temperature, 2);

    This project is a little more complicated than our others.  It takes some work to figure out how to use different I2C devices.  A good place to start is by doing an internet search to see if someone has already figured out the device that you want to use.  One great thing about being part of the Arduino community is building on the experience of other community members.  Just remember to share your code when you figure out something new!

    Back to Projects 6

    Copyright Olympia Circuits LLC 2014. All Rights Reserved.