algorithm Arduino electronics hardware

Reading LM34, LM35, LM335 (LM3x) Temperature Sensors Accurately

LM35 ImageThe LM3x series of sensors are precision, easily-calibrated, integrated circuit temperature sensors. These are ideal as a beginner sensor, only to disappoint when code is copied from somewhere, run on the MCU and the temperature readings seem to be wildly varying and incorrect. Why is this happening and what can be done about it? Read on.

The LM34, LM35 and LM335 all work in a similar fashion. The difference between them is that they provide proportional output calibrated to different units of measure:

  • LM34 provides output in degrees Farenheit, between −50°F and 300°F (-45.5°C to 149°C).
  • LM35 provides output in degrees Centigrade, between −55°C and 150°C.
  • LM335 provides output in degrees Kelvin, between 218°K and 423°K (−55°C and 150°C).

In this article I’ll focus on the LM335 as the ‘official’ measure of temperature is °K, but the same principles apply to all three types.

Sensor output

The sensor has 3 pins and is easily interfaced to the MCU. The datasheet (LM335_Temperature_Sensor) is always a good starting point for understanding any device. For the purposes of this analysis I assume that the sensor is set up as a basic, uncalibrated sensor – the simplest possible 3 pin MCU connection (V+, Gnd, Out).

Highlights from the datasheet relevant to this analysis, captured in the figure below:

  • Sensor output voltage is linearly proportional to the temperature measurement at +10mV/°K.
  • At 0°K the output voltage is 0V and the sensor is calibrated to 2.982V at 298.15°K (25°C). This gives us 2 known points on a straight line.


For a linear relationship T = sV + b, where the T axis intercept b = 0 and the slope of the line s =  1°K/10mV and so, including the units to make sure we are consistent,


Which, when simplified provides the simple relationship


We can use the given calibrated value to provide a check: 2.982 * 100 = 298.2°K = 25.05°C, as published.

So what can go wrong?

All this seems straightforward, so how can we get inaccurate readings? Using the MCU, we don’t read voltage directly. Rather, the Arduino libraries return a 10 bit number (0 to 1023) derived by the DAC (Digital to Analog Converter) that represents the proportion of the MCU DAC reference voltage. By default this is usually the supply voltage, say 5V.

This is then converted to the actual voltage (in millivolts) by calculating

V = (DAC_output / 1023) * 5000

This calculation and the assumption about the reference voltage are the major cause of inaccurate reading from these sensors.

The reference voltage is hardly ever exactly 5V. Common reasons for the variation are that USB power supplies can vary ‘around’ 5V or that devices such as motors and servos can temporarily disrupt the supply voltage when they run. In the first case there is a consistent systematic error, in the second the sensor will seem to go haywire and give inconsistent consecutive readings.

LM35_Incorrect_VoltageThe effect of variations in voltage is  illustrated using the figure at left. For the exact supply voltage V1, we can read the temperature T1. For the actual (lower) supply voltage V2, the DAC count proportionally still provides the reading V2 for T1 but, because we are assuming the voltage is V1, then the apparent temperature is T2.

A calculated example using the reference at 25°C demonstrates this effect. From the datasheet, V=2.982V is read for 25°C. If the reference voltage is 5V, then the DAC reading is (2.982/5)•1023 = 610. For a reference voltage of 4.8V, the count is (2.982/5)•1023 = 621. If we are assuming 5V but actually supply 4.8V, then the count returned (621) will be converted back to (621/1023)•5 = 3.04V. Instead of reading 298.2 °K (25°C) we ‘seem’ to be reading 304°K (31°C), a significant error which is much higher than the actual sensor error.

Gaining accuracy

Clearly the key to accuracy with these sensors is knowing the exact value of the reference voltage for use in the temperature calculation. This can be done in a few ways:

  1. Ensure that the power supply remains stable. This is not simple and may only work in a limited number of cases, as the voltage is affected by the environmental conditions whilst the code remains invariant.
  2. Change the DAC reference voltage. This is possible by specifying  analogReference(INTERNAL) in the code. This changes the DAC reference to an accurate known voltage, internally generated by the MCU. The function documentation for analogReference() indicates that the reference voltage will depend on the hardware used. Using this method, signals larger than the reference voltage (eg, greater than 1.1 volts on the ATmega168 or ATmega328) will not return the correct DAC count.
  3. Use the supply voltage for the DAC reference, but measure the supply voltage accurately against the internal reference voltage. This allows each DAC reading to be assessed against the actual supply voltage. The code is hardware dependent, as it uses low level register access. An example for the ATmega168 or ATmega328 is shown below.
int readVcc()
// Calculate current Vcc in mV from the INTERNAL reference voltage
#if defined(__AVR_ATMega168__) || defined(__AVR_ATMega328__)  
  long result = 5000;

  // Read 1.1V reference against AVcc  
  ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
  delay(2); // Wait for Vref to settle
  ADCSRA |= _BV(ADSC); // Convert
  while (bit_is_set(ADCSRA,ADSC));  
  result = ADCL;  
  result |= ADCH<<8;  
  result = 1126400L / result; // Back-calculate AVcc in mV    
  return(5000); // can't handle, assume nominal V

In conclusion, these sensors are accurate but the supply voltage must also be know with accuracy. Once this is understood, a number of possible hardware and software solutions can be implemented to improve the consistency of temperature readings.

2 replies on “Reading LM34, LM35, LM335 (LM3x) Temperature Sensors Accurately”

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s