Posted by: disquisitioner | October 1, 2012

Arduino Analog Thermometer

My Arduino starter kit included an analog temperature sensor which happily matched my long-standing interest in having a home weather station. I wasn’t sure how, but clearly there had to be a path leading from measuring temperature with a simple sensor to building a more complete home weather station with an Arduino.

But first things first — figuring how how to use the TMP36 analog temperature sensor I had at hand. The TMP36 is popular because it is inexpensive, reasonably accurate, and provides linear values over a positive output range for typical human (not industrial) environments. Specifically the sensor outputs a voltage of 10mv per degree Centigrade with a constant offset of 500mv so at 20 degrees Celsius (68 degrees Farenheit) it reads 700mV. Adafruit has a great TMP36 tutorial and I happily followed it to build a thermometer with the TMP36 using code something like:

void loop() {
    reading = analogRead(sensorPin);    // Read TMP36 in input range 0-1024
    voltage = (reading * 5.0) / 1024.0; // Scale to actual voltage (5V Arduino)
    tempC = (voltage - 0.5) * 100;      // 10mv per degree with 500mv offset
    Serial.println(tempC);
}

Initially I was reporting the observed temperature by outputing readings to the Serial Monitor. That was easy, but meant I needed to have my laptop connected to see the readings which was inconvenient. My Arduino starter kit didn’t include an LCD, alas, so my next best alternative was to display the temperature in binary using LEDs. That worked but wasn’t great, so I ordered an LCD.

While waiting for the display to arrive I went to work figuring out how to measure the temperature some distance away from the Arduino. My first target was our refrigerator so I needed some kind of probe at the end of a few feet of wire. The TMP36 has three leads and is packaged in a TO-92 transistor-style case, and I happened to have a transistor socket from a previous electronics project. I soldered two feet of wire to each of the socket’s three connectors, inserted the TMP36, and I had my probe.  Now I could locate the TMP36 sensor up to two feet away from the Arduino, so dashed to the kitchen to take readings inside the refrigerator (and freezer) while keeping the Arduino outside.

When the LCD arrived a few days later I quickly replaced the binary LED “display” and modified the sketch to use the LiquidCrystal library included with Arduino 1.0. Now I had all the basics taken care of — crude probe with the TMP36 at the end of two feet of wire, sketch to take readings from the TMP36 and convert them to degrees, and an LCD to display instantaneous temperature.

It was at this point that I started to wonder about the readings I was seeing from the TMP36. I had expected the displayed temperature to be fairly stable within the sensor’s one degree Celsius accuracy rating but instead my readings varied over a several degree range and never seemed to reflect a stable temperature. I recalled that the Adafruit TMP36 tutorial recommended using a 3.3V analog reference for greater accuracy because the ten bits of Arduino analog-to-digital resolution span just a 3.3V range and so represent fewer millivolts per sampled bit. I followed the tutorial’s instructions and easily switched to operating with a 3.3V reference (remembering to scale the reading in my sketch against 3.3V rather than 5V).

That helped, but not enough. My next approach was to presume the troubling variation in sensor reading was due to noise that I could eliminate by averaging the instantaneous sensor value over an interval of many samples. I modified my thermometer sketch to do just that, sampling once a second and averaging five minutes worth of readings before updating the display. That meant introducing use of a timer and doing the averaging whenever five minutes have elapsed:

void setup() {
    ...
    prevMillis = millis(); // Initialize time keeping
    totalReading = 0;      // For totalling temp readings
    numReadings = 0;       // Count readings so we can compute the average
    ...
}

void loop()
{
    reading = analogRead(sensorPin);    // Read TMP36 in input range 0-1024
    voltage = (reading * 3.3) / 1024.0; // Scale to ref voltage (3.3V)
    tempC = (voltage - 0.5) * 100;      // 10mv per degree with 500mv offset

    totalReading += tempC; // Accumulate latest temp reading
    numReadings++;         // Inrement reading counter

    currentMillis = millis();      // Read clock
    if( (currentMillis-prevMillis) > 300000) { // 5 min (300,000ms) elapsed?
        avgTemp = totalReading / numReadings;
        Serial.print(Average Temperature: ");
        Serial.print(avgTemp);
        totalReading = 0;          // Clear out accumulator
        numReadings = 0;           // Reset counter to zero
        prevMillis = currentMills; // Update elapsed time point
    }
    ...
}

That gave me results like this:
Overall this looks much better. The full source for the sketch, complete with additional explanatory comments, details on Arduino pin assignments, optional debug output, specifics on wiring the LCD, use of customer characters on the display, and much more is available from the project repository on github.com

While I thought about looking for ways to further reduce the variability in readings from the TMP36 it was at this point that I decided it was time to explore using a digital sensor. More on that in an upcoming post.


Leave a comment

Categories