The ADC seems to be unstable.

Hello

I'm trying to create a thermometer with a thermistor. I've attached the analog input 0 to my voltage divider with a thermistor.

The temperature is variating from 16 to 25 degreeds celsius within 30 seconds (with stable 20 degreeds in the room). I've also tried to print the raw input (without deviding on 1024), and when I did that, the number was variating between something like 200 and 600.

I've measured the voltage from my multimeter, and when I did that, the voltage was stable. Any clue why the arduino ADC makes the results so unstable?

The thermistor is a NTC100K, and the resistor is 10K.

By the way: it's the ArduinoBT card.

Here is my code:

#include <math.h>
/*

(Ground) ---- (10k-Resister) -------|------- (Thermistor) ---- (+5v)
|
Analog Pin 0

============================================================
*/

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

void loop()
{

//Making an array for the average of the last 30 seconds.
//Serial.println(analogRead(A0));
double sensorValue = analogRead(A0);
double voltage = 5.17sensorValue/1024; //5.17 is the voltage
double rT=(5.17-voltage)/(voltage/10000); //10000 is the resistor
double temp=1/((-0.00144158)+(0.000500509)
(log(rT))+(-0.000000619769)(log(rT))(log(rT))*(log(rT))); //Steinhart-hard formula with A, B and C
temp =temp-273.15;
Serial.println(temp, DEC);
delay(1000);
}

What pull up resistor value have you used on the analogue input?

Thanks for fast reply.

I'm not 100% sure what resistor you are refering to, but as far as I understood from wikipedia, you are refering to the Thermistor? When it's 25 degreeds in the room, the thermistor has a value of 100000 ohm. If it's 20 degreeds in the room, the thermistor is circa 115000 ohm.

Did that answered your question?

(Ground) ---- (10k-Resister) -------|------- (Thermistor - 100k at 25 degreeds celsius) ---- (+5v)
|
Analog Pin 0

Well indirectly, your answer should have been
"I am using a 10K pull down resistor"

That is sort of OK but not what I would have done. Anyway as you are finding that the reading is some what random you need to introduce a 0.1uF capacitor across the 10K resistor to smooth things out.

Thanks, I will try that. When you say "Across", you mean in parallell, right? And why exactly a 0.1 uF cap.? How do you calculate that value?

Would it be better with a 100K pulldown? And what is the reason why the multimeter gives me a stable voltage (when I messure the voltage from the point between the thermistor and the resistor, to ground), while the result I read through the arduino is so "random"?

When you say "Across", you mean in parallell

Yes

And why exactly a 0.1 uF cap

It is a standard sort of value.

How do you calculate that value?

If you must it give you a time constant T of RC. So work out what time constant you want (the break point of the filter) and the resistance you have, then the capacitor is C = T/R but it is super none critical.

Would it be better with a 100K pulldown?

No that will make matters worse, 10K is the optimal value for the A/D.

And what is the reason why the multimeter gives me a stable voltage

Multimeters do not have a very rapid response your arduino does. The meter is doing the smoothing for you.

Because the ADC on the Arduino can respond to voltage changes faster than your multimeter. You are probably seeing some noise being picked up. The capacitor will smooth it out for you. The bigger the capacitor the slower the response will be.

Thank you, guys! I will test this tomorrow, and give you feedback :slight_smile:

Edit: some of my classmates are talking about that I need to take the internal resistor in the arduino in considuration. They mean that this internal resistor will make the resault of the temperature wrong. Is that correct? Something about measurement error or something.

Is that correct?

No, because you never enable the internal resistor. (you should not do this because it is not a very stable or accurate value)

r2d290:
I've also tried to print the raw input (without deviding on 1024), and when I did that, the number was variating between something like 200 and 600.

Something is very wrong. The voltage on the pin should be around 0.4v at 20C and 0.45v at 25C, so the raw readings at these temperatures should be around 82 and 93 respectively. It looks to me that you are reading the wrong pin. Have you tried calling analogRead(0) instead of analogRead(A0) ?

r2d290:
Would it be better with a 100K pulldown?

With a 10K pulldown, your resolution is around 0.5C. With a 100k pulldown, it would be 0.14C. You'd be running the ADC with an effective source resistance of 50K, which is above the 10K recommended on the data sheet. In practice, the ADC works quite well with higher source resistances provided you increase the sample time (e.g. by taking 2 readings and discarding the first). Alternatively, put a capacitor between the pin and ground (which has already been suggested). The datasheet gives the ADC input resistance as 100M typical, which means that if you leave the ADC permanently switched to that pin, the typical error introduced by using 50K source resistance will only be about 0.5LSB.

Where did you get coefficients in your formula:

double temp=1/((-0.00144158)+(0.000500509)(log(rT))+(-0.000000619769)(log(rT))(log(rT))(log(rT)));

They are different from others sources:
http://arduino.cc/playground/ComponentLib/Thermistor4
and Thermistor - Wikipedia

A is close, B almost twice bigger, and C (some sources name it D) ~6 times bigger ?

@dc42: Sorry, I think I lost my mind for a minute while I wrote that post. I don't remember what the raw-value was at this woltage, but 80-90 does not sounds incorrect. I will test the raw input again tomorrow. But what ever what the raw input was, the important point is that the raw input were variating also. And I think the raw input was variating even when I tried to connect it to a power supply.
Anyways: I know I'm reading from the correct pin. When the thermistor is in room temperature, it gives me around 20 degreeds, and if I holds my fingers around it, it gives me around 32 degreeds. And if I dip it into cold water, I get around 5 degreeds.

I did not understand what you ment with the 50k resistance (where did you got this number from?)
What does LSB stands for? Least segnificant bit? Could you please explain the context of that last paragraph a bit slower? I did not understood it all.

@Magican:

I did three measurements: 277,65 kelvin, 292,65 kelvin and 323,15 kelvin. That gave me respectively 265000 ohm, 118300 ohm and 36100 ohm.

Used this formula three times:
1/ 277,65_1=A+B*(ln(265000))+C(ln(265000))^3
1/292,65=A+B*(ln(118300))+C(ln(118300))^3
1/323,15=A+B*(ln(36100))+C(ln(36100 ))^3

That gave me A= -0,00144158 B=0,000500509 and C=-6,19769*10^(-7)

Are these calculations incorrect?

Yes, there is an error somewhere in your calculation , coefficients are not correct.
I create a LibreOffice calculus sheet, that helping to track down math formula fast.
Results show up in columns:
D - calculated on your original formula, completely off road, T goes up 10.000 C;
E - based on coefficient from wiki:

F - also from wiki:
Steinhart–Hart equation - Wikipedia linked document:
http://www.cornerstonesensors.com/reports/ABC%20Coefficients%20for%20Steinhart-Hart%20Equation.pdf

E and F in good agreement, but they offset around 30C each other, I suggest, due different NTC resistance or type were used to get data.
They also report offset to expected measurements ( F up around 50 C , E - up 80 C ).

So, I try to adjust A coefficient , in order to fix offset in column F, and created G.
I played with data in the raw 24, setting Input A0 with a value, that would correspond to rT=100.000
Than, as we know rT 100.000 for temp. 25 C, I adjust A to get 25 as result in G24 cell.
Probably, it's not absolutely accurate, but you can use the same technics to "calibrate" your sensor.

NTC100.xls (23 KB)

r2d290:
I did not understand what you ment with the 50k resistance (where did you got this number from?)
What does LSB stands for? Least segnificant bit? Could you please explain the context of that last paragraph a bit slower? I did not understood it all.

The pulldown resistor to ground and the thermistor to +5v may be considered to be in parallel from the point of view of the source resistance seen by the pin, so if both are about 100K, the source resistance seen by the pin is about 50K.

LSB is indeed least significant bit. When you connect the ADC with 100M input resistance to a voltage source with 50K resistance, the 50K and the 100M form a voltage divider. The 0.5LSB error comes from the calculation that 50k/100M is 1 part in 2000, and 1 LSB is 1 part in 1024. In fact the potential error is only this high if the input is near 0v or +5v.

Another way of looking at it is that the ADC input looks like a 100M resistor connected to somewhere between 0v and +5v. So the error it introduces is equivalent to connecting a 100M resistor in parallel with the thermistor, or a 100M resistor in parallel with the pulldown resistor, or somewhere in between.

@dc42: Thank you! I think I understand this now. Am I correct that you are arguing why I should NOT take the internal resistor into considuration, because the effect of that internal 100 megaohm resistor would be neglected?

r2d290:
@dc42: Thank you! I think I understand this now. Am I correct that you are arguing why I should NOT take the internal resistor into considuration, because the effect of that internal 100 megaohm resistor would be neglected?

More or less. I'm saying that the effect of having 50k source resistance on the reading is negligible in the typical case, provided you allow for the ADC input needing an increased sample time. The effect might be more serious in the worst case, but unfortunately AVR ony publishes a typical value for the ADC input resistance and not a minimum value, so we don't know what the worst case is.

Okay, I tried with the capasitor, but couldn't see any difference. So, I tried to simply connect the analog input directly to a stable 0.4 (ish) powersuply.
I used this simple code:

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

void loop() 
{
  double sensorValue = analogRead(A0);
  Serial.println(sensorValue);
  delay(1000);
}

That gave me the following raw output:

72.00
72.00
74.00
76.00
72.00
72.00
104.00
74.00
74.00
72.00
76.00
72.00
68.00
74.00
72.00
72.00
74.00
73.00
76.00
104.00
76.00
77.00
95.00
74.00
79.00
76.00
74.00
72.00
95.00
77.00
74.00
88.00
72.00

So, as far as I can tell, the problem must be a place inside the arduino, right? And this is not how it's supposed to be?

If your 0.4v supply really is stable, then it looks like the power supply to your Arduino is not (or you have a dodgy connection somewhere). How are you powering the Arduino?

Thanks again for the support.

The ArduinoBT does not have an included power supply. Ther's a white +/- input with screws. I can connect any powersupply to this input, and I have tried three different, with the same resault.

I have connected the +5V on the powersupply to the + on the arduino brick. Ground at the powwersupply is connected to GND on the Arduino.

A 0,4V powersupply has the + connected to Analog in (0) on the arduino, and the gnd on the 0,4V powersupply is connected to the GND on the 5V powersupply.

I've also tried to use a "trainer" which has both 0,4V and 5V output (with common ground), so I don't think it can be a grounding-problem.

Connect the ground of the 0.4V supply to the gnd on the Arduino board, not on the 5V supply - otherwise you are seeing IR voltages from the +5V supply superimposed on the analog reading.