Below is some tested and robust code for accurately measuring two different automotive temperature sensors; the GM 12146312 and Stewart Warner 33..400 ohm sensors. Both of these are NTC (negative temperature coefficient) temperature-dependent resistors and require a polynomial to map resistance to temperature. This code uses the common Steinhart-Hart NTC polynomial and coefficients I found on the net.
This thread was inspired by this thread from a few years ago, now closed. There's a typo in the polynomial (misplaced paren). GM Coolant Sensor #12146312 Interface
One side of the sensor is connected to ground (The S.W. sensor body is ground) and the other to the Arduino analog input. A single resistor from the sensor/input pin to 5V or 3.3V ("pull up") is required. That's it.
My solution is slightly more complicated than what is possible but I think you'll see it's easier in the end -- I first calculate the sensor's resistance in ohms, then map that resistance to temperature (degrees F or C). The reason for this is that the fundamental calculation does not need to be changed to accommodate whatever arbitrary pull up resistance or voltage is used.
There are two subroutines; one that reads the analog pin and determines resistance, and another that converts resistance to temperature reading, given the Steinhart-Hart coefficients.
Be warned that all of these automotive sensors are not very accurate at temperatures below 100F. Engine systems are concerned with over 100F up to 300F or so; below 100, eg. room temperature, they're not very good at all. So don't let testing on the bench fool you that they're not working.
These parameters go at the top of the source and define your electrical setup. ADCFULLSCALE is typical analogRead() maximum value.
// Sensor parameters. Sensors are resistive, ground connected, and pulled
// up to (in this case) 5V with 470 ohms.
//
const float ADCFULLSCALE = 1024; // analogRead() returns 0..1023
const float SENSORPUVOLTS = 3.3; // volts
const float SENSORPUOHMS = 330; // pullup resistor
// These are the Steinhart-Hart coefficients for the two sensor types.
//
const double SWCoeffA = 0.0007350115860272266;
const double SWCoeffB = 0.00042333918838882934;
const double SWCoeffC= -2.005500370510285e-7;
const double GMCoeffA = 0.001129148;
const double GMCoeffB = 0.000234125;
const double GMCoeffC = 0.0000000876741;
This is how a Stewart-Warner 100 to 280F temperature sensor is read. Returns integer degrees F. Pin is the analog input pin number. The text is for printing debug info.
readNTCSensor (pin, "SW oil temp", SWCoeffA, SWCoeffB, SWCoeffC));
This is how a GM #12146312 temperature sensor is read. Returns integer degrees F. Pin is the analog input pin number. The text is for printing debug info.
readNTCSensor (pin, "GM coolant temp", GMCoeffA, GMCoeffB, GMCoeffC)
This is the code that does the calculation.
int readNTCSensor (int pin, const char *text, double kA, double kB, double kC) {
double Rs;
double logR2, T;
Rs= readSensor (pin);
// Steinhart-Hart NTC thermistor resistance to degrees F.
// Steinhart - Hart Equation = 1/T = A+B(LnR)+C(LnR)3
//
logR2= log (Rs);
T= 1.0 / (kA + (kB * logR2) + (kC * logR2 * logR2 * logR2));
T= T - 273.15; // K to C
T= (T * 9.0) / 5.0 + 32.0; // C to F
return T + 0.5;
}
/* read a resistive sensor pulled up with a resistor, return it's resistance, in ohms. */
int readSensor (int pin) {
int a;
float adcV, I, Rs;
// voltage at the resistor divider. if the sensor is open
// circuit, this should be the same as the reference
// voltage.
//
a= analogRead (pin);
adcV= (float)a * (SENSORPUVOLTS / ADCFULLSCALE);
// current flowing through the sensor and the pullup.
// the battery voltage is in millivolts. this won't work out
// well if the sensor is infinite ohms, hence the max (i, .0001)
//
I= fmax ((SENSORPUVOLTS - adcV) / SENSORPUOHMS, 0.0001);
// sensor R now derives from I.
//
Rs= adcV / I;
return Rs + 0.5;
}