Sunday, January 22, 2012

TMP36 Temperature Sensor

Before I got on a side-track on the MQTT project, I'd wanted to interface with a temperature sensor. The one I had originally chosen turned out to be a one-wire digital sensor.  This is probably a great sensor, but there are, as I understand now, some issues with the Netduino and one-wire sensors.  So, that sensor got sidelined until this support is fixed up and in non-beta firmware (or until I buy a FEZ Cobra - which would address several issues I'm facing - albeit with a significantly higher price tag.)

So, off I went to find a analog temperature sensor.  There are numerous options - I even briefly thought about drafting one of my MSP430's for this.  :)

But I settled for a TMP36 from Futurlec.  This (I mean 'these' - never only buy 1 of anything :) ) arrived on Friday after a trip from Hong Kong along with a bunch of random odds and ends that I'm tired of going to Radio Shack to get - 2 at a time (I'm ok with 100%+ markup to get it in town - but throw 10-20 into a bag, not 2).

Between the datasheet (http://www.analog.com/static/imported-files/data_sheets/TMP35_36_37.pdf) and some help from the AdaFruit blog (http://www.ladyada.net/learn/sensors/tmp36.html) we got it working pretty well.


The cap is actually a normal orange ceramic disk - not sure why Fritzing doesn't have those.  It was added per the datasheet (0.1uF) for RFI purposes - but, in my non-scientific testing, it didn't make any difference if it was there or not (at least in my environment - which I'd figure is a mess RFI-wise).

I have several temperature sensors that I want to play with, so we made a class to hold those:


using System;
using System.Threading;
using Microsoft.SPOT;
using Microsoft.SPOT.Hardware;
using SecretLabs.NETMF.Hardware;

namespace Temperature_Sensors
{

    public static class TMP36
    {

        // port is analog port
        // sample is the number of samples to take
        // interval is the time (ms) to wait between samples
        // voltage is input voltage * 1000, default is 3.3v
        public static float getVoltage(AnalogInput port, int sample = 10, int interval = 100, int voltage = 3300)
        {
            int reading = 0;
            for (int i = 0; i < sample; i++)
            {
                Thread.Sleep(interval);
                // Read the value on the AIO port
                reading += port.Read();
            }
            reading /= sample;
            Debug.Print("Reading: " + reading + "");
            // Voltage at pin in milliVolts = (reading from ADC) * (3300/1024) http://www.ladyada.net/learn/sensors/tmp36.html
            return (reading * (voltage / 1024F));
        }

        public static float getCTemp(AnalogInput port, int sample = 10, int interval = 100, int voltage = 3300)
        {
            // Temp in °C = [(Vout in mV) - 500] / 10 http://www.ladyada.net/learn/sensors/tmp36.html
            return ((getVoltage(port, sample, interval, voltage) - 500F) / 10F);
        }

        public static float getFTemp(AnalogInput port, int sample = 10, int interval = 100, int voltage = 3300)
        {
            // Convert to °F 
            return ((getCTemp(port, sample, interval, voltage) * (9F / 5F)) + 32F);
        }
    }
}

And here is a program to drive this - with a timer being used to periodically collect the temperature:


using System;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using Microsoft.SPOT;
using Microsoft.SPOT.Hardware;
using SecretLabs.NETMF.Hardware;
using SecretLabs.NETMF.Hardware.NetduinoPlus;
using Temperature_Sensors;

namespace myTempSensor
{
    public class Program
    {
        static AnalogInput analogInput;

        static void checkTemp(object o)
        {
            float fTemp = TMP36.getFTemp(analogInput, 10, 100, 3300);
            Debug.Print("Temp: " + fTemp + "");
        }

        public static void Main()
        {

            analogInput = new AnalogInput(Pins.GPIO_PIN_A0);
            Timer tempTimer = new Timer(new TimerCallback(checkTemp), null, 1000, 10000);

            // go to sleep until the timer wakes us (saves power)
            Thread.Sleep(Timeout.Infinite);
        }
    }
}


Right now we're not doing anything with this data - but soon we'll smoosh this up against the MQTT stuff and start getting this published - probably to the test.mosquitto.org server.

<aside>
Speaking of which - we might have to take another break and write some visualization stuff - Roger of Mosquitto fame has issued a challenge (http://mosquitto.org/2012/01/challenge-web-based-mqtt-graphing/) for visualization of some energy data that is being fed to his server.  This might be fun.  I'm thinking of using the Node.js client then feeding that data into the Google charts API.
</aside>

Anyway, I haven't got this sensor to be particularly accurate yet.  Although, forcing my math to floating point math REALLY helped.  :)  I may just try a thermistor.  Not sure, I'm sure that a digital sensor is probably the right plan...  I think my main problem at this point is the accuracy of the sensor (+-2C), mixed with the stated "non-high precision" of the Netduino ADC's.  So, this combination seems to be about as accurate as that of my other "high precision" thermometer.  :)



Since the accuracy is odd - I added the ability to collect a bunch of readings and average them.  Not sure it really helped as much as I would have expected either, but it's there.

I think next up is going to be a Syslog library for the Netduino - which will require an NTP library since I don't have an RTC board handy and you need time for logs.  (FEZ Cobra has one though I think....Which might be a better approach than buying a mini-board...  I don't know...  I could do SSL with the Cobra too...)

And we'll keep working on the MQTT stuff.  Still need a couple message handlers and to redo some stuff related to the fixed headers.

Also, kind of seriously thinking about writing an MQTT-S gateway (forwarder?) and client for the Netduino Plus - then getting some sort of comm stuff to talk between a few things around here.  I'm kind of taking that "no publicly available implementation" bit as a challenge...  :)


6 comments:

  1. The problem I have with the TMP36 is that it varies according to the voltage supplied. Works pretty flawlessly when my *duino is plugged in to USB, but anything wireless and battery powered, the voltage varies and so the temperature readings are not so great.

    ReplyDelete
  2. Thanks for your insight! I'd thought about power - but I'd thought about it in terms of 3.3v versus 5v (which did not help). I'll give this a try tonight!

    ReplyDelete
  3. I tried that and it does look like it might have helped a bit. A large number of the readings are very close and some are even identical. But there are still a few way off readings: 77, 77, 77, 83, 77, 77, 69, etc.

    I pulled out the multimeter and the input voltage is a solid 3.3(02). The measure coming out of the TMP36 is also very stable (and oddly, for a Celcius sensor, very well aligned with the room temp in F (maybe better - this room probably about 70 - the output from above says 77 - the meter said .77.) o_O

    ReplyDelete
  4. I am happy to found this Website. Show appreciation you for posting this. I just have to say Great information. I like how you have presented your information in outstanding detail.
    Home Alarm Installation

    ReplyDelete
  5. I am Justin and new member in this community. I recently came across your forum I thought I would leave my first comment. I will keep visiting to this community. Here lots of discussion will help to understand the forum better.
    Thanks all the member.
    Temperature Sensor

    ReplyDelete