← All projects
Sensors Beginner

LM35 and TMP36: an Analog Thermometer on ESP32 and Arduino Without Libraries

Three legs, 10 mV per degree and no library at all. We look at how the LM35 differs from the TMP36, why on an ESP32 you should read millivolts rather than raw ADC counts, and how averaging removes jumpy readings.

Difficulty
Beginner
Time
30 min
Category
Sensors
Updated

About the project

The LM35 and the TMP36 are the simplest temperature sensors there are: a chip in a TO-92 package, like a transistor, outputs a voltage proportional to temperature. No bus, no address, no library — just analogRead(). That makes them a good way to learn how a microcontroller ADC behaves and where its errors come from.

What you need

  • ESP32 DevKit (or an Arduino Uno / Nano)
  • An LM35DZ or TMP36 sensor
  • A few wires; for a long cable, a 0.1 µF capacitor between OUT and GND

LM35 or TMP36

LM35 TMP36
Slope 10 mV/°C 10 mV/°C
0 °C 0 mV 500 mV
Supply 4–30 V 2.7–5.5 V
Range on a single supply +2…+150 °C −40…+125 °C
Formula T = U / 10 T = (U − 500) / 10

The main LM35 trap is its 4 V minimum supply. It is not specified for 3.3 V, so on an ESP32 it goes to the 5V pin: the output never exceeds 1.5 V anyway, which is safe for an ESP32 input. The second catch is that on a single supply the LM35 cannot output a negative voltage, so it never shows frost. For outdoors use a TMP36 or a DS18B20.

Wiring

Holding the sensor with the flat side towards you, the legs from left to right are +Vs, Vout, GND.

Sensor ESP32 Arduino Uno
+Vs 5V (LM35) or 3V3 (TMP36) 5V
Vout GPIO34 (ADC1) A0
GND GND GND

On an ESP32 use the ADC1 pins (GPIO32–39): ADC2 does not work while Wi-Fi is on.

Why millivolts rather than analogRead()

The ESP32 ADC is non-linear: near zero and near the top it loses tens of millivolts, and the gain differs from chip to chip. analogRead() * 3.3 / 4095 easily gives 2–3 °C of error. analogReadMilliVolts() applies the factory calibration stored in eFuse and returns millivolts — for an LM35 that is tenths of a degree straight away.

On an Arduino Uno the ADC is linear but coarse: 10 bits against 5 V is 4.9 mV per step, about 0.5 °C. You can do better by switching the reference to the internal 1.1 V (analogReference(INTERNAL)): the step becomes 0.1 °C and the maximum 110 °C.

Code

// LM35 / TMP36 on the ESP32: average the readings and convert millivolts to °C
const int SENSOR_PIN = 34;     // ADC1
const bool IS_TMP36 = false;   // true for a TMP36 (0 °C = 500 mV)

float readCelsius() {
  uint32_t sum = 0;
  for (int i = 0; i < 16; i++) {
    sum += analogReadMilliVolts(SENSOR_PIN);   // millivolts with the factory calibration
    delay(2);
  }
  float mv = sum / 16.0;
  return IS_TMP36 ? (mv - 500) / 10.0 : mv / 10.0;
}

void setup() {
  Serial.begin(115200);
}

void loop() {
  float t = readCelsius();
  Serial.printf("Temperature: %.1f °C\n", t);
  delay(1000);
}

Sixteen readings 2 ms apart average out ADC noise and Wi-Fi interference. In the simulator change the temperature in the sensor properties and switch the model to TMP36 — then remember to change IS_TMP36 too.

Common problems

  • It reads 5–10 °C too high. The sensor heats itself or picks up heat from the board. Move it away from the regulator on a wire.
  • Readings jump on a long cable. The LM35 dislikes cable capacitance: add a 2 kΩ resistor in series with the output, or a 0.1 µF capacitor to GND at the ADC input.
  • A 3.3 V supply. From 3.3 V the LM35 reads wrong or gets stuck — the simulator warns you about it.
  • 0.5 °C steps on an Arduino. That is the 10-bit ADC; use analogReference(INTERNAL) or a digital sensor.