Built-in project · Arduino Uno R3

Thermometer on an Arduino Uno

A TMP36 on A0 and the temperature on a 16x2 LCD in four-bit mode, with the high and low on the second row. The whole build, an Arduino Uno and 2 more parts, runs here in your browser on the firmware below; open it in the editor to change the wiring or the code and run it again.

IntermediateRuns in your browser. Free, and no account needed.

Step by step, with the wiring and the common mistakes: Arduino TMP36 Temperature Sensor in °F and °C

Thermometer · Arduino Uno R3live0.000 s 0.00x
Click to open it in the editor
The circuit itself, running here on the simulator. Press what can be pressed; click anything else to open it in the editor.

The code

The firmware exactly as the editor opens it. Change a line there and press Run: it compiles in the browser.

sketch.ino · Arduino Uno R3
// Thermometer: a TMP36 on the analogue input, the reading on a 16x2 LCD.
//
//   A0      the TMP36's middle leg; its outer legs go to 5 V and GND
//   LCD     RS -> pin 12, E -> pin 11, D4..D7 -> pins 5, 4, 3, 2
//           RW -> GND, V0 -> GND for full contrast, A -> 5 V, K -> GND
//
// Two parts and no bus: the sensor is a voltage and the display is six wires.
// Drag the slider on the sensor to change the weather.
//
// # The sum, in whole numbers
//
// A TMP36 puts out 500 mV at zero degrees and moves 10 mV for every degree
// above it. The ADC gives 0 to 1023 against the 5 V reference, so
//
//   millivolts = reading * 5000 / 1024
//   celsius    = (millivolts - 500) / 10
//
// There is no soft-float runtime on this board, so none of that is done in
// floating point and none of it needs to be. 5000/1024 is exactly 625/128, and
// 10 mV a degree means one millivolt is one *tenth* of a degree, so the whole
// conversion is
//
//   tenths of a degree = reading * 625 / 128 - 500
//
// in 32-bit integers, and it is exact rather than nearly right.
//
// The offset is the trick of the part. It is what lets a sensor on a single
// supply read below freezing, and it is the thing every first sketch gets
// wrong by leaving it out.
//
// # Why the reading is averaged
//
// The ADC's last bit is noise, and one count is about five tenths of a degree
// here, so an unfiltered display flickers between two readings forever. Sixteen
// samples added up and shifted right by four is a divide-free mean.
//
// The second line is the lowest and highest it has seen since it was switched
// on, which is what turns a thermometer into something worth watching.

#include "mokxi_lcd1602.h"

const int SENSOR = A0;

Lcd1602 lcd(12, 11, 5, 4, 3, 2);

int16_t lowest = 32000;
int16_t highest = -32000;

/** Sixteen conversions, averaged, as tenths of a degree Celsius. */
static int16_t readTenths() {
  uint16_t total = 0;
  for (uint8_t i = 0; i < 16; i++) {
    total = (uint16_t)(total + (uint16_t)analogRead(SENSOR));
  }
  uint16_t mean = (uint16_t)(total >> 4);
  // 5000 mV over 1024 counts is 625/128, in 32 bits because 1023 * 625 does
  // not fit in sixteen. One millivolt above the 500 mV offset is a tenth of a
  // degree, so the millivolts are the tenths.
  int32_t millivolts = ((int32_t)mean * 625) / 128;
  return (int16_t)(millivolts - 500);
}

void setup() {
  lcd.begin();
  lcd.print("Mokxi thermo");
  Serial.begin(115200);
  Serial.println("Mokxi Arduino Uno: TMP36 thermometer on a 1602 LCD");
  Serial.println("drag the slider on the sensor to change the temperature");
  delay(600);
  lcd.clear();
}

void loop() {
  int16_t tenths = readTenths();
  if (tenths < lowest) {
    lowest = tenths;
  }
  if (tenths > highest) {
    highest = tenths;
  }

  lcd.setCursor(0, 0);
  lcd.print("Temp  ");
  lcd.printFixed(tenths, 1);
  lcd.print(" C");
  lcd.padLine();

  lcd.setCursor(0, 1);
  lcd.print("lo ");
  lcd.printFixed(lowest / 10, 0);
  lcd.print(" hi ");
  lcd.printFixed(highest / 10, 0);
  lcd.padLine();

  static int16_t said = -32000;
  if (tenths != said) {
    said = tenths;
    Serial.print("temperature ");
    Serial.print((int)(tenths / 10));
    Serial.print(".");
    Serial.print((int)(tenths < 0 ? -tenths % 10 : tenths % 10));
    Serial.println(" C");
  }

  delay(250);
}

Parts list

4 parts, plus the jumper wires. Every one is in the editor's parts bin.

How it is wired

9 connections, pin by pin, read from the circuit itself. Each line is one set of pins joined together, by a jumper wire or a breadboard strip.

  • Arduino Uno R3 pin 12; Character LCD, 16x2 pin RS
  • Arduino Uno R3 pin 11; Character LCD, 16x2 pin E
  • Arduino Uno R3 pin 5; Character LCD, 16x2 pin D4
  • Arduino Uno R3 pin 4; Character LCD, 16x2 pin D5
  • Arduino Uno R3 pin 3; Character LCD, 16x2 pin D6
  • Arduino Uno R3 pin 2; Character LCD, 16x2 pin D7
  • Arduino Uno R3 pin 5V; Temperature sensor pin VS; Character LCD, 16x2 pin VDD; Character LCD, 16x2 pin A
  • Ground: Arduino Uno R3 pin GND; Temperature sensor pin GND; Character LCD, 16x2 pin VSS; Character LCD, 16x2 pin V0; Character LCD, 16x2 pin RW; Character LCD, 16x2 pin K
  • Arduino Uno R3 pin A0; Temperature sensor pin VOUT

Change it and keep it

Open it in the editor, change the circuit or the code, and keep your version in a free account.