TMP36 reading low

I have TMP36 and the readings are about 5-6 degrees Fahrenheit too low.
It should be about 68F and it is reading 62F/63F
I have put a 47Kohm resistor from TMP36 VOUT to GND as suggested by Simon Monk in his blog Dr. Monk's DIY Electronics Blog: Accurate and Reliable Readings from a TMP36

I am also using 3.3V instead of the USB 5V as suggested by Using a Temp Sensor | TMP36 Temperature Sensor | Adafruit Learning System

Any ideas other than chucking the TMP36?

Whats your ADC reading? Should be around 217 with AREF of 3.3V at 20 C (68 F).

It is consistent at 224.

    sensor = analogRead(A0);
    voltage = sensor * (3300 / 1024);

    Serial.println(sensor);

and the conversion is

        celsius = (voltage - 500) / 10;
        
        fahrenheit = (1.8 * celsius) + 32.0;  //convert Celsius to Fahrenheit

Check the voltage at your AREF pin and set the 3300 in the formula to match, you can tweak it a little 'til your reading matches a known accurate thermometer.

Try this test sketch, it uses a rolling average of the last 8 readings and reads within 0.4 C of a Fluke 52 with type K thermocouple from 10 C to 35 C.
I also put a 100nF ceramic cap from AREF pin to GND, also use INTERNAL reference (1.1 volts).

int adcnt;
float adcv;
float tempC, tempF;
int adavg[8];

void setup()
{
  Serial.begin(9600);
  analogReference(INTERNAL);
  for(int i = 0;i < 8;i++)
    adavg[i] = analogRead(0);
}

void loop()
{
  for(int j = 0;j < 8;j++)
  {
    adcnt = 0;
    analogRead(0);
    for(int i = 0;i < 16;i++){
      adcnt += analogRead(0);
      delay(2);
    }  
    adavg[j] = adcnt / 16;
    Serial.print(adavg[j]); Serial.print("  ");
    adcnt = 0;
    for(int k = 0;k < 8;k++)
      adcnt += adavg[k];
    adcnt /= 8;  
    adcv = adcnt * 1.1 / 1023 - 0.5;
    tempC = adcv  * 100; tempF = tempC * 9 / 5 + 32; 
    
    Serial.print(adcv,3); Serial.print("  ");
    Serial.print(tempC,1); Serial.print("  ");
    Serial.println(tempF,1);
    delay(1000);
  }  
}

I am not sure about the INTERNAL reference 1.1 volts. Where will I get that on the Arduino Uno? I must not be understanding something.

In setup(), (line 10 in the sketch).

analogReference(INTERNAL);

Great.
Thank you.
I will put in the capacitor tomoroww.

Do you actually mean a capacitor on AREF? Or do you mean a capacitor on Vout of the TMP36?

Thermometers have to be calibrated.
Change the Aref voltage value (in this case 3300) in the maths line untill you have the right temp in the serial monitor.

DON't set Aref to INTERNAL if you have connected Aref to 3.3volt.
You will damage the micro if you do. See the warning on the IDE's Reference > analogReference() page.
I don't know why Adafruit is recommending this.
It would be better/safer to use a resistor between 3.3volt and Aref.
If you use a 10k resistor, Aref will drop to 32/42 * ~3.3 = ~2.5volt
Even higher resolution, and a protected Aref pin, and still the ability to measure to 150C (-50 to 150C).
Now you have to change that "3300" value to ~~2514 (could be upto ~2550) to calibrate.
Leo..

I have AREF set to INTERNAL and nothing is connected to AREF.

Why don't you like the idea of setting AREF to INTERNAL and use the built-in 1.1V ?

Some of your calculations are being done as integer math, I think.

Your variables need to be declared as floats and your numbers need to be made floats also.

For example: 1024 is an integer, 1024.0 is a float.

Your data yields a temperature of about 62 degrees with integer math and about 72 degrees using floats.

ieee488:
I am not sure about the INTERNAL reference 1.1 volts.

You have "almost" right -> see (1) for explanation and (2) for solution.

ieee488:
Why don't you like the idea of setting AREF to INTERNAL and use the built-in 1.1V ?

(1) Internal reference is given for : Vref = 1,1 V +/-10% , see Atmel datasheet !

(2) For a given batch Internal reference is stable and contant.
When Internal reference is set , you can measure exact Vref value on Aref pin.

The solution I use for each Atmega :
A) I measure Vref with a digital voltmeter
B) I save this value in the EEPROM.

By doing so, program is independent of the micro.

tf68:
Some of your calculations are being done as integer math, I think.

Your variables need to be declared as floats and your numbers need to be made floats also.

For example: 1024 is an integer, 1024.0 is a float.

Your data yields a temperature of about 62 degrees with integer math and about 72 degrees using floats.

I noticed that when I added more Serial.println in the sketch after reading outsider's post.
The way I have it initially is how it is in the book Arduino Workshop. :confused:

68tjs:
You have "almost" right -> see (1) for explanation and (2) for solution.

(1) Internal reference is given for : Vref = 1,1 V +/-10% , see Atmel datasheet !

(2) For a given batch Internal reference is stable and contant.
When Internal reference is set , you can measure exact Vref value on Aref pin.

The solution I use for each Atmega :
A) I measure Vref with a digital voltmeter
B) I save this value in the EEPROM.

By doing so, program is independent of the micro.

Thank you for the explanation.

For a simple temperature measurement sketch this has turned out to be more complicated than I thought it would be. :o

ieee488:
For a simple temperature measurement sketch this has turned out to be more complicated than I thought it would be. :o

Not that hard once you understand Aref.

Default Aref (if you don't do anything in code) is the board's supply.
If you use an Uno or Mega, that will be ~5volt.
Not so good to use for accurate measurements, because it's not that stable (dips from flashing LEDs, relays, motors, etc.).

Then there is an internally generated ~1.1volt Aref that you can call in setup.
analogReference(INTERNAL);
Not accurate (could be 1 to 1.2volt), but it is very stable.
A Mega also has a ~2.56volt Aref.

You can also provide your own Aref.
Connect a stable/accurate voltage to the Aref pin, and use analogReference(EXTERNAL); in setup.

There is a danger of connecting an external voltage to the Aref pin (3.3volt in the Adafruit link).
You have to make sure Aref is set to EXTERNAL.
When it's on default (forgot to change it in code), or you have set it to INTERNAL, the externally voltage will fight the 5volt or 1.1volt that is on the Aref pin.
Using a resistor eliminates that danger at the cost (or gain) of a slightly lower Aref.

See analogReference() - Arduino Reference

The TMP36 outputs 0-2volt with temps between -50C and +150C. This is a 200C span.

If you use default (5volt) Aref, you will have 2/5 * 1024 = ~410 A/D values to work with.
410 / 200 = About two values per degreeC. Not really enough for a temp readout to one decimal place.

If you use 1.1volt Aref, you can only measure 0-1.1volt. That is -50C to ~+60C. A 110C span.
But now you have 1024 values across that span, so 9.3values per degreeC. Ok for one decimal place.
Limitation is now ~+60C, but that shouldn't be a problem if only indoor/outdoor temps are measured.

If you make your own Aref, e.g. by connecting the 3.3volt pin to Aref (with a resistor), you can set the upper limit of your temp sensor as you please. At the cost of less A/D values per degree C.

Hope this explains it a bit.
Leo..

Sorry but in ICs, resistors are +/-20%. or +/- 30 %.
It works because they are all at + 5% or all at -25 %. depending of the batch.

It is for that reason that internal 1.1V reference is given @ +/- 10 %.
So you don't know exact value of internal 32 k.

Your idea is good but you have to calibrate with a known voltage.