[AVR] reading thermistors - Page 1
Forum section: electronics / general

author: Simon
author_rank: Unknown
timestamp: July 05, 2018, 01:03:31 pm
content: For a long time my method of dealing with thermistors has been to use a series resistor that sort of gets me a linear response in the area i am interested in. This of course has severe limitations.So I am looking to just use the thermistor formula to calculate the temperature based on the resistance. I have come across the attached, would this all work in GCC/AVR land? seem's I just need to add the relevant *.C file to my project and call the function when I want the temperature from the calculated resistance.

author: darrylp
author_rank: Regular Contributor
timestamp: July 05, 2018, 01:09:15 pm
content: To use on an avr processor ? That's a huge lib. Many avr are very limited on program space. Surely a better quick 8 bit based lib would be better, or do you need high accuracy ? In which case use a proper temp device that can talk i2c or give a linear output might be better ?Sent from my HTC One using Tapatalk 2

author: firewalker
author_rank: Super Contributor
timestamp: July 05, 2018, 01:21:29 pm
content: No need for a library. Just solve the Steinhart-Hart equation for temperature.Code:#include <avr/io.h>#include <util/delay.h>#include <stdio.h>#include <stdlib.h>#include <math.h>// R2 exact value.#define R2 9988.0// NTC value at 25 degrees C.#define Rn 10000.0/*Vcc||/\/ NTC_Res\/||--------ADC_in|/\/ R2\/||GNDNTC_Res = (1024*R2)/ADC - R2*/// A, B, C and D are NTC coefficient.#define A 0.003354016#define B 0.000256985#define C 0.000002620131#define D 0.00000006383091double adc2temp(int RawADC) {double NTC_Res, celsius;double tmp; // temporary variable.NTC_Res=((1024 * R2 / RawADC) - R2);tmp = log(NTC_Res/Rn);tmp = (A+(B*tmp)+(C*tmp*tmp)+(D*tmp*tmp*tmp));celsius = (1.0/tmp)-273; // Celsius to Kelvin.return celsius;}Alexander.

author: Simon
author_rank: Unknown
timestamp: July 05, 2018, 01:33:04 pm
content: ok but i normally only ever get the beta value. I found this that makes short work of it:https://learn.adafruit.com/thermistor/using-a-thermistor

author: mikerj
author_rank: Super Contributor
timestamp: July 05, 2018, 01:47:21 pm
content: You still need to put some current through the thermistor to measure it's resistance, and you might as well carry on doing this with a fixed resistor since this provides a decent amount of linearisation. After that, just use a pre-calculated lookup table to convert your ADC value to a temperature - the linearisation provided by the resistor means you can get away with a fairly small table and use interpolation, which will be massively faster than trying to calculate temperature in real time via either the Beta equation or Steinhart-Hart.

author: C
author_rank: Super Contributor
timestamp: July 05, 2018, 03:22:56 pm
content: You could do a calibration run against a know good sensor and collect a lot of data.then use a program to built a correction table.Then between values of table you could possibility do a Least Squares fit

author: Kalvin
author_rank: Super Contributor
timestamp: July 05, 2018, 04:01:40 pm
content: Precomputed piece-wise linear lookup table might do the job with very little Flash/RAM without the floats.

author: Simon
author_rank: Unknown
timestamp: July 05, 2018, 04:25:58 pm
content: Quote from: mikerj on July 05, 2018, 01:47:21 pmSo when did anyone say a series resistor was not being used. I do get some linearity with a resistor but I'd like a less adhoc method.I could break it down into small sections and use a straight line every 10C. Code speed is not a problem.

author: C
author_rank: Super Contributor
timestamp: July 05, 2018, 07:06:37 pm
content: Quote from: Simon on July 05, 2018, 04:25:58 pmWith some math you can replace the straight line fit with a curved line fit and possibility get a better answer with a smaller table.As stated before if you have an ADC value that you can match to actual temperature the fit can get better.Instead of sitting an taking a bunch of reading, the easy way is to use a CPU to compare actual temperature from a good calibrated temperature sensor to your ADC value and use this data to build table.Not that hard to create a slow heat/slow cool chamber. This constant slow change even if not linear lets you get better comparison of values.C

author: mikerj
author_rank: Super Contributor
timestamp: July 06, 2018, 11:45:44 am
content: Quote from: Simon on July 05, 2018, 04:25:58 pmIt's not an "adhoc" method, it's an absolutely standard way of using thermistors. Code speed is not the only downside; drag in floating point libraries and the code size also bloats up significantly. There is really no good reason to do this on an 8bit micro when a basic piece-wise linear interpolation will give you all the performance you need at a fraction of the code size and execution time, especially if you are using the on-board ADC.Stick the thermistor parameters (Beta or Steinhart) into Excel and make yourself a table. You can do some basic analysis to determine the error introduced for the number of points in your table. FWIW I used this method on a Mega128 to control the temperature of a tunable laser to a resolution better than 0.01 Celsius (with a 16bit SPI ADC). IIRC the linearisation function took around 150 cycles without any special optimisations.If you make the table hold temperatures in equal, power-of-two ADC intervals rather than equal temperature intervals then it makes the maths very easy and very fast. The initial table lookup just requires the ADC value to be shifted right by the number of bits of your intervals size (e.g. 6 bits for an interval of 64LSBs) and used as the index into the table. The power of two interval then makes the interpolation calculations fast and simple with only a single multiply required.

author: firewalker
author_rank: Super Contributor
timestamp: July 06, 2018, 12:07:28 pm
content: Manufactures like Vishay have Excel files available to build the tables really quickly.Alexander.

author: Simon
author_rank: Unknown
timestamp: July 06, 2018, 01:06:50 pm
content: Quote from: mikerj on July 06, 2018, 11:45:44 amYes that is indeed what I think i will do, the change is R/C is not much over a few C so it would be fairly easy to do and like you say so much less resource hungry.

author: T3sl4co1l
author_rank: Super Contributor
timestamp: July 06, 2018, 01:07:31 pm
content: https://www.seventransistorlabs.com/Calc/Thermistor.html/threadTim

author: Simon
author_rank: Unknown
timestamp: July 06, 2018, 01:12:51 pm
content: Thanks Tim

author: Gibson486
author_rank: Frequent Contributor
timestamp: July 12, 2018, 01:13:35 am
content: Steinhart is fine on an AVR....until you start using an ADC greater than 12 bits. We used piece wise equations instead. It worked well until we realized that we were talking to a computer, so why not just have the computer take care of the conversion.

author: sleemanj
author_rank: Super Contributor
timestamp: July 12, 2018, 01:34:48 am
content: Some years ago I made a whole spreadsheet thing for generating NTC code including various different approximations charts so you can pick suitable ranges and so forth...https://sparks.gogo.co.nz/ntc_thermistor.htmlAt the core it isSteinhartBeta equation (which is a derivation from Steinhart) and derivations or further linear approximation based on that including integer-math only approximations if you don't have room for floating point.There is a lot of information there, but in essence, open the spreadsheet (make a copy), in the thermistor charcateristics change the Beta Value and nominal resistance as appropriate (if you don't know beta you can calculate it see the info in the green boxes), then set connection to either Vcc of Gnd (where the thermistor is connected) and choose the other resistor (other half of the divider), then you can right click the code in cell A45 and copy-paste it. For the cheaper approximations set a range of temperatures you are most interested in in the Low and High C fields, and change fiddle about with the Multiplier and "Other Resistor" while watching the charts.

author: sleemanj
author_rank: Super Contributor
timestamp: July 12, 2018, 01:50:00 am
content: For sake of simple example, for a 10k thermistor of beta 3950 with a 10k "other" resistor with the NTC on the low side (connected to Gnd), and a 10 bit ADC, my spreadsheet will poop out the following code (from which I have stripped comments for legibility)...Code:float convertAnalogToTemperature(unsigned int analogReadValue){// If analogReadValue is 1023, we would otherwise cause a Divide-By-Zero,// Treat as crazy out-of-range temperature.if(analogReadValue == 1023) return 1000.0;return (1/((log(((10000.0 * analogReadValue) / (1023.0 - analogReadValue))/10000.0)/3950.0) + (1 / (273.15 + 25.000)))) - 273.15;}float approximateTemperatureFloat(unsigned int analogReadValue){return -0.0917300598433493*analogReadValue+72.3197381920379;}int approximateTemperatureInt(unsigned int analogReadValue){return ((((((long)analogReadValue*64) / -698) * 64) + 4628) / 64) - 0;}

author: Simon
author_rank: Unknown
timestamp: July 12, 2018, 07:21:54 am
content: Quote from: T3sl4co1l on July 06, 2018, 01:07:31 pmYou lost me there as i don't have the practical understanding of the math. But peicewise linearization will do fine for my application.

author: T3sl4co1l
author_rank: Super Contributor
timestamp: July 12, 2018, 03:12:07 pm
content: The article is lengthy, but example code appears at the bottom.Piecewise interpolation is worse in all respects: it requires much more memory (lookup table), code and execution time (a division is required). A polynomial fit is best suited to the AVR, because it has hardware multiply.I suppose I should port the code to C some time, and also compare GCC's performance on the task.Tim

author: Simon
author_rank: Unknown
timestamp: July 12, 2018, 03:25:36 pm
content: Basically I can have power of two intervals so I can have an array with the linear slope of a range of values, bit shifting the reading will give the index of the applicable slope value, multiply by it.

author: mikerj
author_rank: Super Contributor
timestamp: July 13, 2018, 06:26:29 am
content: Quote from: T3sl4co1l on July 12, 2018, 03:12:07 pmArrange the table with 2^x ADC intervals and the division can be performed by shifts.