## STEINHART-HART COEFFICIENTS for Thermistors

21 posts / 0 new
Author
Message

I have these STEINHART-HART COEFFICIENTS for a thermistor and have no idea how to use them to linearize my 10 bit result that so far I send to an LCD.

a = 0.00112485;
b = 0.000234822;
c = 0.000000085;

From AD0 I am reading 0-1023 depending on the temperature with 600 being around 25c.

I did study an example from Michael Spiceland which I have attached who uses a different thermistor but in his example he has four fields for the Thermistor Coefficents where mine just has three, I am trying to get the temp from a device who's thermistor is glued in so I cannot use another one.

Also, on the Atmega128, it has Vref. Is this for feeding an external voltage reference into the AD, If so I am wondering if more accurate/stable results from the thermistor would be possible if I used say a 2.5V precision reference instead of VCC.

Any help appreciated.

## Attachment(s):

```//----thermistor stuff----------
#define C2K 273.15
#define FIVEOVERNINE .5555555
#define NINEOVERFIVE 1.8
#define FIVEOVER1023 .05

float ntcv;
float ntcr;
float rref,ntci;
float tk,tc;
float tf;
float lnr,lnrcu;
float oneovert;
//-------------------------
//steinhart eqn:   1/T= a+ b*LnR + c*LnR^3
//rref is in series with thermistor from VCC

ntcv = adavg*FIVEOVER1023; //v across thermistor
ntci = (5.0-ntcv)/rref;    //i thru thermistor (use actual vcc rather than 5.0)
ntcr = ntcv/ntci;          //r of thermistor
lnr = log(ntcr);           //ln of r
lnrcu = lnr*lnr*lnr;       //(ln of r)^3
oneovert =a + b*lnr + c*lnrcu;
tk = 1.0/oneovert;         //kelvin
tc = tk - C2K;             //celcius
tf = NINEOVERFIVE*tc + 32.0;  //fahrenheit
}

//-------------------------
void thermistorloop(void){
char ch;

cprintf("v       r       tc      tf\n");
//  a= 1.197529e-3;   //from US sensors applet
//  b= 2.405050502e-4;
//  c= 1.92392e-7;

while(ch != 'q'){
cprintf("%#7.3f %#7.1f %#7.1f %#7.1f  \r",ntcv,ntcr,tc,tf);
if(kbhit()){
ch=getchar();
}
}
}
```

Imagecraft compiler user

Thanks bob but that's confused me like crazy.

I have been making some progress with this code although my results are a little ooooff.

And also, am trying to get results with .1 or better resolutions.

```ActualTemp = Thermister(ADCvalue);
// Returns 37 at 27.8 celcius
```
```
// Returns 5700 to 5800 at 27.8 celcius
```
```
/*
A simple little application to test temperitures on an atmega128/16.
*/

#include
#include
#include
#include
#include
#include "lcd.h"
#include
#include
#include
#include
#include
#include

void was_LCD_connected();
// A function that tests if the LCD is plugged in
bool LCD_CONNECTED;
// a Variable set by is_LCD_connected 1=connected:0 is missing
volatile uint16_t word;

long Resistance;
double Temp;

{

// Select from ADC Channel specified

// use AVcc as the reference

// clear for 10 bit resolution

// 128 prescale for 16Mhz  = 125Khz.

}

{

Temp = log(Resistance);
Temp = 1 / (0.00112485 + (0.000234822 * Temp) + (0.000000085 * Temp * Temp * Temp));
Temp = Temp - 273.15;
// Convert Kelvin to Celsius

//Temp = (Temp * 9.0)/ 5.0 + 32.0;
// Here if result should be Fahrenheit.
return Temp;
}

int main(void)
{

char ws[50];
float ActualTemp;

was_LCD_connected();
// Checks if the pyhsical connector of the LCD is in Place

if (LCD_CONNECTED)
lcd_init(LCD_DISP_ON);
lcd_clrscr();

while(1)
{

if (LCD_CONNECTED)
{

// 5V = 1023 which is 10 bits. 0V = 0

// Returns 37 at 27.8 celcius
itoa(ActualTemp, ws, 10);
lcd_gotoxy(0,0);
lcd_puts(ws);
lcd_puts("  ");

// Returns 5700 to 5800 at 27.8 celcius
itoa(Resistance, ws, 10);
lcd_gotoxy(0,1);
lcd_puts("Resistance=");
lcd_puts(ws);
lcd_puts("  ");

}

}

}

```

You need the resistance of the thermistor. If you have a known R from a known V to the thermistor, and read the volts across the thermistor, you can also calc the I thru it because of the known R above it. See how my program calculated R by using I and V?

Imagecraft compiler user

US Sensors has an applet where you enter 3 temperatures and 3 resistances from the sensor (like at 0 deg, 25 deg, and 100 deg) and it calcs the a,b, and c.

Imagecraft compiler user

Yes it has just three constants, I am almost there but just seam to be calculating wrong some place.

Quote:
If so I am wondering if more accurate/stable results from the thermistor would be possible if I used say a 2.5V precision reference instead of VCC.

2V5 is better than Vcc, mainly because of the reduction of self-heating of the thermistor you use. What value of pullup resistor do you use ? Be sure you use a pullup resistor that is accurate enough

Are you sure its only one set of a/b/c constants ? The thermistor I use (thermometrics) has 4 sets of a/b/c/d, each for another temperature range.

Well I am going insane here.

I am trying getting the voltage from the ADC but end up with something strange when writing to the LCD.

Been searching all day on the net to try and figure this one out.

So 622 * 4.76 / 1024 should be 2.89

Actually as I write this, and do it with a calculator the result is "2.891328125" could it be I am not allowing enough space in WX and its wrapping around?

On the LCD I get "V=2.XX" the two XX being garbled characters.

Am using AVR-GCC with winAVR.

```
VOLtage = (ADCvalue * 4.76) / 1024;

char WX[20];

itoa(VOLtage, WX, 10);
lcd_gotoxy(10,1);
lcd_puts("V=");

lcd_putc(WX[0]);
lcd_putc('.');
lcd_putc(WX[1]);
lcd_putc(WX[2]);
lcd_puts("  ");

```

Also if I try it this way I get compiler errors:

```   VOLtage=(ADCvalue * 4.76) / 1024;
sprintf(WX,"%.2f    ",VOLtage);
```

if VOLtage is an integer then the result of (622 * 4.76) / 1024 is indeed 2. I suspect the garbled characters are a result of WX[1] & WX[2] being empty/undefined.

What compiler errors do you get exactly?

maximax wrote:
if VOLtage is an integer then the result of (622 * 4.76) / 1024 is indeed 2. I suspect the garbled characters are a result of WX[1] & WX[2] being empty/undefined.

What compiler errors do you get exactly?

If I do it with sprintf I get these errors.

Build started 30.8.2011 at 23:00:25
avr-gcc -mmcu=atmega128 -Wall -gdwarf-2 -std=gnu99 -DF_CPU=16000000UL -Os -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums -MD -MP -MT test_lcd.o -MF dep/test_lcd.o.d -c ../test_lcd.c
avr-gcc -mmcu=atmega128 -Wall -gdwarf-2 -std=gnu99 -DF_CPU=16000000UL -Os -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums -MD -MP -MT lcd.o -MF dep/lcd.o.d -c ../lcd.c
avr-gcc -mmcu=atmega128 -Wl,-Map=test_lcd.map test_lcd.o lcd.o -o test_lcd.elf
c:/winavr-20100110/bin/../lib/gcc/avr/4.3.3/../../../../avr/lib/avr51\libc.a(inverse.o): In function `inverse':
(.text.avr-libc.fplib+0xc): relocation truncated to fit: R_AVR_13_PCREL against symbol `__divsf3' defined in .text section in c:/winavr-20100110/bin/../lib/gcc/avr/4.3.3/avr51\libgcc.a(_div_sf.o)
c:/winavr-20100110/bin/../lib/gcc/avr/4.3.3/../../../../avr/lib/avr51\libc.a(modf.o): In function `modff':
(.text.avr-libc.fplib+0x3e): relocation truncated to fit: R_AVR_13_PCREL against symbol `__subsf3' defined in .text section in c:/winavr-20100110/bin/../lib/gcc/avr/4.3.3/avr51\libgcc.a(_addsub_sf.o)
make: *** [test_lcd.elf] Error 1
Build failed with 1 errors and 0 warnings...

Hi Maximax, VOLtage was indeed an int so I tried a float and still get the same problem.

I get V2. and two characters that look like palm trees, so I think you are spot on about the 2.XX so its likely the 2.89088908 as an example is not getting loaded into WX as 289088908 which I would expect.

Quote:

if VOLtage is an integer then the result of (622 * 4.76) / 1024 is indeed 2. I suspect the garbled characters are a result of WX[1] & WX[2] being empty/undefined.

My palm trees instead of digits, see attached photo.

## Attachment(s):

lasershows wrote:
so I tried a float and still get the same problem.

if you mean the first example, itoa does not accept a float, only int!

What happens if you use sprintf with the float?

maximax wrote:
lasershows wrote:
so I tried a float and still get the same problem.

if you mean the first example, itoa does not accept a float, only int!

What happens if you use sprintf with the float?

I get ../test_lcd.c:123: warning: format '%.2f' expects type 'double', but argument 3 has type 'float'

If I change it to double I get the same compile errors as above.

Am just wondering something could it be the AVR-GCC and WInavr are not supporting these directives in sprintf

AVR-GCC 4.18.684
WIN-AVR 20100110

Are these old?

lasershows wrote:
Am just wondering something could it be the AVR-GCC and WInavr are not supporting these directives in sprintf

I will have to leave that one to the pros, but here is an alternative that does not involve the use of floating point math.
Off the top of my head and untested!

```long VOLtage = (ADCvalue * 476) / 1024;

char WX[20];
itoa(VOLtage, WX, 10);

lcd_gotoxy(10,1);
lcd_puts("V=");
lcd_putc(WX[0]);
lcd_putc('.');
lcd_putc(WX[1]);
lcd_putc(WX[2]);

```

maximax wrote:
lasershows wrote:
Am just wondering something could it be the AVR-GCC and WInavr are not supporting these directives in sprintf

I will have to leave that one to the pros, but here is an alternative that does not involve the use of floating point math.
Off the top of my head and untested!

```long VOLtage = (ADCvalue * 476) / 1024;

char WX[20];
itoa(VOLtage, WX, 10);

lcd_gotoxy(10,1);
lcd_puts("V=");
lcd_putc(WX[0]);
lcd_putc('.');
lcd_putc(WX[1]);
lcd_putc(WX[2]);

```

I have to hand it to you, untested, it works like that after testing here. Amazing that a a different way of looking at it solves it in an instant. Knowledge is power.

Thanks a lot for your time to look. Now I can know for sure what I am testing is right or not and move forward with the rest of it.

I would buy you a beer if it was so possible.

I think there are 3 versions of which printf to use in the link params in the makefile, and the default is 'dont link in the floating point print stuff', so you need to uncomment that one and comment the one that is uncommented out. The imagecraft compiler has a check box in the compile options dialog for this.

Imagecraft compiler user

Hi Guys,

Finally, a result.

Attached photo showing the figures.

Its a little flickery between the last digit but will add some stabilization to smooth it all out. Checked the results with a precision temp sensor and am about a little out but that should be improvable with tweaking.

Am getting 0.01 changes by blowing on the thermistor.

## Attachment(s):

Glad to hear you got it working :D

Regarding the tweaking, I am still rather curious about the 4.76V reference. I think part of your OP (and other questions) have not been answered fully.

Personally I would try to use the internal band gap reference if at all possible and use a look-up table (LUT) rather than all that foating point stuff (not sure if that was what Bob hinted at earlier)
I have been involved in a similar project myself, not thermistors but thermocouples, and had success with this approach as compared to a calibrated (testo) digital thermometer at different ambient temps.

Best of luck with your endeavours.

maximax wrote:
Glad to hear you got it working :D

Regarding the tweaking, I am still rather curious about the 4.76V reference. I think part of your OP (and other questions) have not been answered fully.

Personally I would try to use the internal band gap reference if at all possible and use a look-up table (LUT) rather than all that foating point stuff (not sure if that was what Bob hinted at earlier)
I have been involved in a similar project myself, not thermistors but thermocouples, and had success with this approach as compared to a calibrated (testo) digital thermometer at different ambient temps.

Best of luck with your endeavours.

What I wanted to do was get to this point then improve something that is kind of functional. Its kind of now so can be improved. The 4.76v was DMM measured to put into the calculations. I understand there is some way to measure the VCC of an atmel so will look at that soon so it can keep itself upto date.