[SOLVED] Thermistor resistance measured by Arduino differs from multimeter

Hey guys, I'm stuck and need your help.

I'm making a 3D printer module for a CNC Mill, and needed to make a circuit to control the temperature of the hot-end. So I hooked up a heater, a 100K thermistor, an LCD screen, an encoder to set the temperature and a fan. Just like the circuit below:

However, as I was testing the thermistor, I was getting some weird response at higher temperatures (>110°C). So I improvised a test rig, where I would put the thermistor and a cooking thermometer next to each other in a pan, where I would put some oil and heat it up. The graph below shows something close to the results I got:

The temperature Arduino shows me goes hand in hand with the temperature shown by the thermometer up to around 110°C, then it simply can't go above 140°C.

"This thermistor must be faulty", is what I think, so I check its resistance with a multimeter at various points, and they also start to differ from the resistance shown by Arduino at around 110°C. In fact, the measured resistance was exactly the expected value at that temperature.

TL;DR: The thermistor resistance calculated by my code fits the resistance measured with a multimeter up to around 110°C, then it sort of stagnates above 2kOhms, while the multimeter shows that it actually keeps going down.

So definitely there must be something wrong with either my code, or my wiring (I'm using a breadboard and a lot of jumper wires, even though I heard they're not ideal, sorry it's my first time).

EDIT: Here is an approximation of the results for the resistance shown by Arduino and by a multimeter:

(The data in these graphs is not completely accurate, it's just based on what I remember from my test)

Here is my full code, the thermistor's resistance function is at the end. The Steinhart-Hart equation appears to be working just fine.

#include <PID_v1.h>
#include <LiquidCrystal.h>
#include <Encoder.h>

double Setpoint, currentTemp, Output;
const int kP = 3;
const int kI = 1.5;
const int kD = 2;
PID myPID(&currentTemp, &Output, &Setpoint,kP,kI,kD, DIRECT);
LiquidCrystal lcd(12, 11, 7, 6, 5, 4);

//pins
const int buttonPin = 8;
const int encoder1Pin = 2;
const int encoder2Pin = 3;
const int thermistorPin = A0;
const int transistorPin = 10;
const int ledPin = 9;

Encoder myEnc(encoder1Pin, encoder2Pin);

//Variables
long oldPosition = -999;
long newPosition;

boolean buttonPress;
int buttonState = 0;
int thermistorMax = 260;
int thermistorMin = 30;

#define resistorResistence 98500 //series resistor resistance
#define thermistorNominal 100000 //termistor nominal resistance
const int temperatureNominal = 25; //nominal temperature (C)
const int numSamples = 5;
const int betaCoefficient = 4083;
int samples[numSamples];
const int SAMPLETIME = 1000;
int nextUpdate = 0;

void setup() {
  analogReference(EXTERNAL);
  pinMode(transistorPin, OUTPUT);
  pinMode(thermistorPin, INPUT);
  pinMode(buttonPin, INPUT_PULLUP);
  pinMode(encoder1Pin, INPUT_PULLUP);
  pinMode(encoder2Pin, INPUT_PULLUP);
  Setpoint = 95;
  myPID.SetMode(AUTOMATIC);
  myPID.SetSampleTime(SAMPLETIME);

  lcd.begin(16, 2);
  lcd.home();
  lcd.print("Controlador");
  lcd.setCursor(5,1);
  lcd.print("Temperatura");
  delay(2000);
  lcd.clear();

  Serial.begin(9600);

  delay(200);
  lcd.setCursor(0,0);
  lcd.print("SetPoint:");
  lcd.setCursor(0,1);
  lcd.print("Extrusor:");
  delay(200);
  
}

void loop() {
  //routine for detecting one of two encoder button states
  buttonPress = digitalRead(buttonPin);
  if (buttonPress == 0) { 
    if (buttonState == 0) {
      buttonState = 1; 
      while (buttonPress == 0) { 
        buttonPress = digitalRead(buttonPin);
        delay(100);
      }
    }
    else {
      buttonState = 0; 
      while (buttonPress == 0) { 
        buttonPress = digitalRead(buttonPin);
        delay(100);
      }
    }
  }
  newPosition = myEnc.read();
  if (newPosition > oldPosition) {
    if (Setpoint >= thermistorMax) { 
      lcd.setCursor(11,0);
      lcd.print(" MAX ");
        delay(1000);
      Setpoint = thermistorMax;
    }
    else {
      if (buttonState == 0) {
        Setpoint += 5; 
      }
      else {
        Setpoint += 1;
      }
    }
    delay(100);
    oldPosition = myEnc.read();
    lcd.setCursor(11,0);
    if (Setpoint < 99.5) {
      lcd.print(" ");
    }
    lcd.print(Setpoint);
    lcd.setCursor(14,0);
    lcd.print(char(223));
    lcd.println("C");
  }
  else if (newPosition < oldPosition) { 
    if (Setpoint <= thermistorMin) { 
      lcd.setCursor(11,0);
      lcd.print(" MIN ");
        delay(1000);
      Setpoint = thermistorMin;
    }
    else {
      if (buttonState == 0) {
        Setpoint -= 5; 
      }
      else {
        Setpoint -= 1;
      }
    }
    delay(100);
    oldPosition = myEnc.read();
    lcd.setCursor(11,0);
    if (Setpoint < 99.5) {
      lcd.print(" ");
    }
    lcd.print(Setpoint);
    lcd.setCursor(14,0);
    lcd.print(char(223));
    lcd.println("C");
  }
  currentTemp = getThermistor(); 
  lcd.setCursor(11,1);
  if (currentTemp < 99.5) {
    lcd.print(" ");
  }
  lcd.print(round(currentTemp));
  lcd.setCursor(14,1);
  lcd.print(char(223));
  lcd.println("C");
  myPID.Compute();
  analogWrite(transistorPin, Output);
  if (Output > 0) {
    digitalWrite(ledPin, HIGH);
   }
   else {
    digitalWrite(ledPin, LOW);
   }
}

float getThermistor() {    
  uint8_t i;
  float average;
  int ms = millis();
  if (ms >= nextUpdate) { //repeats routine after a certain time period (500 ms)
    for (i=0; i<numSamples; i++) {
      samples[i] = analogRead(thermistorPin);
      delay(10);
    }
      average = 0;
    for (i=0; i<numSamples; i++) {
      average += samples[i];
    }
    average /= numSamples; 

    //Calculate thermistor resistance:
    // [Thermistor Resistance] = [Series Resistor] / (1023/ADC - 1)
    float average = 1023 / average - 1;                         // (1023/ADC - 1) 
    float average = resistorResistence / average;               // 98500 / (1023/ADC - 1)

    //Steinhart-Hart equation:
    // 1/T = 1/To + 1/Beta * ln(R/Ro)
    float steinhart;
    steinhart = average3 / thermistorNominal;             // (R/Ro)
    steinhart = log(steinhart);                           // ln(R/Ro)
    steinhart /= betaCoefficient;                         // 1/Beta * ln(R/Ro)
    steinhart += 1.0 / (temperatureNominal + 273.15);     // 1/To + 1/Beta * ln(R/Ro)
    steinhart = 1.0 / steinhart;                          // inverts
    steinhart -= 273.15;                                  // converts to Celsius

    Serial.print(average);
    Serial.print(" ");
    Serial.print(steinhart);
    Serial.print(" ");
    Serial.println(Output);
   
    nextUpdate = ms + 500;
    
    return steinhart;
  }
}

There are several possible sources of error in your setup, including the fact that the Steinhart-Hart equation is just an approximation for the thermistor behavior.

  1. Have you calibrated your resistor/thermistor combination against known temperatures?

  2. Are you using the best possible coefficients for the Steinhart-Hart approximation, for that particular thermistor/resistor combination?

  3. Are you exceeding the temperature range over which the S-H coefficients are accurate?

To measure temperatures in the higher end you have to lower the value of your series resistor (now 100k) to roughly match that of the thermistor (you mention a resistance of about 2k). That will greatly improve your accuracy measuring the resistance. Just do the math, and see the effect of one ADC point difference at a ratio of 100/2 and 2/2 (or 100/100).

As a rule, when using thermistors, you should choose a series resistor value that matches the value of the thermistor at the temperature of interest. That gives you the best accuracy at that temperature.

Thank you for the response, jremington. Yes, I calibrated the thermistor using the test rig I mentioned, reading 3 temperatures and their resistances and inputting them in this online thermistor calculator (I'll post the link later because I'm on my phone right now) and getting the coefficients.
But the Steinhart-Hart equation is not the problem, the temperatures are matching perfectly the resistance read by Arduino (I know this because the calculator also shows that). The problem is that the resistance is wrong to begin with, compared to the multimeter readings.
To calculate the resistance, the code reads the voltage on the analog pin, so there must be something wrong with this reading (that is if the code is fine, which I think it is).

wvmarle:
To measure temperatures in the higher end you have to lower the value of your series resistor (now 100k) to roughly match that of the thermistor (you mention a resistance of about 2k). That will greatly improve your accuracy measuring the resistance. Just do the math, and see the effect of one ADC point difference at a ratio of 100/2 and 2/2 (or 100/100).

As a rule, when using thermistors, you should choose a series resistor value that matches the value of the thermistor at the temperature of interest. That gives you the best accuracy at that temperature.

Oh I see, that makes sense.
I'll go after a different resistor and come back with the results then. Thank you for your help wvmarle!

I swaped the 100k resistor for a 680 and it worked like a charm! Thank you wvmarle!

Good to hear it worked like that.
And good luck with the rest of your project.