Soil temperature is one of the things the Garduino monitors.  Unfortunately, soil is a harsh environment and replacing a $1.50 TMP36 everything time one stopped working was becoming a bit of a drag, so I looked for something cheaper.  The MCP9700 is a temperature sensor available from for $0.34, and at that price, I feel a little more free to experiment with waterproofing these sensors.

These devices are pretty nice to work with, since they can take a supply voltage of 2.1 to 5.5V and the output pin will be at .5V at 0° C and rise 0.01V for every rise in 1°C.  This document  describes how to compensate for 2nd order effects to increase accuracy further.

It is critical to put a capacitor between the Vout pin in ground (about 2nF), because without it, there is a 27kHz wave that appears on the output.  In my tests, Vout oscillated 0.0575 Volt P-P, which represents a variation of 5.75 °C from reading to reading.  With the capacitor between Vout and GND, the variation between readings drops to about 0.5°C.

The code for reading the temperature of these devices is pretty straightforward:

float readMCP9700(int pin,float offset)
  for (int n=0;n<5;n++)

  int adc=analogRead(pin);
  float tSensor=((adc*(1.1/1024.0))-0.5+offset)*100;
  float error=244e-6*(125-tSensor)*(tSensor - -40.0) + 2E-12*(tSensor - -40.0)-2.0;
  float temp=tSensor-error;

  return temp;

In my application, I have some ADC calls done against the 5V analogReference, and the analogReads for the MCP9700 are done against the internal 1.1V reference.  According to the ATMega328 datasheet, when switching between references, you should throw out the reading immediately after the switch, because it will be inaccurate.  In this function, I throw out  5 readings after setting the analogReference, just to give it extra time to settle down, and then I take the real measurement.  The 2nd order error is calculated as described in the accuracy compensation document mentioned above.

I also pass in an offset to allow me to adjust each individual sensor against a know temperature.  In my case, I really didn’t have a know temperature reading I thought was any more accurate than anything else I had, so I setup 4 MCP9700s and let them read the same temperature.  I averaged these readings, and I pass in the offset for each individual MCP9700 from that average, so, if nothing else, the temperatures read between these 4 devices will be consistent.  The offsets were on the order of 0.01V.