Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Revised thermistor code. Thermistor table now in 14.2 fixed point

Two thermistor tables included:
  ThermistorTable.h.dist.old, which is the table we used to have, included so those already using it don't have to recalibrate.
  ThermistorTable.h.dist, which was generated with 50 entries, and trimmed down in lower temperature ranges where we don't care as much about accuracy and there's less deviation from a straight line anyway.

Corrected default temp sensor entry in config.h.dist to thermistor instead of intercom. (Now matches earlier definitions which by default say we're using a thermistor)

Added noheater sensor example to config.h.dist

Copied CreateTemperatureLook.py from "official" firmware, and modified it for 14.2 fixed point, no negative temperatures (we're using uint16_t's), and PROGMEM.

Since I simply copied the example linear interpolation formula from wikipedia, I'm certian that it could be more efficient. The code that was there wouldn't work with 14.2 table values, and my understanding of it was too shallow to fix it. This works, and upgading the calculations to uint32_t actually takes less code space than leaving them at uint16_t. I assume it's calling a library routine that's already being linked in for the 32-bit math.
  • Loading branch information...
commit 686e4174012f7019957f5eb505fb68a6d36bacdc 1 parent 6c1040c
John Gilmore (none) authored committed
View
41 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
+};
View
40 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
+};
View
5 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)
/***************************************************************************\
View
155 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:])
View
60 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);
Please sign in to comment.
Something went wrong with that request. Please try again.