ADC Reading conversion to NTC temperature

Hello,
Is this viable as a conversion method from ADC reading to NTC thermistor temperature?
I'm using the Beta factor to convert it.

float rawTempToActual(int raw) {
  adcVoltage = rawTemp * (3.3/4096);
  thermistorResistance = -((adcVoltage * 10000) / (adcVoltage - 3.3)); //for 10k R1 in series with thermistor and connected to 3.3V reference voltage
  actualTemp = 1 / ((log(thermistorResistance / 10000) / 3435) + (1 / 298.15)); //for a thermistor with Beta 3435K, 10kohm @ 25°C
  return actualTemp;
}

Now, I haven't actually tested this, but all of the calculations are based off of known and proven equations. Made for a thermistor with Beta of 3435K, 10kohm @ 25°C, reference voltage of 3.3V, 10k resistor connected between 3.3V and the thermistor, and a 12bit ADC.

Don't need to tell me it'll be slow, I know that.

Thanks for any input!

what the minus in front ?

what's the types of the various variables ?

if you want Celsius, the formula should read
float actualTemp = 1.0 / ((log(thermistorResistance / 10000.0) / 3435.0) + (1.0 / 298.15)) - 273.15;

there are some points in your code where you can replace divisions with multiplications.
(assuming raw == rawTemp)

float rawTempToActual(int rawTemp) 
{
  adcVoltage = rawTemp * (3.3/4096.0);
  thermistorResistance = -((adcVoltage * 10000.0) / (adcVoltage - 3.3));
  actualTemp = 1.0 / ((log(thermistorResistance * 0.0001) * (1.0 / 3435) ) + (1.0 / 298.15));
  return actualTemp;
}

Furthermore you could have a look at my multimap library, that approximates conversions with interpolation. Could be more performant (and depending on number of points less accurate but accurate enough).

The - in front is required for the calculation. If you look at the divisor in the equation, it comes out negative, which would mean the entire equation would come out negative in the end. The intended output is Kelvin, so that checks out, I guess.

Interesting, thank you! I'll take a look. The performance isn't really that important, I mean, if the calculation takes 10ms, that's okay. Its not a time or performance critical application.

1 Like

ah right, you could have written (3.3 - adcVoltage) then :slight_smile:

A quick test on AVR shows replacing divisions with multiplications as above
(including the minus optimization)
reduces from 312 => 284 micros, so ~10%

note the log function takes ~172 micros so (~60% of the time).


Checked, my multimap lib has an NTC example (Celsius but OK).

oh, yes. Guess I wasn't paying attention when I was making the equation. Thanks!

Yeah, that is absolutely no problem. How can I do these calculations? Some kind of a simulator?

Always have an UNO R3 besides my laptop for development and testing.

1 Like

How do you measure the time tho?

//    FILE: .ino
//  AUTHOR: Rob Tillaart
// VERSION: 0.2.0
//    DATE: 
// PURPOSE: 
//     URL: 

#include "Arduino.h"

uint32_t start, stop;

volatile int x = 125;
volatile float f;

void setup() 
{
  Serial.begin(115200);
  while(!Serial);
  Serial.println(__FILE__);
  delay(100);

  x = analogRead(A0);
  
  start = micros();
  f = rawTempToActual1(x);
  stop = micros();
  Serial.println(stop - start);
  Serial.println(f, 6);
  delay(10);

  start = micros();
  f = rawTempToActual2(x);
  stop = micros();
  Serial.println(stop - start);
  Serial.println(f, 6);
  delay(10);

  start = micros();
  f = rawTempToActual3(x);
  stop = micros();
  Serial.println(stop - start);
  Serial.println(f, 6);
  delay(10);
}

void loop()
{


}


float rawTempToActual3(int rawTemp) 
{
  float adcVoltage = rawTemp * (3.3/4096.0);
  float thermistorResistance = ((adcVoltage) / (3.3 - adcVoltage));
  float actualTemp = 1.0 / ((log(thermistorResistance) * (1.0 / 3435) ) + (1.0 / 298.15));
  return actualTemp;
}


float rawTempToActual2(int rawTemp) 
{
  float adcVoltage = rawTemp * (3.3/4096.0);
  float thermistorResistance = -((adcVoltage * 10000.0) / (adcVoltage - 3.3));
  float actualTemp = 1.0 / ((log(thermistorResistance * 0.0001) * (1.0 / 3435) ) + (1.0 / 298.15));
  return actualTemp;
}

float rawTempToActual1(int rawTemp)
{
  float adcVoltage = rawTemp * (3.3/4096);
  float thermistorResistance = -((adcVoltage * 10000) / (adcVoltage - 3.3)); //for 10k R1 in series with thermistor and connected to 3.3V reference voltage
  float actualTemp = 1 / ((log(thermistorResistance / 10000) / 3435) + (1 / 298.15)); //for a thermistor with Beta 3435K, 10kohm @ 25°C
  return actualTemp;
}

// -- END OF FILE --

Added delays between the tests so the measurements are more accurate

output:
sketch_nov21c.ino
328
364.595642
288
364.595642
264
364.595642

So 328 => 264 == ~20% improvement.

How many decimal places do you need in the calculated temperature? A pre-calculated lookup table would be the fastest method.

I don't really need it to be fast. It would be good if it was a continuously calculated value tho.

Looks like you have a 12-bit ADC, and the ADC input value with a thermistor will be only a portion of that, so there is a limited number of possible temperatures produced by the equation. If the is no other need for floating point numbers, a lookup table might take less memory than the code needed for floating point calculations.

I'm using an STM32F411CEU6 Blackpill board, so my current code only takes a few % of the flash and RAM. And there's a whole lot more code that just this funtion.