Shop OBEX P1 Docs P2 Docs Learn Events
Thermistor lookup table — Parallax Forums

Thermistor lookup table

Hello all,

I an using a 12-bit ADC to read the voltage from a thermistor voltage divider. I used a Vishay spreadsheet to calculate the min and max resistance value for each degree. I then took those values and made a spreadsheet that does the voltage divider calculations, and outputs a min ADC, and max ADC value for each degree.

My question is, how do i take a list of min ADC values, and max ADC values and have the prop know that if the ADC value it just read correlates to a temperature value?

I have included a couple values from my spreadsheet.
DAT
                        '        min     max
        tempList        byte    $03D8,  $03AD   '0deg
                        byte    $03FE,  $03D2   '1deg
                        byte    $0425,  $03F9   '2deg
                        byte    $044D,  $0420   '3deg
                        byte    $0475,  $0448   '4deg
                        byte    $049E,  $0470   '5deg
                        byte    $04C7,  $0499   '6deg
                        byte    $04F1,  $04C3   '7deg
                        byte    $051C,  $04EE   '8deg
                        byte    $0547,  $0518   '9deg
                        byte    $0572,  $0544   '10deg
                        byte    $059E,  $0570   '11deg
                        byte    $05CA,  $059C   '12deg
                        byte    $05F7,  $05C9   '13deg
                        byte    $0624,  $05F6   '14deg
                        byte    $0651,  $0623   '15deg
                        byte    $067E,  $0650   '16deg
                        byte    $06AB,  $067E   '17deg
                        byte    $06D8,  $06AC   '18deg
                        byte    $0706,  $06D9   '19deg
                        byte    $0733,  $0707   '20deg
                        byte    $0760,  $0735   '21deg
                        byte    $078E,  $0763   '22deg
                        byte    $07BB,  $0790   '23deg
                        byte    $07E8,  $07BE   '24deg
                        byte    $0814,  $07EB   '25deg
                        byte    $0841,  $0818   '26deg
                        byte    $086E,  $0844   '27deg
                        byte    $089A,  $086F   '28deg
                        byte    $08C6,  $089B   '29deg
                        byte    $08F2,  $08C6   '30deg
                        byte    $091D,  $08F0   '31deg
                        byte    $0947,  $091B   '32deg
                        byte    $0971,  $0944   '33deg
                        byte    $099B,  $096D   '34deg
                        byte    $09C4,  $0996   '35deg
                        byte    $09EC,  $09BE   '36deg
                        byte    $0A14,  $09E6   '37deg
                        byte    $0A3B,  $0A0D   '38deg
                        byte    $0A61,  $0A33   '39deg
                        byte    $0A87,  $0A58   '40deg
                        byte    $0AAC,  $0A7D   '41deg
                        byte    $0AD0,  $0AA2   '42deg
                        byte    $0AF4,  $0AC6   '43deg
                        byte    $0B16,  $0AE9   '44deg
                        byte    $0B39,  $0B0B   '45deg
                        byte    $0B5A,  $0B2C   '46deg
                        byte    $0B7B,  $0B4D   '47deg
                        byte    $0B9B,  $0B6E   '48deg
                        byte    $0BBA,  $0B8D   '49deg
                        byte    $0BD9,  $0BAC   '50deg

Thanks TC

Comments

  • I hope you are only using a thermistor because you can't use a digital thermometer chip such as the DS18B20 or MCP9808 etc. The latter is accurate to ±0.25°C (typical) from -40°C to +125°C and costs ~$1 and you connect to it on the I2C bus easily.

    Otherwise you need to do it the hard way as you are doing and normalize and interpolate from your table to make it fit the table the way you have done it or you could just substitute a multi-turn trim pot to dial up these "temperatures" and build up your table with the actual ADC values and simply interpolate unless you aren't worried about precision. Too much hard work this way though.
  • TCTC Posts: 1,019
    I hope you are only using a thermistor because you can't use a digital thermometer chip such as the DS18B20 or MCP9808 etc. The latter is accurate to ±0.25°C (typical) from -40°C to +125°C and costs ~$1 and you connect to it on the I2C bus easily.

    Otherwise you need to do it the hard way as you are doing and normalize and interpolate from your table to make it fit the table the way you have done it or you could just substitute a multi-turn trim pot to dial up these "temperatures" and build up your table with the actual ADC values and simply interpolate unless you aren't worried about precision. Too much hard work this way though.

    Unfortunately I have to use thermistors. They have the package I need.

    The table I made is the minimum ADC, and the maximum ADC value for each temperature degree. For example, say the prop got a reading of $0712, it would use the lookup table and find $0712 is greater than $0707, and less than $0733, the prop would then know those values correspond to 20 degrees.

    Is there a better way to make a lookup table? I only need 1 degree(ish) precision.

  • idbruceidbruce Posts: 6,197
    edited 2017-03-17 14:47
    TC

    Others may disagree, but I would not list min and max readings, instead I would list min and corresponding temp. After obtaining a reading, iterate through the min list and compare. If the reading is above the current min value, then compare to the next min value, otherwise you have found your temp.

    I have some good code for this written in C, if you are interested.
  • MJBMJB Posts: 1,235
    HI @TC,

    first I notice is that your max and min seem to be swapped.

    Second is - the ranges overlap.

    So I would change the spreadsheet to give the border values between 2 neighboering degree values and thus reduce the values you have to store in a table by 50%.
    So gives you just a simple list of values to compare your reading against to find the position which is the °C result then.

    Or you can run a little plotting / regression in EXCEL and see if a simple linear or low order approximation is good enough. Giving you a formula instead of the table.



  • TCTC Posts: 1,019
    idbruce wrote: »
    TC

    Others may disagree, but I would not list min and max readings, instead I would list min and corresponding temp. After obtaining a reading, iterate through the min list and compare. If the reading is above the current min value, then compare to the next min value, otherwise you have found your temp.

    I have some good code for this written in C, if you are interested.

    That was one option I was thinking of since I am not looking for perfect accuracy, close enough is good enough.


    MJB wrote: »
    HI @TC,

    first I notice is that your max and min seem to be swapped.

    Second is - the ranges overlap.

    So I would change the spreadsheet to give the border values between 2 neighboering degree values and thus reduce the values you have to store in a table by 50%.
    So gives you just a simple list of values to compare your reading against to find the position which is the °C result then.

    Or you can run a little plotting / regression in EXCEL and see if a simple linear or low order approximation is good enough. Giving you a formula instead of the table.



    You are correct, I did not notice I had the labels backwards. I got the values from Vishay's spreadsheet. Then I took the "Rmin" and "Rmax" values and inputted them into the voltage divider formula (~ Vout=(4.096V*(10KΩ/"termsistor resistance"+10KΩ)) ~). I then took that value multiply it by 100, then made it an integer. That value would repersent the ADC equivalent for the termistor resistant value.

    I hope that makes sense.

  • A simple table in memory is the easiest way. Use a halfing search of the sorted table in order to get the fastest lookups in most cases.

    If you do not mind me asking, why are you using an external ADC? For a thermistor (something I am also working with now on the Propeller) using a simple cap and second resistor to make a simple RC-Time circuit is quite enough, especially considering the high resistance of a thermistor until you get to extremely high temperatures. I am only working in the temperature range of -10C to +280C so it is fairly simple, though the range excludes the use of a chip thermometer.
  • TCTC Posts: 1,019
    A simple table in memory is the easiest way. Use a halfing search of the sorted table in order to get the fastest lookups in most cases.

    If you do not mind me asking, why are you using an external ADC? For a thermistor (something I am also working with now on the Propeller) using a simple cap and second resistor to make a simple RC-Time circuit is quite enough, especially considering the high resistance of a thermistor until you get to extremely high temperatures. I am only working in the temperature range of -10C to +280C so it is fairly simple, though the range excludes the use of a chip thermometer.

    I am reading 7 thermistors, but I cant tie up a lot of pins. I am using a MCP3208 to read the voltages from the thermistor voltage divider.

  • MJBMJB Posts: 1,235
    edited 2017-03-17 16:32
    If you post the whole table (in decimals, not HEX) I am sure there is a simple formula for approximating it.
  • TCTC Posts: 1,019
    MJB wrote: »
    If you post the whole table (in decimals, not HEX) I am sure there is a simple formula for approximating it.

    I changed the values from HEX to decimal, and I can see there is a lot of cross over of the values. So what I have decided to do is, only calculate for the actual temperature, and not the temperature plus the tolerance. The prop would just start at the first value, compare the ADC value to the list, the ADC value is larger that the list value, the prop would go to the next value. The prop would keep doing that untill it came across a value that is less than the ADC value. And every time the prop went to the next value in the lookup table, it would add 1 to a counter.

  • I'm attaching an object that I use for a particular Murata thermistor, but it might give you some ideas. There is a table in DAT that comes from the thermistor data sheet. Entries are resistance in ohms at evenly spaced 5 degree Celsius intervals from -40 to +125. There is a method that takes the voltage across the divider and the voltage across the thermistor to find the temperature by interpolation between the 5 degree increments. It is a simple step search. The main entry points start by calculating the resistance, followed by the resistance to temperature conversion.

  • TC

    Here it is in C, perhaps this will give you some ideas.

    The code was originally written by Adafruit for the ADS1015, but it has been highly altered by yours truly to permit to different thermistor readings.

    You should be able to open it up in any text editor.
  • JasonDorieJasonDorie Posts: 1,930
    edited 2017-03-17 17:44
    Bruce's suggestion of storing only the low value for each temperature is spot on. I've done this with a project of my own, using thermistors because digital temp IC's didn't have the high-end range I needed.

    If you store the low-point for a given temperature, you iterate through the list of numbers until you find one higher than your sample reading, or you reach the end of the table. When you find a reading, you can even figure out where you are between readings, and use that as a fractional measure of the degree value to improve precision.

    For example, if your sample is $A4F, and your table is:
                            byte    $0A31   '39deg
                            byte    $0A5C   '40deg
    

    Low = $A31 = 2609
    High = $A5C = 2652
    Sample = $A4F = 2639

    Range = (High - Low) = 43 (distance between your table entries)
    Pos = (Sample - Low) = 30 (where your sample falls in the above range)

    Fraction = (Pos / Range) = 30 / 43 = 0.7

    So your temperature is (roughly) 39.7 degrees

    For my application, I stored the temperatures in 5 degree increments and use interpolation to get degrees.
  • JonnyMacJonnyMac Posts: 8,912
    edited 2017-03-17 18:32
    Why are you using byte instead of word in your table definition? Am I missing a trick?
  • Why lookup table, when its possible to calculate with math?

    https://learn.adafruit.com/thermistor/using-a-thermistor

    Done this with arduino and get 2-3 degrees error. It's simple to translate to spin.
  • JonnyMac wrote: »
    Why are you using byte instead of word in your table definition? Am I missing a trick?

    Hah - Good catch. I copied from the original post and didn't even notice he'd be overflowing the 8-bit limit. That would very certainly cause you issues. A byte won't hold a value higher than $FF, and it'll most likely truncate, keeping the lower 8 bits of your original value.
  • JasonDorie wrote:
    A byte won't hold a value higher than $FF, and it'll most likely truncate, keeping the lower 8 bits of your original value.
    IIRC, the compiler gives you a range error when your cup runneth over.

    -Phil
  • JDat wrote: »
    Why lookup table, when its possible to calculate with math?

    https://learn.adafruit.com/thermistor/using-a-thermistor

    Done this with arduino and get 2-3 degrees error. It's simple to translate to spin.
    WOW, thank you. I had been attempting to reverse engineer a good formula from the values I am getting, that will simplify life a lot (no need to reinvent the wheel on this one).

    Thank you.
  • TC wrote: »
    A simple table in memory is the easiest way. Use a halfing search of the sorted table in order to get the fastest lookups in most cases.

    If you do not mind me asking, why are you using an external ADC? For a thermistor (something I am also working with now on the Propeller) using a simple cap and second resistor to make a simple RC-Time circuit is quite enough, especially considering the high resistance of a thermistor until you get to extremely high temperatures. I am only working in the temperature range of -10C to +280C so it is fairly simple, though the range excludes the use of a chip thermometer.

    I am reading 7 thermistors, but I cant tie up a lot of pins. I am using a MCP3208 to read the voltages from the thermistor voltage divider.

    I can see that. 7 Thermistors would take 14 pins, and that would be a problem for most any project. I am doing only 3 thermistors, so only 6 pins.
  • The issue with the solving the Steinhart-Hart equation on the Prop is that you'll probably need to load a floating point library. It will take up more memory and it will be slower than a table lookup.
  • The issue with the solving the Steinhart-Hart equation on the Prop is that you'll probably need to load a floating point library. It will take up more memory and it will be slower than a table lookup.

    What is wrong with using fixed point for that application?
  • jmgjmg Posts: 15,140
    TC wrote: »
    Is there a better way to make a lookup table? I only need 1 degree(ish) precision.
    You have started along the right track.
    TC wrote: »
    I changed the values from HEX to decimal, and I can see there is a lot of cross over of the values.

    This also is the right track. You do need to use those MAX and MIN values to give you some error indications, but you should not use them for lookups.
    Instead, you want the most likely curve as your decision basis.
    TC wrote: »
    So what I have decided to do is, only calculate for the actual temperature, and not the temperature plus the tolerance. The prop would just start at the first value, compare the ADC value to the list, the ADC value is larger that the list value, the prop would go to the next value. The prop would keep doing that untill it came across a value that is less than the ADC value. And every time the prop went to the next value in the lookup table, it would add 1 to a counter.

    That works, but more compact is to store a difference in the ADC table, which can now fit in a byte, making a smaller table.
    The table scan now adds the differences, and increments the Degrees by 1 each time.
    ( A slight speed hit, has decreased the table size.)

    You pick the nearest table Sum, to your ADC reading. (not a < test)

    The points you store to make the decisions, should be (nominally) 0.5 degrees offset, so you have a +/- 0.5 degree sawtooth error
    result.
    The ADC deltas you have look to vary from 31~38/1 deg increment, so you will be quite precise on the 0.5 offset , and have enough spare resolution you could add a 0.1 degree interpolate if you wanted to.

  • The issue with the solving the Steinhart-Hart equation on the Prop is that you'll probably need to load a floating point library. It will take up more memory and it will be slower than a table lookup.

    What is wrong with using fixed point for that application?

    The Adafruit article linked above by JDat used floating point. Be that as it may, I'm all for fixed point. However, you'll have to formulate the natural log function as well as tricky scaling. It's not that easy. There is a log table in the Prop Rom, however you have to really understand how to use it. Most of the Prop floating point libraries use that table, so it comes back to a table lookup with lots of overhead.

    The table lookup I posted earlier has parameters stored in DAT for the increment between temperature values, set at 5 degrees, but it could just as well be 1 or 2 degrees to cover the desired range with greater accuracy, also with interpolation. There are parameters in DAT for the lowest value (-40) and the highest value (+125) in the table, and the lookup/interpolation algorithm adjusts for the high, low, and the increment.





  • TCTC Posts: 1,019
    edited 2017-03-22 13:19
    I am sorry everyone, I have been under the weather. My brain has not been working that great these couple weeks.

    I did notice the "byte" should of been "word" when I took a good long look. I will reply to everyone a little later when my brain starts getting better.

    Thanks
    TC
  • max72max72 Posts: 1,155
    With thermistors in some cases you can use another resistor in parallel and linearize the output, depending on your range and requirements it could be enough.
    Massimo
Sign In or Register to comment.