An Arduino thermometer with a TMP36 and an LCD
- 192parts on the bench
- 25boards running now
- 1.00xreal time, on every board
The TMP36 is the classic first temperature sensor: three legs, no library, no protocol, and a voltage that simply is the temperature. The circuit above is an Arduino Uno reading one on A0 and showing the temperature, plus the lowest and highest it has seen, on a 16x2 character LCD. It is running in your browser right now on the same sketch shown further down.
Drag the slider on the sensor and the display follows. The example prints Celsius, like the science lab thermometers most classes use, and this page shows the one line that turns it into Fahrenheit for a US weather-style reading.
What you need
- An Arduino Uno
- A TMP36 temperature sensor
- A 16x2 character LCD (the plain six-wire kind, not the I2C backpack version)
- A breadboard and jumper wires
Wiring
How the TMP36 turns heat into volts
Power the sensor and its middle leg sits at 500 millivolts at 0 °C (32 °F), and rises 10 millivolts for every degree Celsius above that. Room temperature, 25 °C or 77 °F, is 750 mV. A freezer at -10 °C (14 °F) is 400 mV.
That 500 mV offset is the whole trick of the part. It lets a sensor on a single 5 volt supply read below freezing without needing a negative voltage. It is also the thing almost every first sketch gets wrong. Leave it out, treating the sensor like an LM35 where 0 volts means 0 degrees, and every reading comes out 50 °C (90 °F) too hot.
The math, in whole numbers
analogRead gives 0 to 1023 against the 5 volt reference, so one count is 5000 / 1024 millivolts, which is exactly 625 / 128. Subtract the 500 mV offset, and because the sensor moves 10 mV per degree, every remaining millivolt is one tenth of a degree Celsius. The whole conversion is tenths = reading x 625 / 128 - 500, done in 32-bit integers so it is exact and needs no floating point.
The sketch also averages sixteen readings before converting. One count is about half a degree here, and the last bit of any converter is noise, so a single reading flickers between two values forever. Adding sixteen samples and shifting right by four gives a steady mean with no division.
For Fahrenheit, multiply the Celsius value by 9, divide by 5 and add 32. In tenths of a degree that is f10 = tenths x 9 / 5 + 320, still in whole numbers. Use it for the display line and keep the Celsius value for anything a science class will graph.
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);
int32_t millivolts = ((int32_t)mean * 625) / 128;
return (int16_t)(millivolts - 500); // tenths of a degree C
}
// Tenths of a degree F, if you want the US reading on the display
int16_t tenthsF = (int16_t)((int32_t)readTenths() * 9 / 5 + 320);The display, and the high and low
The LCD is driven in four-bit mode: RS, E and four data lines, six wires in all. RW goes to ground because the sketch never reads the display back, and V0 goes to ground for full contrast. On a real module V0 usually goes to the middle of a 10 k potentiometer so you can adjust the contrast; if your screen shows a row of solid blocks or nothing at all, that pot is the first thing to turn.
The second row shows the lowest and highest readings since power-on. Two variables and two comparisons turn a thermometer into something worth leaving on a windowsill overnight.
One difference from the Arduino IDE: this example uses Mokxi’s own LCD header, mokxi_lcd1602.h, rather than the LiquidCrystal library. The wiring is the same. On a real Uno, include LiquidCrystal.h, create LiquidCrystal lcd(12, 11, 5, 4, 3, 2), call lcd.begin(16, 2), and print the value with lcd.print().
Try it in the editor
Add the Fahrenheit line to loop() and print both scales, one on each row. Drag the slider to 0 °C and check that the display says 32 °F.
Then set the sensor’s offset property to 0 in the properties panel. That turns it into an LM35. Watch the reading jump by 50 degrees, and change the sketch to match.
Finally, drop a multimeter on the canvas and measure the middle leg. At 25 °C it reads 0.750 V, and you can check the sketch’s arithmetic against the meter by hand.
Common mistakes
Forgetting the 500 mV offset, so everything reads 50 °C (90 °F) too hot.
Wiring the sensor backwards. With the flat face toward you and the legs down, the order is supply, output, ground. Reversed on a real bench, a TMP36 gets hot enough to burn a finger.
Doing the math in int with 1023 x 625, which overflows 16 bits on an Uno and gives nonsense. Use a 32-bit long for the multiplication.
Expecting lab accuracy. A real TMP36 is about ±1 °C (±2 °F) at room temperature and ±2 °C over its range. The simulated one returns exactly the temperature you set, which is right for learning the code but is not a calibration.
Questions
How do I convert TMP36 voltage to temperature?
Degrees Celsius = (millivolts - 500) / 10. Degrees Fahrenheit = Celsius x 9 / 5 + 32. On an Uno, millivolts = analogRead value x 5000 / 1024.
Why does my TMP36 read about 50 degrees too high?
The 500 mV offset is missing from the math. The sensor outputs 500 mV at 0 °C, so subtract 500 before dividing by 10.
Can I use a TMP36 with a 3.3 V board?
Yes. It needs 2.7 V or more. The output still follows the same line, and the converter’s full scale is then 3.3 V, so use 3300 instead of 5000 in the math.
Build this for real
Open the editor, change a value and watch the number move with it. Nothing to install, and no account needed.