.net, Raspberry Pi 3

How to read the temperature from the TMP102, using C# and the Raspberry Pi 3

This is the latest in my series of tutorials on how to use C# to get readings from different sensor microchips – this time I’ll look at the digital temperature sensor TMP102.

I’ve previously created a NuGet package which I use to simplify developing in C# for I2C devices, and I’ll use this again in this project.

Getting started

I created a blank Windows 10 UWP solution in Visual Studio 2015, and I added a reference to the “Windows IoT Extensions for the UWP”.

screenshot.1462650773

Next, I searched on NuGet for my I2C library, and added this to the project also.

I created a class named TMP102, which extends the AbstractI2CDevice class from my I2C library.

Getting the I2C Slave Address for the TMP102

The TMP102 has an interesting feature, as it has a pin A0 which allows the I2C slave address to change depending on what A0 is connected to.

  • If it’s connected to ground, the slave address is 0x48.
  • If it’s connected to 3.3V, the slave address is 0x49.
  • If it’s connected to the data line SD, the slave address is 0x4A.
  • If it’s connected to the clock SCL, the slave address is 0x4B.

I created an enumeration in C# to represent this information.

public enum A0PinConnection
{
    Ground = 0x48,
 
    VCC = 0x49,
 
    SDA = 0x4A,
 
    SCL = 0x4B
}

I use this enumeration as a parameter to the constructor for the TMP102, as it helps me define what the I2C slave address should be at the time the object is instantiated.

public class TMP102 : AbstractI2CDevice
{
    private byte I2C_ADDRESS;
 
    public TMP102(A0PinConnection pinConnection)
    {
        I2C_ADDRESS = (byte)pinConnection;
    }
 
    public override byte GetI2cAddress()
    {
        return I2C_ADDRESS;
    }
 
    //...
}

By extending the AbstractI2CDevice class, I have to create a concrete implementation for the GetDeviceId method. However, there is no unique device identifier for the TMP102 (or at least not one that I can find), so I throw a NotImplementedException.

public override byte[] GetDeviceId()
{
    throw new NotImplementedException("This device does not have a unique device identifier.");
}

Getting the temperature from the TMP102

I connected the TMP102 directly to my Raspberry Pi 3, using 4 connectors:

  • 3.3v to Pin 1
  • Ground and A0 to Pin 6
  • SCL (serial clock) to Pin 5
  • SDA (serial data) to Pin 3

It’s very easy to get the temperature – I simply write the slave address to the device, and read back the two bytes that are returned. The values of two bytes can be used to calculate the temperature – according to the datasheet, only the first 12 bits of information are used to calculate the temperature (8 from the most significant byte, and the biggest 4 from the least significant byte). The number represented by these 12 bits is multiplied by 0.0625 to get the temperature in Celcius.

So this can be put together into a fairly simple method to get the temperature:

public float GetTemperature()
{
    byte[] readBuffer = new byte[2];
            
    this.Slave.WriteRead(new byte[] { I2C_ADDRESS }, readBuffer);
 
    var mostSignificantByte = readBuffer[0];
 
    var leastSignificantByte = readBuffer[1];
 
    // this formula is from the data sheet.
    // 1. Add the most significant and least significant bytes (using logical OR)
    // 2. Right shift the sum by 4 places (i.e. divide by 16)
    // 3. Multiply by 0.0625
    var bytesAddedTogether = mostSignificantByte << 8 | leastSignificantByte;
 
    var bytesRightShiftedByFourBits = bytesAddedTogether >> 4;
 
    return bytesRightShiftedByFourBits * 0.0625f;
}

So this can all be combined into a single class, as shown below.

public class TMP102 : AbstractI2CDevice
{
    private byte I2C_ADDRESS;
 
    public TMP102(A0PinConnection pinConnection)
    {
        I2C_ADDRESS = (byte)pinConnection;
    }
 
    public override byte GetI2cAddress()
    {
        return I2C_ADDRESS;
    }
 
    public override byte[] GetDeviceId()
    {
        throw new NotImplementedException("This device does not have a unique device identifier.");
    }
 
    public float GetTemperature()
    {
        byte[] readBuffer = new byte[2];
            
        this.Slave.WriteRead(new byte[] { I2C_ADDRESS }, readBuffer);
 
        var mostSignificantByte = readBuffer[0];
 
        var leastSignificantByte = readBuffer[1];
 
        // this formula is from the data sheet.
        // 1. Add the most significant and least significant bytes (using logical OR)
        // 2. Right shift the sum by 4 places (i.e. divide by 16)
        // 3. Multiply by 0.0625
        var bytesAddedTogether = mostSignificantByte << 8 | leastSignificantByte;
 
        var bytesRightShiftedByFourBits = bytesAddedTogether >> 4;
 
        return bytesRightShiftedByFourBits * 0.0625f;
    }
}

With this class, it’s very easy to write a method which will get the temperature and write to the output.

private async Task WriteTemperatureSettingsToDebug()
{
    var temperatureSensor = new TMP102(A0PinConnection.Ground);
 
    await temperatureSensor.Initialize();
            
    while(true)
    {
        var temperature = temperatureSensor.GetTemperature();
 
        Debug.WriteLine("Temperature = " + temperature);
 
        Task.Delay(1000).Wait();
    }
}

I’ve created a UWP library project on GitHub so that other people can use this code with the TMP102.