diff --git a/ThermistorTable.h.dist b/ThermistorTable.h.dist new file mode 100644 index 0000000..f21b24f --- /dev/null +++ b/ThermistorTable.h.dist @@ -0,0 +1,41 @@ +// default thermistor lookup table +// Thermistor lookup table, generated with --num-temps=50 and trimmed in lower temperature ranges. +// You may be able to improve the accuracy of this table in various ways. +// 1. Measure the actual resistance of the resistor. It's "nominally" 4.7K, but that's ± 5%. +// 2. Measure the actual beta of your thermistor:http://reprap.org/wiki/MeasuringThermistorBeta +// 3. Generate more table entries than you need, then trim down the ones in uninteresting ranges. (done) +// In either case you'll have to regenerate this table, which requires python, which is difficult to install on windows. +// Since you'll have to do some testing to determine the correct temperature for your application anyway, you +// may decide that the effort isn't worth it. Who cares if it's reporting the "right" temperature as long as it's +// keeping the temperature steady enough to print, right? +// ./createTemperatureLookup.py --r0=100000 --t0=25 --r1=0 --r2=4700 --beta=4066 --max-adc=1023 +// r0: 100000 +// t0: 25 +// r1: 0 +// r2: 4700 +// beta: 4066 +// max adc: 1023 +#define NUMTEMPS 20 +// {ADC, temp*4 }, // temp +uint16_t temptable[NUMTEMPS][2] PROGMEM = { + {1, 3364}, // 841.027617469 C + {21, 1329}, // 332.486789769 C + {41, 1104}, // 276.102666373 C + {61, 987}, // 246.756060004 C + {81, 909}, // 227.268080588 C + {101, 851}, // 212.78847342 C + {121, 805}, // 201.30176775 C + {141, 767}, // 191.787692666 C + {161, 734}, // 183.662212795 C + {181, 706}, // 176.561442671 C + {201, 680}, // 170.244089549 C + {221, 658}, // 164.542298163 C + {241, 637}, // 159.33475843 C + {321, 567}, // 141.921298995 C + {381, 524}, // 131.166509425 C + {581, 406}, // 101.561865389 C + {781, 291}, // 72.9710018071 C + {881, 219}, // 54.8051659223 C + {981, 93}, // 23.4825243529 C + {1010, 1} // 0.498606463441 C +}; diff --git a/ThermistorTable.h.dist.old b/ThermistorTable.h.dist.old new file mode 100644 index 0000000..8b79d43 --- /dev/null +++ b/ThermistorTable.h.dist.old @@ -0,0 +1,40 @@ +// default thermistor lookup table +// You may be able to improve the accuracy of this table in various ways. +// 1. Measure the actual resistance of the resistor. It's "nominally" 4.7K, but that's ± 5%. +// 2. Measure the actual beta of your thermistor:http://reprap.org/wiki/MeasuringThermistorBeta +// 3. Generate more table entries than you need, then trim down the ones in uninteresting ranges. +// In either case you'll have to regenerate this table, which requires python, which is difficult to install on windows. +// Since you'll have to do some testing to determine the correct temperature for your application anyway, you +// may decide that the effort isn't worth it. Who cares if it's reporting the "right" temperature as long as it's +// keeping the temperature steady enough to print, right? +// ./createTemperatureLookup.py --r0=100000 --t0=25 --r1=0 --r2=4700 --beta=4066 --max-adc=1023 +// r0: 100000 +// t0: 25 +// r1: 0 +// r2: 4700 +// beta: 4066 +// max adc: 1023 +#define NUMTEMPS 20 +// {ADC, temp*4 }, // temp +uint16_t temptable[NUMTEMPS][2] PROGMEM = { + {1, 3364}, // 841.027617469 C + {54, 1021}, // 255.484742371 C + {107, 836}, // 209.086676326 C + {160, 736}, // 184.041730874 C + {213, 667}, // 166.757734773 C + {266, 613}, // 153.384693074 C + {319, 569}, // 142.306856925 C + {372, 530}, // 132.69219366 C + {425, 496}, // 124.050228124 C + {478, 464}, // 116.059537816 C + {531, 433}, // 108.487976164 C + {584, 404}, // 101.149819461 C + {637, 375}, // 93.8781909528 C + {690, 346}, // 86.5019752148 C + {743, 315}, // 78.8186715355 C + {796, 282}, // 70.5502229207 C + {849, 244}, // 61.2498501294 C + {902, 200}, // 50.050743055 C + {955, 138}, // 34.7070638836 C + {1008, 12} // 3.01733235284 C +}; diff --git a/config.h.dist b/config.h.dist index 7d1348c..f5a4281 100644 --- a/config.h.dist +++ b/config.h.dist @@ -247,8 +247,11 @@ undefine if you don't want to use them #endif // name type pin -DEFINE_TEMP_SENSOR(extruder, TT_INTERCOM, 0) +DEFINE_TEMP_SENSOR(extruder, TT_THERMISTOR, 0) // DEFINE_TEMP_SENSOR(bed, TT_THERMISTOR, 1) +// "noheater" is a special name for a sensor which doesn't have a heater. +// Use "M105 P#" to read it, where # is a zero-based index into this list. +// DEFINE_TEMP_SENSOR(noheater, TT_THERMISTOR, 1) /***************************************************************************\ diff --git a/createTemperatureLookup.py b/createTemperatureLookup.py new file mode 100755 index 0000000..15de1e0 --- /dev/null +++ b/createTemperatureLookup.py @@ -0,0 +1,155 @@ +#!/usr/bin/python +# +# Creates a C code lookup table for doing ADC to temperature conversion +# on a microcontroller +# based on: http://hydraraptor.blogspot.com/2007/10/measuring-temperature-easy-way.html +# Modified Thu 10 Feb 2011 02:02:28 PM MST jgilmore for 5D_on_arduino firmware +# temps are now in 14.2 fixed point notation (i.e. measured in quarter-degrees) +# temps are not permitted to be negative (BUG:may result in numtemps fewer than requested) +# bugfix: --num-temps command line option works. + +"""Thermistor Value Lookup Table Generator + +Generates lookup to temperature values for use in a microcontroller in C format based on: +http://hydraraptor.blogspot.com/2007/10/measuring-temperature-easy-way.html + +The main use is for Arduino programs that read data from the circuit board described here: +http://make.rrrf.org/ts-1.0 + +Usage: python createTemperatureLookup.py [options] + +Options: + -h, --help show this help + --r0=... thermistor rating where # is the ohm rating of the thermistor at t0 (eg: 10K = 10000) + --t0=... thermistor temp rating where # is the temperature in Celsuis to get r0 (from your datasheet) + --beta=... thermistor beta rating. see http://reprap.org/bin/view/Main/MeasuringThermistorBeta + --r1=... R1 rating where # is the ohm rating of R1 (eg: 10K = 10000) + --r2=... R2 rating where # is the ohm rating of R2 (eg: 10K = 10000) + --num-temps=... the number of temperature points to calculate (default: 20) + --max-adc=... the max ADC reading to use. if you use R1, it limits the top value for the thermistor circuit, and thus the possible range of ADC values + +It is suggested to generate more values than you need, and delete some of the ones in the ranges +that aren't interesting. This will improve accuracy in the temperature ranges that are important to you. +""" + +from math import * +import sys +import getopt + +class Thermistor: + "Class to do the thermistor maths" + def __init__(self, r0, t0, beta, r1, r2): + self.r0 = r0 # stated resistance, e.g. 10K + self.t0 = t0 + 273.15 # temperature at stated resistance, e.g. 25C + self.beta = beta # stated beta, e.g. 3500 + self.vadc = 5.0 # ADC reference + self.vcc = 5.0 # supply voltage to potential divider + self.k = r0 * exp(-beta / self.t0) # constant part of calculation + + if r1 > 0: + self.vs = r1 * self.vcc / (r1 + r2) # effective bias voltage + self.rs = r1 * r2 / (r1 + r2) # effective bias impedance + else: + self.vs = self.vcc # effective bias voltage + self.rs = r2 # effective bias impedance + + def temp(self,adc): + "Convert ADC reading into a temperature in Celcius" + v = adc * self.vadc / 1024 # convert the 10 bit ADC value to a voltage + r = self.rs * v / (self.vs - v) # resistance of thermistor + return (self.beta / log(r / self.k)) - 273.15 # temperature + + def setting(self, t): + "Convert a temperature into a ADC value" + r = self.r0 * exp(self.beta * (1 / (t + 273.15) - 1 / self.t0)) # resistance of the thermistor + v = self.vs * r / (self.rs + r) # the voltage at the potential divider + return round(v / self.vadc * 1024) # the ADC reading + +def main(argv): + + r0 = 10000; + t0 = 25; + beta = 3947; + r1 = 680; + r2 = 1600; + num_temps = int(20); + max_adc = int(1023); + + try: + opts, args = getopt.getopt(argv, "h", ["help", "r0=", "t0=", "beta=", "r1=", "r2=", "max-adc=", "num-temps="]) + except getopt.GetoptError: + usage() + sys.exit(2) + + for opt, arg in opts: + if opt in ("-h", "--help"): + usage() + sys.exit() + elif opt == "--r0": + r0 = int(arg) + elif opt == "--t0": + t0 = int(arg) + elif opt == "--beta": + beta = int(arg) + elif opt == "--r1": + r1 = int(arg) + elif opt == "--r2": + r2 = int(arg) + elif opt == "--max-adc": + max_adc = int(arg) + elif opt == "--num-temps": + num_temps = int(arg) + + increment = int(max_adc/(num_temps-1)); + + t = Thermistor(r0, t0, beta, r1, r2) + + adcs = range(1, max_adc, increment); +# adcs = [1, 20, 25, 30, 35, 40, 45, 50, 60, 70, 80, 90, 100, 110, 130, 150, 190, 220, 250, 300] + first = 1 + + #Chop of negative temperatures (as we're using a unsigned 16-bit value for temp) + for i in range(0,len(adcs)): + if int(t.temp(adcs[i])*4) < 0: + adcs=adcs[0:i+1] + #Replace this with the ADC reading for 0C + adcs[i]=int(t.setting(0)) + #If the closes ADC reading to 0C is negative, convert to next highest ADC reading + if int(t.temp(adcs[i])*4)<0: + adcs[i] -=1 + break + print "// Thermistor lookup table" + print "// default thermistor lookup table" + print "// You may be able to improve the accuracy of this table in various ways." + print "// 1. Measure the actual resistance of the resistor. It's \"nominally\" 4.7K, but that's ± 5%." + print "// 2. Measure the actual beta of your thermistor:http://reprap.org/wiki/MeasuringThermistorBeta" + print "// 3. Generate more table entries than you need, then trim down the ones in uninteresting ranges." + print "// In either case you'll have to regenerate this table, which requires python, which is difficult to install on windows." + print "// Since you'll have to do some testing to determine the correct temperature for your application anyway, you" + print "// may decide that the effort isn't worth it. Who cares if it's reporting the \"right\" temperature as long as it's" + print "// keeping the temperature steady enough to print, right?" + print "// ./createTemperatureLookup.py --r0=%s --t0=%s --r1=%s --r2=%s --beta=%s --max-adc=%s" % (r0, t0, r1, r2, beta, max_adc) + print "// r0: %s" % (r0) + print "// t0: %s" % (t0) + print "// r1: %s" % (r1) + print "// r2: %s" % (r2) + print "// beta: %s" % (beta) + print "// max adc: %s" % (max_adc) + print "#define NUMTEMPS %s" % (len(adcs)) + print "// {ADC, temp*4 }, // temp" + print "uint16_t temptable[NUMTEMPS][2] PROGMEM = {" + + counter = 0 + for adc in adcs: + counter = counter +1 + if counter == len(adcs): + print " {%s, %s} // %s C" % (adc, int(t.temp(adc)*4), t.temp(adc)) + else: + print " {%s, %s}, // %s C" % (adc, int(t.temp(adc)*4), t.temp(adc)) + print "};" + +def usage(): + print __doc__ + +if __name__ == "__main__": + main(sys.argv[1:]) diff --git a/temp.c b/temp.c index 3985dc0..f5423b2 100644 --- a/temp.c +++ b/temp.c @@ -60,30 +60,7 @@ struct { #ifdef TEMP_THERMISTOR #include "analog.h" - -#define NUMTEMPS 20 -uint16_t temptable[NUMTEMPS][2] PROGMEM = { - {1, 841}, - {54, 255}, - {107, 209}, - {160, 184}, - {213, 166}, - {266, 153}, - {319, 142}, - {372, 132}, - {425, 124}, - {478, 116}, - {531, 108}, - {584, 101}, - {637, 93}, - {690, 86}, - {743, 78}, - {796, 70}, - {849, 61}, - {902, 50}, - {955, 34}, - {1008, 3} -}; +#include "ThermistorTable.h" #endif #ifdef TEMP_AD595 @@ -191,15 +168,44 @@ void temp_sensor_tick() { //Calculate real temperature based on lookup table for (j = 1; j < NUMTEMPS; j++) { if (pgm_read_word(&(temptable[j][0])) > temp) { - // multiply by 4 because internal temp is stored as 14.2 fixed point - temp = pgm_read_word(&(temptable[j][1])) * 4 + (temp - pgm_read_word(&(temptable[j-1][0]))) * 4 * (pgm_read_word(&(temptable[j][1])) - pgm_read_word(&(temptable[j-1][1]))) / (pgm_read_word(&(temptable[j][0])) - pgm_read_word(&(temptable[j-1][0]))); + // Thermistor table is already in 14.2 fixed point + if (debug_flags & DEBUG_PID) + sersendf_P(PSTR("pin:%d Raw ADC:%d table entry: %d"),temp_sensors[i].temp_pin,temp,j); + // Linear interpolating temperature value + // y = ((x - x₀)y₁ + (x₁-x)y₀ ) / (x₁ - x₀) + // y = temp + // x = ADC reading + // x₀= temptable[j-1][0] + // x₁= temptable[j][0] + // y₀= temptable[j-1][1] + // y₁= temptable[j][1] + // y = + // Wikipedia's example linear interpolation formula. + temp = ( + // ((x - x₀)y₁ + ((uint32_t)temp - pgm_read_word(&(temptable[j-1][0]))) * pgm_read_word(&(temptable[j][1])) + // + + + + // (x₁-x) + (pgm_read_word(&(temptable[j][0])) - (uint32_t)temp) + // y₀ ) + * pgm_read_word(&(temptable[j-1][1]))) + // / + / + // (x₁ - x₀) + (pgm_read_word(&(temptable[j][0])) - pgm_read_word(&(temptable[j-1][0]))); + if (debug_flags & DEBUG_PID) + sersendf_P(PSTR(" temp:%d.%d"),temp/4,(temp%4)*25); break; } } + if (debug_flags & DEBUG_PID) + sersendf_P(PSTR(" Sensor:%d\n"),i); + //Clamp for overflows if (j == NUMTEMPS) - temp = temptable[NUMTEMPS-1][1] * 4; + temp = temptable[NUMTEMPS-1][1]; temp_sensors_runtime[i].next_read_time = 0; } while (0);