Float help - Thermistor - Steinhart Eq

Hi,

R2 = R1 * (1023.0 / (float)Vo - 1.0);

I don't understand the use of (float) in that line.
Can somebody please explain it to me. Which float variable is it referring to?

int ThermistorPin = 0;
int Vo;
float R1 = 10000;
float logR2, R2, T;
float c1 = 1.009249522e-03, c2 = 2.378405444e-04, c3 = 2.019202697e-07;

void setup() {
Serial.begin(9600);
}

void loop() {

  Vo = analogRead(ThermistorPin);
  R2 = R1 * (1023.0 / (float)Vo - 1.0);
  logR2 = log(R2);
  T = (1.0 / (c1 + c2*logR2 + c3*logR2*logR2*logR2));
  T = T - 273.15;
  T = (T * 9.0)/ 5.0 + 32.0; 

  Serial.print("Temperature: "); 
  Serial.print(T);
  Serial.println(" F"); 

  delay(500);
}

https://www.circuitbasics.com/arduino-thermistor-temperature-sensor-tutorial/

For my version of the code:

const int OilTempPin = A0; //A0 analog pin
const int R1 = 62330; //62330 ohm Total Pull - up resistors in series that I used.
float TempK;
float Vout;
float TempC;
float R2;
float logR2;


//SteinHart Constants
const float A = 0.000686524426;
const float B = 0.000244478897;
const float C = 0.000000019057;

void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);
  Serial.print("Oil Temperature Reading:");
}

void loop() {
  // put your main code here, to run repeatedly:
  Vout = analogRead (OilTempPin);
  R2 = R1 * (1023.0 / (float)Vout - 1.0);
  logR2 = log(R2);
  TempK = 1 / (A + B * logR2 + C * logR2 * logR2 * logR2);
  TempC = TempK - 273.15;
  Serial.print("Oil Temperature:");
  Serial.println(TempC, 1); //Display temp. to 1 d.p
  Serial.println("C");


  delay(1000);`Preformatted text`
}

I'm getting nan - not a number in the serial monitor.
What am I doing wrong?
I know that my A,B,C values work when I put them into the original code.

thanks!

const int R1 = 62330; //62330 ohm Total Pull - up resistors in series that I used.

You are exceeding the maximum value for an int (32767). The compiler is setting R1 to a negative number, messing up the calculations. Might as well make it a float since the rest of the equation uses floats.

Ahh, thanks David, it works now.

That "(float)" is called a cast. It tells the compiler to convert that variable to a "float".
Sometimes it is not needed, but you can use it to tell the compiler explicitly what it should do.

This is no problem:

float a = 3.0;
float b = 3.5;
float c = a * b;

This is showing what is going on and telling the compiler what to do:

int a = 3;
float b = 3.5;
float c = (float) a * b;

This is let the compiler sort things out, and hopefully it will do what you want it to do (in this case, the compiler will do the conversion from int to float for you):

int a = 3;
float b = 3.5;
float c = a * b;

I'm trying to smoothen out my readings. My original readings of 15/16 degrees C is now 400+! What did I mess up this time?
Thanks again!

Smoothenreading

SmoothenreadingW


const int OilTempPin = A0; //A0 analog pin
float R1 = 62330; //62330 ohm Total Pull - up resistors in series that I used.
float TempK;
float Vout;
float TempC;
float R2;
float logR2;


//SteinHart Constants
const float A = 0.000686524426;
const float B = 0.000244478897;
const float C = 0.000000019057;

void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);
  Serial.print("Oil Temperature Reading:");
}

void loop() {
  // put your main code here, to run repeatedly:

//Smoothen reading
  int readno = 8; //Number of samples
  int Sensor = 0; // Sum of sensor readings
  for (int x = 0; x < readno; x++) {
    Sensor += analogRead(OilTempPin); //Add analog reading to Sensor
    delay(1);
  }
  int AvgSensor = Sensor / readno; //take the avg. reading

  Vout = analogRead (OilTempPin);
  R2 = R1 * (1023.0 / (float)Vout - 1.0);
  logR2 = log(R2);
  TempK = 1.0 / (A + B * logR2 + C * logR2 * logR2 * logR2);
  TempC = TempK - 273.15;
  Serial.print("Oil Temperature:");
  Serial.println(AvgSensor, 1); //Display temp. to 1 d.p
  Serial.println("C");


  delay(1000);
}

Follow the path of the data.

It should be:

AnalogRead -> add 8 of them -> divide by 8 for average -> calculate R2 -> calculate Kelvin -> calculate Celsius -> print Celsius.

You have:

AnalogRead -> add 8 of them -> divide by 8 for average -> print average

And on the side, you also do:

AnalogRead (no average) -> calculate R2 -> calculate Kelvin -> Calculate Celsius -> throw away Celsius

I've connected a car temperature sensor to the arduino.
It seems to work at room temperature, but I just tried applying heat to it with a hairdryer, and the readings is messed up.

SmoothenreadingW1

Any suggestions?

Thanks.

Did you change your code since the last time the code was posted? If so, post the new version so that we can keep up.

My guess is that you have an overflow somewhere. Check your data types.

No I haven't.

Then insert serial prints in between the reading and calculation steps to monitor the values.

With the equations you used in the last code you posted, an analog input value of 1023 will give the -273.1 value, so it is likely the oil sensor is not wired properly.

< edit >
This will probably get into a long discussion (generally of whether to divide the analog reading by 1023 or 1024), but it is likely the equation for R2 should be:

    R2 = R1 * (1024.0 / Vout - 1.0);

Note that since Vout is declared as a float, there is no need to cast it to a float in the equation.



float TempCelsius (void) {
  uint8_t i;
  float average;
  int samples[] = { 0, 0, 0, 0, 0} ;
 
  // take 5 samples in a row, with a slight delay
  for (i=0; i<5; i++) {
   samples[i] = analogRead(0);
   delay(10);
  }
 
  // average all the samples
  average = 0;
  for (i=0; i< 5; i++) {
     average += samples[i] ;
  }
  average /= 5 ;
  average = 1023 / average - 1 ;
  average = 10000.0 / average ;
  float steinhart ;
  steinhart = average / 10000.0 ;      // (R/Ro)
  steinhart = log(steinhart) ;         // ln(R/Ro)
  steinhart /= 3950.0 ;                // 1/B * ln(R/Ro)
  steinhart += 1.0 / (25.0 + 273.15) ; // + (1/To)
  steinhart = 1.0 / steinhart ;        // Invert
  steinhart -= 273.15 ;                // convert to C
  return (steinhart) ;
}

10K resistor & 10K NTC

@mrburnette The delay when taking samples is not needed to reduce electronic noise. The array is also not needed, you can calculate the total in a single variable.

This is my breadboard setup. (The front facing side)
Orange wire: 5V
Green: Signal from sensor
Black: Top right corner, from ground from sensor.
White: To Analog A0 pin.

Voltage divider/pull up setup.
This is a correct way to connect x6 10K Resistors in series?
For resistors, I went off the manufacturer's lowest temp. measurement; 62.3 K ohms.
Tried with an extra 330 ohm resistor with my 60K R setup. Didn't make a difference.
I'm guessing it is correct, I managed to get serial monitor to display my room temp. reading (slightly incorrect I guess). because when I disconnect 5V, or whenever I fiddle/nudge the wiring a bit, the -273.1 C reading pops up.

Left table is sensor specs from manufacturer/seller. Right table, is my workings of Steinhart eq.

I think actual Temp VS R readings is slightly off, as I've tested the sensor at different water temps. I'll do I full record at different water temps, and will report back.

Is your arduino earth connected to your sensor earth?
G

HI @kelvinkkong

One issue, if you're using an Arduino with an 8-bit AVR based microcontroller, such as the Uno/Nano/Mega etc..., is that these boards use only single precision floating point representation for both float and double data types.

Single precision will give you roughly 6 to 7 digits after the decimal point, but not enough to represent your A, B and C constants.

Yes, you are certainly correct. But,

I selected a 10+ year old cut-n-paste from some code stored in my sketch folder; which is to say a free-standing snippet from the old AVR UNO days. The selected piece was documented and simple ... not my usual style, so I suspect much was plagiarized. The use of an array is often requested by Ops in the forum; in this case it is perfectly clear what every step of the code does. I see no particular harm in having a few more steps added for clearity (once taught adults computer sciences) as long as the "fluff" provides insight into the process.

Answering questions in a forum is complicated because we (responders) often expect the Op to have the same knowledge and experiences that we have. But, we will lose the Op and other readers if we code like this:

$latex \displaystyle \left[ {\begin{array}{*{20}{c}} 1 & {\ln \left( {{{R}_{1}}} \right)} & {\ln {{{\left( {{{R}_{1}}} \right)}}^{3}}} \\ 1 & {\ln \left( {{{R}_{2}}} \right)} & {\ln {{{\left( {{{R}_{2}}} \right)}}^{3}}} \\ 1 & {\ln \left( {{{R}_{3}}} \right)} & {\ln {{{\left( {{{R}_{3}}} \right)}}^{3}}} \end{array}} \right]\cdot \left[ {\begin{array}{*{20}{c}} A \\ B \\ C \end{array}} \right]=\left[ {\begin{array}{*{20}{c}} {\frac{1}{{{{T}_{1}}}}} \\ {\frac{1}{{{{T}_{2}}}}} \\ {\frac{1}{{{{T}_{3}}}}} \end{array}} \right]$

Thanks for taking the time to comment as it puts the example into a better context. But, the example is complete as-is and follows a logical process, albeit with some non-essential steps.

Ray

For a solderless breadboard, the Excel looks pretty good. The exercise "brings home" how the thermistor changes affect the voltage readings at the resistor-thermistor junction - analog pin input.

My experiments many years ago showed that a quality NTC thermistor of 10K and a 1% 10K resistor gives excellent readings for room ambient temps (compared to calibrated digital thermometer. Expect deviations for high and low extremes.

I do not recommend showing decimals as the implied accuracy is not real. There are techniques that can be utilized but thermistors are not the best choice for measuring temperatures accurately.

Given the limited temperature range and fairly involved calculations, it may be better to generate a lookup table for translating the analog reading. Knowing you only want a single decimal place in the output, the temperature can be stored as an integer in tenths of a degree.

1 Like