Fork me on GitHub

Blog

How’s the weather? TMP102 + Raspberry Pi + plain old C/C++

Tags: Raspberry Pi, Sensors

Measuring temperature is very easy when you have a Pi and a temperature sensor like the TMP102. What’s great about the TMP102 is that

  • it’s tiny 
  • it doesn’t require a lot power (1.4V to 3.6VDC) 
  • accurate (senses differences up to 0.5°C) 
  • it communicates via the I2C bus

The Raspberry Pi let’s you easily communicate with the TMP102 using I2C. There are a lot of examples about how to test the sensor but actually there’s not much out there if you want to write a C/C++ executable that would use the I2C bus to communicate with the sensor. This post is exactly about playing around with a temperature sensor and the Raspberry Pi I2C bus from a very simple C executable.

Configuring the Raspberry Pi I2C port

The Raspberry Pi I2C port is not enabled by default. First You need to enable it by removing it from the blacklist with one of the Pi’s config files:

$sudo vi /etc/modprobe.d/raspi-blacklist.conf

Once this file is open find this line blacklist i2c-bcm2708 and comment it out by adding a # to the front of it.

#blacklist i2c-bcm2708

Save the file and reboot. To use the I2C bus from userspace you’ll need to load the i2c-dev module by running this command:

$sudo modprobe i2c-dev

Now if you check your /dev/ directory you should see the i2c devices listed among the others. On the Raspberry you should see /dev/i2c-0 and /dev/i2c-1 listed. To be able to use these ports you need to give yourself permission to access them.

$sudo chmod o+rw /dev/i2c*

Now you are ready to proceed. However once you reboot the Pi you will have to do the last two commands again. Therefore you can add them to the /etc/rc.local script. To learn more about the Raspberry Pi Kernel modules and how to write your own modules check Chris’s blog here

The Wiring

I2C is a 2-wire serial connection, SDA (Data) and SCL (Clock) – On your Raspberry Pi SDA is on GPIO 0, and SCL is on GPIO 1. Have a look at the schematics here. Here is a picture:

I2C allows you also to have connect more than 1 sensors to your Pi. Note that the TMP102 sensor has a ADD0 pin. If you connect this pin to Ground the address of the device on the Pi would be 0x48. If you connect it to VCC it would be 0x49. We would need these address later in the code. Here is how we can wire two temperature sensors on a breadboard.

The Code

Here is the code. Note that to communicate with through the I2C bus we are using the built in libraries. To do this we need to know the device we want to use and the address. Here the address is 0x48 and the wiring follows the first image above. The sensor has 4 registers that are accessible through the I2C bus:. Register #0 is the Temperature Register, it is Read Only and is the one we will be using. Other than this we have Register #1 which is a Read/Write register used for configuration. When we start reading from Register #0 we are interested in the first two bytes, which are:

  • Byte 1: Full degrees
  • Byte 2: Fraction degrees

To convert to °C, we use these two bytes, shift right by 4, convert to decimal and multiply by 0.0625. Read more about the Registers details at Donal's blog post here

#include <stdio.h>
#include <stdlib.h>
#include <linux/i2c-dev.h>
#include <fcntl.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>

int main(int argc, char **argv)
{
    unsigned int temp = 0;
    unsigned char msb, lsb;

    printf("**** Tmp102 test program ****,\n");
    int fd;                                    // File descritor
    char *fileName = "/dev/i2c-0";             // Name of the port we will be using
    int  address = 0x48;                       // Address of TP102
    unsigned char buf[10];                     // Buffer for data being read/ written on the i2c bus

    if ((fd = open(fileName, O_RDWR)) < 0) {   // Open port for reading and writing
            printf("Failed to open i2c port\n");
            exit(1);
    }

    if (ioctl(fd, I2C_SLAVE, address) < 0) {  // Set the port options and set the address of the device we wish to speak to
            printf("Unable to get bus access to talk to slave\n");
            exit(1);
    }


    buf[0] = 0;                                // This is the register we wish to read from

    if ((write(fd, buf, 1)) != 1) {            // Send register to read from
            printf("Error writing to i2c slave\n");
            exit(1);
    }

    if (read(fd, buf, 1) != 1) {                // Read back data into buf[]
            printf("Unable to read from slave\n");
            exit(1);
    }
    else {
            msb = buf[0];
            printf("0x%02X ", msb);

            if (read(fd, buf, 1) != 1) {         // Read back data into buf[]
                    printf("Unable to read from slave\n");
                    exit(1);
            } else {
                    lsb = buf[0];
                    temp = (msb<<8) | lsb;
                    temp >>= 4;

                    printf("The temperature is: %f \n",temp*0.0625);
            }
    }

    return 0;
}

What's more

In the next post there would a lot on how we used the tiny temperature sensor in Agilart for prototyping with visuals(no coding required):

 

Add a Comment