Guide: accurately read an LM35

I have been trying to find a way to read the LM35 as accurately as possible.

I have tried just about every code example I could find on the Internet, nothing seemed to calculate an accurate temperature, so I've combined the best of what I could find and made my own super accurate function.

For a start just about every formula for converting the analog reading to a temperature value divides by 1024, I don't know if this is correct or not but I assume since the ADC returns values between 0 and 1023 that the number should instead be 1023, it seems to yield super accurate numbers anyway, sometimes .01 degree within a DS18B20.

I used example schematic number 7 in the LM35 data sheet, which shows 2 1N914's (I used 1N1418's as this was all I had handy) in series between LM35 ground pin and ground, an 18k resistor between Vout and ground, Arduino analog pin 0 is connected to Vout and analog pin 1 is connected to the ground pin for reading the actual ground voltage that the LM35 see's, this is important as it gives us a reference that is subtracted from the ADC reading on pin 0, this also allows the LM35 to measure negative temperatures, I have taken this to minus 19 so far and it was within .5 of a degree of a DS18B20.

Here's the code, have fun.

Declare:

#define LM35pin 0 // connect LM35 Vout pin to arduino analog pin 0
#define LM35ref 1 // connect 2x 1N1418 diodes between LM35 ground pin and ground
float LM35tempC;

Usage:

LM35tempC = readLM35(LM35pin, true); // true = temp in celcius, false = temp in fahrenheit

Function:

float readLM35(byte LM35Pin, boolean celcius){       
  int analogVal = 0;
  for(int i = 0; i < 10; i++) { // takes 10 samples to make sure we get a good value
    analogVal += (analogRead(LM35pin) – analogRead(LM35ref)); // subtract Vout ADC reading from LM35 ground ADC reading
    delay(10);
  }
  float tempC = (5.0 * analogVal * 10) / 1023;
  if (celcius == true) {
    return tempC; // return temperature in degrees Celcius
  } 
  else {
    return (tempC * 9 / 5) + 32; // return temperature in degrees Fahrenheit
  }
}

Here's a test run of the above function, I can provide the sketch on request.

LM35 25.86
DS18 25.69

LM35 25.90
DS18 25.75

LM35 26.39
DS18 26.19

LM35 26.39
DS18 26.56

LM35 27.03
DS18 26.81

LM35 27.32
DS18 27.12

LM35 27.37
DS18 27.31

LM35 27.47
DS18 27.50

LM35 27.76
DS18 27.62

LM35 27.86
DS18 27.75

LM35 27.86
DS18 27.69

For a start just about every formula for converting the analog reading to a temperature value divides by 1024, I don't know if this is correct or not but I assume since the ADC returns values between 0 and 1023 that the number should instead be 1023

The ADC returns discrete values, from 0 to 1023, which means that there are 1024 possible return values.

Like I said, I didn't know if it was important, but it seems to be more accurate.

As you can see in the comparison with a DS18B20 it is usually within .2-3 of a degree.

This is not a fluke either, I have 10 LM35's and all bar 2 which seem to be faulty read extremely close to the DS18B20, I also tried 3 different DS18B20's and the story is the same.

It's true that with a 10-bit ADC there are 1024 steps numbered 0..1023. But, I think that in your formula you are correct in dividing by 1023, because:
ADC value of 0 = 0% of scale
ADC value of 1023 = 100% of scale.

So for example if you were just trying to read DC voltage from 0 to 5 V, then ADC 0 = 0V and ADC 1023 = 5V. The scaling formula would be:
Volts = ADC/1023.0 * Span + Offset;
Where in this example Span = 5v - 0v = 5; and Offset = 0.

Another example would be if an analog circuit produced 5v for 100 degC, and 0v for -40 degC. Then Span = 100 - -40 = 140; Offset = -40. Thus ADC 0 = -40 DegC and ADC 1024 = 100 degC.

If you divided by 1024, then the maximum ADC value of 1023 would not give you 100%. It would be 99.9023%.

However this is a very small difference which for many applications is negligible, and potentially dividing by a power of 2 (1024) could allow for more efficient implementations if you can also tolerate the inaccuracies of integer math instead of floating-point. But unless you're project is really loading up the memory or number-crunching speed, I really wouldn't worry about it.

Thanks for the good explanation, I knew I was onto something :), I never doubted the formula, just my reason for it, the numbers speak for them selves, it works and works very well!

I can sacrifice speed and memory usage for accuracy!

I intend on using this function to control the temperature of an aquarium, hence why I want it to be as accurate as possible, I want to know that the water is at 24.5 degrees not ~24 degrees.

The DS18B20 only has an accuracy of +/- 0.5C therefore it is pointless using it to see how accurate an LM35 is being read.
So your statement:-

I didn't know if it was important, but it seems to be more accurate.

Has little or no meaning, just because you get more decimal points in the result doesn't mean it is more accurate.
The LM35 only has 1C accuracy according to the data sheet without calibration. The DS18B20 is not accurate enough to calibrate it for your stated requirements.

In any consideration of tture measurement, it pays to distinguish between accuracy and repeatablility.

While a given sensor may read, say, 1.5 degrees low at, say, `5 deg C, if it ALWAYS reads between 1.4995 and 1.5005 low, then it may well be useable for some purposes. This would be a highly "repeatable" sensor.

No when you quote accuracy it is not the same as saying there is a constant offset between the true value and the reading.
The offset between true reading and real value will vary with the actual value. For example it might be 0.25C over at 25C and 0.25C under at 30C.
It will always be these amount out and if you calibrate the sensor it will give you as accurate a reading as the calibration source.
The repeatability of a reading for the same input here is assumed to be perfect. If there is any variation in the reading given the same input this must be factored in as a separate factor. Normally variability of this sort results from other things apart from the sensor, like system noise, measurement reference error (Vref) and the inherent plus or minus one least significant bit you get with any quantisation system like an A/D.

The DS18B20 only has an accuracy of +/- 0.5C therefore it is pointless using it to see how accurate an LM35 is being read.

3 Different DS18B20's (I could compare all 20 that I have if that would help), 1 DS18S20, and 7 different LM35's all being able to repeat the same value within +/- .3 degrees must be pretty "accurate" or "repeatable" which ever way you want to look at it, I highly doubt I could get more accurate without spending hundreds or thousands on lab quality equipment.

I know there are a whole bunch of others, LM34/5/35, TMP35/6/7 etc, but are there any other highly accurate, easily/cheaply obtainable, military grade or lab quality sensors?

I chose the LM35 because they are cheap and easy to obtain, about $1au, I did get an absolute bargain on DS18B20's, $2.40au each, but still the LM35's are less than half that price, and seem to be more than close enough to accurate to suit my needs.

to repeat the same value within +/- .3 degrees must be pretty "accurate"

No, that's "precision".

Wow... Thanks...

This was intended to help others, not be an argument between repeatability/precision/accuracy.

Maybe next time I'll keep what I learn to myself.

Maybe next time I'll keep what I learn to myself.

Please don't.

I'm sorry if this came across wrong, but I'm a software engineer, and pedantry is second nature - it's what pays the mortgage.

Apologies again.

Understood, but we're talking about a $1 3 pin analog integrated circuit being used in a hobby environment :slight_smile:

The whole point was to give a newbie to Arduino's a drop in function that can produce accurate/precise temperature readings from a sensor that cost's a dollar, I don't really care about the merits of using one word over another, the general message is portrayed in the subject line.

There's allot of great info about the Arduino's and interfacing hardware but simple things like this can be abit hard to find good information on, most of it is just copied code on someone's blog that shows how to read the analog pin and produce a number that should be vaguely right, but I wanted to make something more accurate/precise (it still could be better) and decided to share what I learned so others just starting out wouldn't have to spend days trying to figure it out, and don't get me wrong, I find it highly self satisfying to be able to teach this sort of stuff to myself, my mind works better teaching itself than being taught.

Hmm. This isn't really a matter of just word choice ("the merits of using one word over another"). When learning to read sensors and to work with the data you get from them, it's vital to understand the difference between accuracy and precision.

It is not at all unusual for people* to try to do real work with digits in their readings that have nothing whatsoever to do with the true value of what is being measured. When you try to put those digits to work you find that you don't get what you expected to. I imagine that even the folks who do this stuff professionally can think back with a little "cringing" to their first couple of sensor projects when they thought that having three places after the decimal meant they had accurate readings to that extent.

  • Let me clarify: I did this. More than once, in fact. :-[

A very good comment on the meaning - or meaningless of many decimal places. Much like measuring with a micrometer and writing the results as a valid 0.125", while on the other hand measuring with a tape measure and measuring a 1/8" should NEVER be written as 0.125" since that implies a degree of accuarcy that does not exist.

A simple check for actual accuracy of a temperature sensor is to boil in a pot of distilled water at sea level - should see something around 212ºF, then cool sensor, then put in pot of crushed ice/water solution (distilled water and distilled water used to freeze the ice) - should see somewhere around 32ºF at that time.

Not a lab calibration at all, but gives a pretty good idea if the sensor is in the ball park. tap water won't vary much either ::slight_smile:

Ken H>

I didn't say anything about being accurate because it has more decimal places (not in one single post have I mentioned decimal places), the lcd.print and serial.print functions return 2 decimal places when used with a float, for my purposes I'd be happy with 1 decimal place which is lower precision, however this requires extra memory/speed sapping functions.

I'm saying it's accurate because I can repeat the same values across 10 different sensors... If I'm getting the same number's from 3 different types of sensors totalling 10 separate sensors then surely I must be getting an "accurate" temperature reading?

Might want to be careful using the boiling water method of calibration. Don't forget that at high altitudes water will boil at a slightly lower temperature, hence the "High altitude" cooking directions on many packaged foods.

But the question remains, which is needed for this case: accuracy or precision?

Also, since we're educating ourselves on sensors here, don't forget about resolution. Since the ADC converts an analog value into discretely numbered steps, there is a minimum change in the analog value that can be sensed.

Using the normal reference voltage of 5V, each step is 4.89mV. (5/1023) With the LM35's slope of 10mV/DegC, that gives you a resolution of approximately 1/2 DegC (0.489 C, or 0.88 F).

You could get more resolution (keeping in mind the previous discussion about more decimal places is not more accuracy!) by using the ATmega's internal voltage reference (1.1V).

That would give you a resolution of 1.08mV or for the LM35 about 0.1 DegC. It would limit your range to be 0 - 110 DegC -- between frozen fish & boiled fish :wink:

with 1 decimal place which is lower precision

Sorry to nitpick, I know what you're trying to get at, but to summarize the terms for sensors:

Accuracy = how close to the true value the reading is.
Precision = how repeatable a reading is, even if incorrect.
Resolution = the smallest measurable change (ie. decimal places)

If it's 85 Deg and you say it's 32 Deg, you have poor accuracy. But if you says it's 32 Deg EVERY time it is 85 Deg, then you have high precision. :slight_smile:

It would limit your range to be 0 - 110 DegC -- between frozen fish & boiled fish

Oh, I noticed in the original post that you've shifted the "0" of the LM35 by using a pair of diodes on the ground leg. My statement above of the range was for not having the diodes. With two diodes, 0 Deg C would be about 1.2V, so you wouldn't be able to use the 1.1V reference voltage as the top of your scale (ADC=1023) would correspond to -10 DegC.

The diodes are only needed if you need to measure temperatures below 0 DegC. Important if you're measuring outdoor temperature, but probably not necessary for an aquarium, unless it's for penguins.

Also, don't forget that with a change in reference voltage, you'll have to adjust the conversion formula appropriately.

Yeah I don't intend on measuring negative temperatures in an aquarium... poor fish! that was done as it gives me a nice reference point to self calibrate with.

I guess I could have gone about it another way, ie using the 2nd analog pin to determine the actual voltage coming out of the regulator, but this gives me the option to measure temperatures of freezers and fridges without any code changes.