## How can I conver NTC voltage output to Celcius ?

15 posts / 0 new
Author
Message

Guys,

Now I'm gonna change to NTC,

How can I convert the voltage output from NTC to Celcius ?

Thanks

The conversion is not straight forward because NTC thermistors are very nonlinear (resistance vs temperature).

Standard methods are described here:

http://en.wikipedia.org/wiki/The...

Yes, it involves floating point math with transcendental functions.

Jim

Until Black Lives Matter, we do not have "All Lives Matter"!

ka7ehk wrote:
The conversion is not straight forward because NTC thermistors are very nonlinear (resistance vs temperature).

Standard methods are described here:

http://en.wikipedia.org/wiki/The...

Yes, it involves floating point math with transcendental functions.

Jim

any ideas / clues for a library for NTC ?
thanks

```//------------------ntc stuff------------------------
//      1030           4K-400
// +5---/\/\/\----+---\/\/\/\/\---+
//      rref      |      NTC      |
//                vout		       gnd

#if 0
__flash float a=1.663443e-3; //3k duralast chevy temp sensor from autozone
__flash float b=1.849225e-4;
__flash float c=5.42688e-8;
#endif

#if 0
__flash float a=1.28745e-3; //5k epcos temp sensor
__flash float b=2.357394e-4;
__flash float c=9.5052e-8;
#endif

#if 0
__flash float a=2.22348e-3; //MGB  810 ohm temperature sender
__flash float b=3.965e-5;
__flash float c=2.6583e-6;
#endif

#if 0
float a=1.778139e-3; //wells mfg tu165 from autozone \$9.99
float b=1.511277e-4;
float c=9.472924e-7;
#endif

float ntcvsm; //v smoothed
float ntcrsm; //r smoothed
float ntci;   //current thru thermistor
float ntcdegc;
float ntcdegf;
//----------------------
void calcntctemp(void){
//calc temp from ntc thermistor on pin8 or pin10?
//steinhart eqn: 1/T= a+ b(LnR)+c(LnR)^3
//20 fp ops + a log   takes 2ms
float ntcv;   //v across thermister
float ntcr;   //r of thermistor
float lnr;    //ln(r)
float lnrcu;  //ln(r)^3
float tk;     //kelvin
float oneovertk;

ntcvsm = ntcvsm + .125*(ntcv-ntcvsm); //ntcv smoothed over 8 readings
ntci=(vref - ntcvsm)/rref;  //amps thru thermistor
ntcr=ntcvsm/ntci;           //ohms of thermistor
ntcrsm=ntcrsm + .125*(ntcr - ntcrsm); //ntcr smoothed
lnr=log(ntcrsm);            //ln of ntcr
lnrcu=lnr*lnr*lnr;          //ln ntcr cubed
oneovertk=ntca + ntcb*lnr + ntcc*lnrcu; //the Steinhart equation!
tk=1.0/oneovertk;           //deg in K
ntcdegc=tk-273.15;          //deg C
ntcdegf=1.8*ntcdegc + 32.0; //deg F
}

//-------------------------
void ntcloop(void){
//read ntc on a/d ch 0
//2ms
char c;
unsigned int n;

cprintf("ntc thermistor\n");
n=1000;
while(n--){    //took 2sec
calcntctemp();
}
cprintf("ad  degc   degf   v      a      r   q=quit\n");
while(c != 'q'){
if(kbhit()){
c=getchar();
}
calcntctemp();
cprintf("%03x %#6.1f %#6.1f %#6.3f %#6.4f %#6.1f \r",
delnms(10);
}
}
```

Imagecraft compiler user

```//------------------ntc stuff------------------------
//      1030           4K-400
// +5---/\/\/\----+---\/\/\/\/\---+
//      rref      |      NTC      |
//                vout		       gnd

#if 0
__flash float a=1.663443e-3; //3k duralast chevy temp sensor from autozone
__flash float b=1.849225e-4;
__flash float c=5.42688e-8;
#endif

#if 0
__flash float a=1.28745e-3; //5k epcos temp sensor
__flash float b=2.357394e-4;
__flash float c=9.5052e-8;
#endif

#if 0
__flash float a=2.22348e-3; //MGB  810 ohm temperature sender
__flash float b=3.965e-5;
__flash float c=2.6583e-6;
#endif

#if 0
float a=1.778139e-3; //wells mfg tu165 from autozone \$9.99
float b=1.511277e-4;
float c=9.472924e-7;
#endif

float ntcvsm; //v smoothed
float ntcrsm; //r smoothed
float ntci;   //current thru thermistor
float ntcdegc;
float ntcdegf;
//----------------------
void calcntctemp(void){
//calc temp from ntc thermistor on pin8 or pin10?
//steinhart eqn: 1/T= a+ b(LnR)+c(LnR)^3
//20 fp ops + a log   takes 2ms
float ntcv;   //v across thermister
float ntcr;   //r of thermistor
float lnr;    //ln(r)
float lnrcu;  //ln(r)^3
float tk;     //kelvin
float oneovertk;

ntcvsm = ntcvsm + .125*(ntcv-ntcvsm); //ntcv smoothed over 8 readings
ntci=(vref - ntcvsm)/rref;  //amps thru thermistor
ntcr=ntcvsm/ntci;           //ohms of thermistor
ntcrsm=ntcrsm + .125*(ntcr - ntcrsm); //ntcr smoothed
lnr=log(ntcrsm);            //ln of ntcr
lnrcu=lnr*lnr*lnr;          //ln ntcr cubed
oneovertk=ntca + ntcb*lnr + ntcc*lnrcu; //the Steinhart equation!
tk=1.0/oneovertk;           //deg in K
ntcdegc=tk-273.15;          //deg C
ntcdegf=1.8*ntcdegc + 32.0; //deg F
}

//-------------------------
void ntcloop(void){
//read ntc on a/d ch 0
//2ms
char c;
unsigned int n;

cprintf("ntc thermistor\n");
n=1000;
while(n--){    //took 2sec
calcntctemp();
}
cprintf("ad  degc   degf   v      a      r   q=quit\n");
while(c != 'q'){
if(kbhit()){
c=getchar();
}
calcntctemp();
cprintf("%03x %#6.1f %#6.1f %#6.3f %#6.4f %#6.1f \r",
delnms(10);
}
}
```

Imagecraft compiler user

Thanks bob ;)

Here's the function I have used :

```double ntc_getSH(long adcresistence, double A, double B, double C)
{
// use the Steinhart-Hart Thermistor Equation
// temperature (Kelvin) = 1 / (A + B*ln(R) + C*(ln(R)^3))
double t;
t = 1 / (A + (B * t) + (C * t * t * t));
t = t - 273.15; // convert Kelvin to Celcius
//t = (t * 9.0) / 5.0 + 32.0; // convert Celcius to Fahrenheit
return t;
}```
```main()

char volts[50];
char tempCelcius[50];
double d;

{
lcd_string(volts);
_delay_ms(2000);
//measure temperature
lcd_cmd(0x80);//put the cursor into the first row
_delay_ms (10);
lcd_cmd(0x01);//Clear display
d = ntc_getSH(adcresistance, (double)0.947070725e-3, (double)2.450662058e-4, (double)1.853992838e-7);
sprintf(tempCelcius,"temp=%.5f C",d);
//display temp to LCD
lcd_string("Temp Value");
lcd_cmd(0xC0);//goto second row
//lcd_string("Value of PF0");
_delay_ms(1000);
lcd_string(tempCelcius);
_delay_ms(1000);
}
else
{
lcd_string("No Result!");
_delay_ms(2000);
}

Does anyone know why I get "nan" value on temperature ?
Did I miss something here ?

thanks

I don't know which Compiler you are using.
I suggest that you use double or float consistently.

Personally, I would just use double. Then if I use a compiler with real 64-bit doubles, the code would work the same as on a "32-bit double" system. e.g. I would tell printf() to use the "lf" format.

Incidentally you don't need to cast the f-p constant arguments as double. The ntc_getSH() forward declaration should ensure the correct argument types are used. When you use inappropriate casts, you remove the Compiler's type consistency checking.

Your code 'looks' ok to me. However, I have no idea what values you are using. Trace the calculation in the Simulator. You need some pretty extreme values to get a f-p NaN.

David.

One detail. You have

`adcresistance = (long)((long)(1023*10000)/adc_result-10000); `

The inner expression "1023*10000" is int*int and will overflow (and later converted to a long). Either move in the nearest (long) or write 10230000 or 1023L*10000 or remove the inner pair of parenthesis.

Make a look up table with ADC in and deg. out.
Calc. the table in excel or a similar program.
If it gets to big with all values, then make 32 or so entries with value, and coefficient , then the math can be done by interpolation in simple integer.

snigelen wrote:
One detail. You have
`adcresistance = (long)((long)(1023*10000)/adc_result-10000); `

The inner expression "1023*10000" is int*int and will overflow (and later converted to a long). Either move in the nearest (long) or write 10230000 or 1023L*10000 or remove the inner pair of parenthesis.

I see, thanks for your suggestion.

snigelen wrote:
One detail. You have
`adcresistance = (long)((long)(1023*10000)/adc_result-10000); `

The inner expression "1023*10000" is int*int and will overflow (and later converted to a long). Either move in the nearest (long) or write 10230000 or 1023L*10000 or remove the inner pair of parenthesis.

becoming like this ?

`adcresistance = (long)(10230000/adc_result-10000);`

it works, but strangely, when I tested it, the temperature should go up, but displaying go down, is it because I put the resistor in reverse ??
thanks

I would agree that interpolation with integers is the fastest and most efficient method.

OTOH, human display on LCDs really don't need to be fast. So I would just "tidy up" the code and take snigelen's advice :

```   char volts[50];
char tempCelcius[50];
double d;

{
lcd_string(volts);
...
// I don't understand YOUR expression
// surely R = V / I
d = ntc_getSH(adcresistance, 0.947070725e-3, 2.450662058e-4, 1.853992838e-7);
sprintf(tempCelcius, "temp=%.5lf C", d);
//display temp to LCD
```

Personally, I would choose names like volts or millivolts for your f-p variables. The display string representation might be volt_string.