100K NTC Thermistor on 3D Printer Heatbed Good Until ~80degC

I have been bouncing my head on this for a few days now. Everything seems coded how I would like it as far as the temperature control formulas. And the whole setup is accurate to 1% at the moment. Almost as soon as my actual temperature reaches 80degC + I get a “nan” value. Does anyone have any ideas why this could be happening? My appologies for the lack of comments, I was going to go back and put them in after I had the code where I wanted it.

#include <math.h>
#include <LiquidCrystal.h>
#include <AnalogSmooth.h>

const int rs = 8, en = 7, d4 = 6, d5 = 4, d6 = 5, d7 = 2;
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);

AnalogSmooth as100 = AnalogSmooth(100);

const int T0numRead = 36;
int T0read[T0numRead];
int T0index = 0;
int T0total = 0;
int T0avg = 0;

int T0sensor = A0;
const int T0relay = 9;
const int buzzer = 3;
int T0buzzer;
int T0target;
int entermem;
float T0, T0K, T0Smooth, _a, _b, _c;
const float _T0R1 = 97800;
//const float _T0R1 = 4620;
const float _T0NT = 298.15;
const float _B = 3950;
const float _V0sup = 4.096;
const float _V0ref = 4.096;
const float _T0R2 = 100000;

unsigned long TIM1s_pre = 0;
const long TIM1s = 1000;
unsigned long TIM150ms_pre = 0;
const long TIM150ms = 150;
unsigned long TIM10ms_pre = 0;
const long TIM10ms = 10;
unsigned long TIM5ms_pre = 0;
const long TIM5ms = 5;
unsigned long TIM30s_pre = 0;
const long TIM30s = 30000;
unsigned long TIM1s2_pre = 0;
const long TIM1s2 = 1000;

void setup() {

  pinMode (T0relay, OUTPUT);
  pinMode (buzzer, OUTPUT);
  pinMode (11, INPUT);
  pinMode (12, INPUT);
  pinMode (13, INPUT);
  
  lcd.begin(16, 2);

  lcd.print("  TEMP CONTROL");
  delay(3000);
  lcd.clear();

  analogReference(EXTERNAL);

  for (int T0curread = 0; T0curread < T0numRead; T0curread++) {
    T0read[T0curread] = 0;
  }

  T0target == 0;
  T0buzzer == 0;
  
}

void loop() {

  

  unsigned long TIM10ms_cur = millis();
  if (TIM10ms_cur - TIM10ms_pre >= TIM10ms) {
    TIM10ms_pre = TIM10ms_cur;
    T0Smooth = as100.analogReadSmooth(T0sensor);
  }

  unsigned long TIM5ms_cur = millis();
  if (TIM5ms_cur - TIM5ms_pre >= TIM5ms) {
    TIM5ms_pre = TIM5ms_cur;
    T0total = T0total - T0read[T0index];
    T0read[T0index] = T0Smooth;
    T0total = T0total + T0read[T0index];
    T0index = T0index + 1;
    if (T0index >= T0numRead){
      T0index = 0;
    }
    T0avg = T0total / T0numRead;
  }

  float V0out = _V0ref  * (T0avg / 1023.0);
  float T0R2 = (V0out * _T0R1) / (_V0sup - V0out);
  T0K = 1.0 / ((1 / _T0NT) - ((1 / _B) * (log(T0R2 / _T0R2))));
  T0 = T0K - 273.15;

  int enter = digitalRead(11);
  int up = digitalRead(13);
  int down = digitalRead(12);
  
  if (enter == HIGH) {
    unsigned long TIM1s2_cur = millis();
    if (TIM1s2_cur - TIM1s2_pre >= TIM1s2) {
      TIM1s2_pre = TIM1s2_cur;
      entermem = 1;
      }
  } 
  if (entermem >= 1) {
    unsigned long TIM150ms_cur = millis();
    if (up == HIGH && TIM150ms_cur - TIM150ms_pre >= TIM150ms) {
      TIM150ms_pre = TIM150ms_cur;
      ++T0target;
      }
    if (down == HIGH && TIM150ms_cur - TIM150ms_pre >= TIM150ms) {
      TIM150ms_pre = TIM150ms_cur;
      --T0target;
      }
    } else if (entermem >= 1 && enter == HIGH) {
        T0target = T0target;
        entermem = 0;
        } 
  
  if(T0target >= 30 || T0 <= T0target - 0.5) {
    digitalWrite(T0relay, HIGH);
  }

  if(T0target < 30 || T0 >= T0target + 0.5 || T0 >= 120) {
    digitalWrite(T0relay, LOW);
  }
  
  lcd.setCursor(0, 0);
  lcd.print("T0TARGET:");
  lcd.setCursor(10, 0);
  lcd.print(T0target);
  lcd.setCursor(0, 1);
  lcd.print("T0ACTUAL:");
  lcd.setCursor(10, 1);
  
  unsigned long TIM1s_cur = millis();
  if (TIM1s_cur - TIM1s_pre >= TIM1s) {
    TIM1s_pre = TIM1s_cur;
    lcd.print(T0, 2);
  }

  if (T0 >= T0target - 0.5 && T0 <= T0target + 0.5 && T0buzzer == 0) {
    tone(buzzer, 1000, 500);
    ++T0buzzer;
  }

  if (T0 < T0target - 5.0 && T0 < T0target + 5.0 && T0buzzer == 1) {
    unsigned long TIM30s_cur = millis();
    if (TIM30s_cur - TIM30s_pre >= TIM30s) {
    TIM30s_pre = TIM30s_cur;
    T0buzzer = 0;
    }
  }

}

ADR440_441_443_444_445-878982.pdf (556 KB)

What value pull up resistor did you use with the thermistor. Should be about the same value as the thermistor at the temp of interrest. So NOT 100k for a 100k thermistor if you use it for a hotbed. Leo..

This is also a lot of code to look through not knowing where to look. So please write a minimal sketch that demonstrates the problem: in this case just read the probe, calculate the temperature, and print it to Serial monitor.

That at least tells you whether the probe works as expected.

I noticed references to a 4.096V reference voltage in your code - how is it all wired up? You use some external precision reference for this?

Good catch. 4.096volt assumes an external A/D, and most of them can't be used with a (ratiometric) thermistor.

Need to see a device list and diagram. Leo..

If that's also used as supply for the NTC (precision reference + buffer would do quite well) it should give a good job. Myself I'd still wire an NTC using Vcc as supply, and a regular analog input. Less components for the same result.

And another thing, looking back at the code: using the B-coefficient equation and "accurate to 1%" also doesn't normally go well together, except for a very small range around the nominal temperature/resistance (not necessarily the 25 degree values - you may measure the actual resistance of your NTC at whatever typical working temperature you have and use that for nominal values, will give much more accurate results).

wvmarle: If that's also used as supply for the NTC (precision reference + buffer would do quite well) it should give a good job.

OP might have used the ADS1115. That chip doesn't have Aref exposed, so basically not suitable for a thermistor. Leo..

Wawa:
What value pull up resistor did you use with the thermistor.
Should be about the same value as the thermistor at the temp of interrest.
So NOT 100k for a 100k thermistor if you use it for a hotbed.
Leo…

Currently I have a 100k(97k8 actual) resistor as the pull up resistor.

wvmarle:
This is also a lot of code to look through not knowing where to look. So please write a minimal sketch that demonstrates the problem: in this case just read the probe, calculate the temperature, and print it to Serial monitor.

That at least tells you whether the probe works as expected.

I noticed references to a 4.096V reference voltage in your code - how is it all wired up? You use some external precision reference for this?

Wawa:
Good catch.
4.096volt assumes an external A/D, and most of them can’t be used with a (ratiometric) thermistor.

Need to see a device list and diagram.
Leo…

I am using an ADR444BRZ currently for AREF and to power the thermistor. I will draw up to show the thermistor sketch and post that when complete.

I am rather pleased with this set up right now it is more accurate than I expected <80degC. As soon as it hits 80 I get a “nan” value for my actual temp reading. The bed continues to heat after this point since there is no value to shut off the relay. I am shooting for ~100degC for ABS that I will probably run fairly often. It was at 95degC when I shut it off since I had no control to stop it once it got to that point. I am using an infrared thermometer to compare my readings to physical temp.

wvmarle:
If that’s also used as supply for the NTC (precision reference + buffer would do quite well) it should give a good job. Myself I’d still wire an NTC using Vcc as supply, and a regular analog input. Less components for the same result.

And another thing, looking back at the code: using the B-coefficient equation and “accurate to 1%” also doesn’t normally go well together, except for a very small range around the nominal temperature/resistance (not necessarily the 25 degree values - you may measure the actual resistance of your NTC at whatever typical working temperature you have and use that for nominal values, will give much more accurate results).

You have a point. When I originally wrote this program I did not have access to an accurate thermometer that could handle this. I may be able to use the A,B,C steinhart-hart equation once I get some resistance readings.

I uploaded a quick schematic.

A 100k thermistor is about 10k@82C. So use a 10k pull up resistor if you are interested in the temp of a hotbed.

That will increase resolution at high temp. Probably won't fix 'nan' (not a number?), but it might move the error upwards. As wvmarle said, write a simple sketch that demonstrates the problem.

Would have been easier to use the 3.3volt supply as reference instead of a separate chip. (assuming an Uno, and nothing else connected to 3.3volt) Absolute voltage is irrelevant with a ratiometric sensor. Leo..

Wawa:
A 100k thermistor is about 10k@82C.
So use a 10k pull up resistor if you are interested in the temp of the hotbed.
Leo…

Thank you. I will give that a shot.

Don’t make changes to OP but add your schematic to new posts. Saves a lot of confusion.

Schematic inline, saves searching/downloading/etc:
IMG_0019.jpg

Indeed, wrong resistor value. Needs something much closer to the 100°C value of the NTC. Measure this, or check the data sheet.

Also I’m used to see a pull-up resistor rather than the pull-down you use, and using Vcc and not bothering with getting a separate reference voltage, as Vcc is the reference for the Arduino’s ADC already. Saves quite a few components. See also this Adafruit tutorial about using a thermistor.

wvmarle:
Don’t make changes to OP but add your schematic to new posts. Saves a lot of confusion.

Schematic inline, saves searching/downloading/etc:
IMG_0019.jpg

Indeed, wrong resistor value. Needs something much closer to the 100°C value of the NTC. Measure this, or check the data sheet.

Also I’m used to see a pull-up resistor rather than the pull-down you use, and using Vcc and not bothering with getting a separate reference voltage, as Vcc is the reference for the Arduino’s ADC already. Saves quite a few components. See also this Adafruit tutorial about using a thermistor.

Sorry about the confusion. I will use that as a learning experience.

I tried both methods and I saw the best results with a pull down method. I will try again when I have time to mess with changing the resistor.

If I use a resistor closer to my target temperature of 100degC will I loose accuracy at lower temperatures?

Bunkest: I tried both methods and I saw the best results with a pull down method. I will try again when I have time to mess with changing the resistor.

If I use a resistor closer to my target temperature of 100degC will I loose accuracy at lower temperatures?

There is NO difference. The thermistor between pin and ground is usually SAFER, because there is no 5volt going to the hotbed that can short out.

Yes. Thermistors have the highest number of A/D steps per degreeC if fixed resistor is the same as thermistor value. That's why we recommend the ~10k resistor with a 100k thermistor for hotbed use. Should still have some steps per degreeC at room temp though (try to calculate it). Leo..

Sounds good. Thank you all for the pointers. I will try a few things out tomorrow and report my results.

Bunkest:
If I use a resistor closer to my target temperature of 100degC will I loose accuracy at lower temperatures?

Yes - thermistors have effectively a limited range.

Also the B-coefficient formula loses accuracy that far from the nominal temperature, but it’s accurate enough to tell you whether it’s safe to touch the filament.