Since .NET Micro Framework has good support for I2C bus and I finally get the DS1631 thermometers, I’ve decided to create some nice demo as Tony Pitman did. Measuring temperature is grateful topic, so let’s build thermometer for measuring indoor and outdoor temperature with clock display and unit conversion. As a cherry on top, there will be the man dressing-up according to outside conditions. See more on the video below.

Hardware

There are no special needs for hardware or tools. I assume that readers already have some development kit for .NET Micro Framework. I’am personally happy with Tahoe from EmbeddedFusion, so informations in this article are related to it. For demonstration purpose I’am using non-soldering project board to wire-up the temperature sensors.

Here is the list of parts used.

  1. .NET Micro Framework development kit
  2. Project board or circuit board
  3. 2x DS1631 thermo-sensors
  4. 2x resistor 4k7 ohms
  5. Some wires

Home thermometer project board 400x280 Figure 1

DS1631 is clever device that can behave as standalone temperature regulator. Today we will use it only for temperature measuring. Figure 3 shows very simple DS1631 pin-out. VDD pin is for input voltage, GND is for ground, SCL and SDA are I2C bus connection. The A0 A1 A2 are for configuring the device address on I2C bus. Those connected to input voltage are 1, those connected to ground are 0. Address is created by this simple key 1 0 0 1 A2 A1 A0. Figure 1 and 2 shows, that indoor sensor has address 1001 111 = 0x4F, outdoor sensor is 1001 011 = 0x4B.

Home thermometer scheme 400x210 Figure 2

DS1631 pin out 135x90 Figure 3

Wiring-up is simple, I’am using following color scheme: red wire for input voltage, blue for ground, yellow for SDA, white for SCL, green wires are for addressing. Those two resistors are pull-ups for SCL and SDA on I2C bus. It means, there will be always two - no matter how many sensors will be connected. Figure 4 shows how to connect I2C bus to Tahoe board. There are pins marked SDA and SCL. Input voltage is +5V and ground is 0V.

I2C Tahoe 400x210 Figure 4

Communication with sensors

I wrote I2C driver for basic communication with DS1631. Since DS1631 is able to operate in continuous or single-shot modes and with different number of bits, this driver configures DS1631 to single-shot mode with 12bit accuracy. Configuration is done by the Init() method, which resets the device and writes configuration register value. More information about configuration register can be find in documentation for DS1631.

public bool Init()
{
    bool status;

    try
    {
        // Power-On reset (0x54)
        i2cBus.Write(_slaveConfig, new byte[1] { SOFTWARE_POR }, I2C_TIMEOUT);
        Thread.Sleep(100);
        // Set configuration for 1SHOT and 12bit accuracy 
        // (0xAC, 0x8D)
        i2cBus.Write(_slaveConfig, new byte[2] { ACCESS_CONFIG, INIT_CONFIG }, I2C_TIMEOUT);
        Thread.Sleep(100);
        status = true;
    }
    catch
    {
        status = false;
    }

    return status;
}

Reading actual temperature from DS1631 is two step process. First the Start Convert [0x51] command is send. The the device starts conversion of analogue temperature value to digital (bit) representation. This process takes about 750ms for 12bit accuracy. When conversion is done, master sends Read Temperature [0xAA] command and awaiting two bytes message from device. Two bytes represents MSB and LSB (most/least significant byte), which must be decoded for real temperature value. Method GetTemperature() returns actual temperature from device.

Sometimes the communication with device fails, in such a cases I’am doing re-initialization with the Init() method.

public float GetTemperature()
{
    // Start conevrt command (0x51)
    i2cBus.Write(_slaveConfig, new byte[1] { START_CONVERT }, I2C_TIMEOUT);
    
    // Wait to conversion end
    Thread.Sleep(750);
    
    // Read temperature command (0xAA)
    i2cBus.Write(_slaveConfig, new byte[1] { READ_TEMPERATURE }, I2C_TIMEOUT);

    // Read MSB and LSB of the temperature
    byte[] readBuffer = new byte[2];
    i2cBus.Write(_slaveConfig, readBuffer, I2C_TIMEOUT);

    // Get MSB and LSB together
    int temp = readBuffer[0];
    temp <<= 8;
    temp |= readBuffer[1];

    // Negative value test (subzero temperature)
    temp -= (readBuffer[0] >= 0x80) ? 65536 : 0;

    // Get the temperature in Celsius
    return (float)((temp >> 4) * 0.0625);
}

Source code

Project source code consist of few UI and hardware related classes. Figure 5 shows the MainWindow class which utilize classes inherited from ContentControl to build the application UI. Temperature displays has properties for actual temperature and units to display. Most of the application logic is in the MainWindow class. Thermometer class from figure 6 is the ‘safe’ wrapper around DS1631 driver class. The NumberFormatter is helper class to convert numbers to strings in desired format.

Home thermometer UI classes 430x250 Figure 5

Home thermometer UI classes 560x180 Figure 6

The only one platform specific option in source is in GPIOButtonInputProvider.cs file on lines 39-45. It is an button mapping for specific pins of the CPU. I’am using pins on Meridian CPU which are wired to Up, Down and Select button on Tahoe development kit.

ButtonPad[] buttons = new ButtonPad[]
{
    // Associate the buttons to the pins as setup in the emulator/hardware
    new ButtonPad(this, Button.Up    , Meridian.Pins.GPIO5),
    new ButtonPad(this, Button.Down  , Meridian.Pins.GPIO9),
    new ButtonPad(this, Button.Select, Meridian.Pins.GPIO7),
};

Buttons has different meaning according to system state, method OnButtonDown in MainWindow class is responsible for this functionality. Select button toggles system into clock setting mode, in this mode Up and Down buttons is used to adjust hours and minutes. While in ‘normal’ mode, Up button toggles Celsius/Fahrenheit units and Down button turns off the backlight.

private void OnButtonDown(object sender, ButtonEventArgs e)
{
    // When backlight is off, then every click turns it on
    if (backlightStatus == false)
        ToggleBacklight();
    // Toggling configuration mode (clock-hour, clock-minute, normal)
    else if (e.Button == Button.Select)            
        ToggleConfigMode();
    // In normal mode 'Up' button toggles temperature mode (Celsius, Fahrenheit)
    else if (e.Button == Button.Up && clockSettingMode == ClockSettingMode.None)
        ToggleTemperatureMode();
    // In clock setting mode 'Up' button changes clock
    else if (e.Button == Button.Up && clockSettingMode != ClockSettingMode.None)
        ClockChange(1);
    else if (e.Button == Button.Down && clockSettingMode == ClockSettingMode.None)
    // In normal mode 'Down' button toggles backlight
        ToggleBacklight();
    // In clock setting mode 'Down' button changes clock
    else if (e.Button == Button.Down && clockSettingMode != ClockSettingMode.None)
        ClockChange(-1);

    this.Invalidate();
}

Download

Source code is available for download HomeThermometer.zip

home thermometer tahoe 500x215 Figure 7