reading coolant temperature sensor reliably

I’ve made a coolant temperature display for my car but when the radiator fans or interior fans come on the reading goes up by 15 or so degrees, making it rather unreliable…

The Arduino is powered by a cheap 12v to USB thingy and the results are displayed on a Nokia 5110 screen.
Im using the OEM sensor, which i’m assuming is a Bosch NTC M12 for now.
I’ve attached my sketch

I’ve followed the diagram on the right hand side (voltage divider & filter). I initially used the left but the temp would go up to 130 when i used my indicators!

I’m hoping someone here can shed some light on this?

temp_display.ino (2.59 KB)

The default analog reference is the Vcc of the Arduino. Any change in Vcc will affect the ADC output. Monitor Vcc with a DMM to see if it changes when the fans actuate.

Please read the "how to use this forum-please read" stickies to see how to post code. Many members will not down load code.

I see you have set Aref to EXTERNAL.
So where is the Aref pin connected to.

Is the sensor connected to ground/chassis of the car ? (one wire or two wires back to the Arduino).

pinMode(0, INPUT); // ? the TX pin on an Uno
Which Arduino are you using.
Leo…

groundFungus:
The default analog reference is the Vcc of the Arduino. Any change in Vcc will affect the ADC output. Monitor Vcc with a DMM to see if it changes when the fans actuate.

Please read the “how to use this forum-please read” stickies to see how to post code. Many members will not down load code.

I will check for change in Vcc and post results also i have posted my code better.

Wawa:
I see you have set Aref to EXTERNAL.
So where is the Aref pin connected to.

Is the sensor connected to ground/chassis of the car ? (one wire or two wires back to the Arduino).

pinMode(0, INPUT); // ? the TX pin on an Uno
Which Arduino are you using.
Leo…

The Aref is connected to the 3.3 volt line. the sensor has one wire going to it and is grounded to the block. I am using an UNO R3, i have made a little shield. see pics, hopefully this clarifies things.

I’m not sure what youre asking about “pinMode(0, INPUT); // ? the TX pin on an Uno”? I can’t see this anywhere in my code :confused:

I thought the USB voltage regulator would account for fluctuation in the cars 12-14v operating voltage and output a nice clean 5v but its not that simple…?
I based by circuit on this thread. The only difference in the first circuit diagram on this thread and mine is the diodes (which i have now ordered). Is this the solution to the problem? what is my problem? :confused:

It has taken me weeks of intermittent research and pondering to finally ask for help on here, thanks for your replies!



sensor datasheet

#include <Arduino.h>
#include <U8g2lib.h>

U8G2_PCD8544_84X48_1_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8); // Nokia 5110 Display

// which analog pin to connect
#define THERMISTORPIN A0
// how many samples to take and average, more takes longer but is more 'smooth'
#define NUMSAMPLES 10
// the value of the 'other' resistor
#define SERIESRESISTOR 330

//My Bosch Motorsport | Temperature Sensor NTC M12
// out[] holds the values wanted in cm
int out[] = {130, 120, 110, 100, 90, 80, 70, 60, 50, 40, 30, 20, 10, 0, -10, -20,};
// in[] holds the measured analogRead() values for defined distances
// note: the in array should have increasing values
int in[]  = {89, 113, 144, 187, 243, 323, 436, 596, 834, 1175, 1707, 2500, 3792, 5896, 9397, 15462};

uint16_t samples[NUMSAMPLES];

int tempC = 0;
int optostate = 1;

const int optoIN = 2;
const int backlight =12;

void setup(void) {
  analogReference(EXTERNAL);
  digitalWrite(backlight, HIGH);
  pinMode(backlight, OUTPUT);
  pinMode(optoIN, INPUT);

  u8g2.begin();
  u8g2.enableUTF8Print();
}

void loop(void) {

  uint8_t i;
  float average;
  float error = 0;

  // take N samples in a row, with a slight delay
  for (i = 0; i < NUMSAMPLES; i++) {
    samples[i] = analogRead(THERMISTORPIN);
    delay (10);
  }

  // average all the samples out
  average = 0;
  for (i = 0; i < NUMSAMPLES; i++) {
    average += samples[i];
  }
  average /= NUMSAMPLES;
  error = average;

  // convert the value to resistance
  average = 1023 / average - 1;
  average = SERIESRESISTOR / average;

  draw(tempC = multiMap(average, in, out, 16), error);

  opto(optoIN, optostate);

  delay(300);
}

void draw (int tempC, float error)
{
 u8g2.firstPage();
  do {


    if (error >= 1020)
    {

      u8g2.setFont(u8g2_font_helvB12_te);
      u8g2.setCursor(0, 13);
      u8g2.print("check ECT");
      u8g2.setFont(u8g2_font_helvB12_te);
      u8g2.setCursor(15, 28);
      u8g2.print("sensor");
      u8g2.setCursor(3, 44);
      u8g2.print("continuity");
    }
    else if (error <= 2)
    {
      u8g2.setFont(u8g2_font_helvB12_te);
      u8g2.setCursor(0, 13);
      u8g2.print("check ECT");
      u8g2.setFont(u8g2_font_helvB12_te);
      u8g2.setCursor(15, 28);
      u8g2.print("sensor");
      u8g2.setCursor(15, 44);
      u8g2.print("curcuit ");

    }
    else
    {
      u8g2.setFont(u8g2_font_helvB12_te);
      u8g2.setCursor(0, 13);
      u8g2.print("Coolant °C");
      u8g2.setFont(u8g2_font_inb33_mn);
      u8g2.setCursor(0, 47);
      u8g2.print(tempC)  ;
    }

  } while ( u8g2.nextPage() ); 
}

// note: the _in array should have increasing values
int multiMap(int val, int* _in, int* _out, uint8_t size)
{
  // take care the value is within range
  // val = constrain(val, _in[0], _in[size-1]);
  if (val <= _in[0]) return _out[0];
  if (val >= _in[size - 1]) return _out[size - 1];

  // search right interval
  uint8_t pos = 1;  // _in[0] allready tested
  while (val > _in[pos]) pos++;

  // this will handle all exact "points" in the _in array
  if (val == _in[pos]) return _out[pos];

  // interpolate in the right segment for the rest
  return (val - _in[pos - 1]) * (_out[pos] - _out[pos - 1]) / (_in[pos] - _in[pos - 1]) + _out[pos - 1];
}

void opto(int optoIN, int optostate)
{
    optostate = digitalRead(optoIN);

  if (optostate == 1)
  {
    digitalWrite(backlight, LOW);
  }
  else
  {
    digitalWrite(backlight, HIGH);
  }
}

doseph:
I'm not sure what youre asking about "pinMode(0, INPUT); // ? the TX pin on an Uno"? I can't see this anywhere in my code :confused:

It's in the .ino you attached in post#0.

You probably wanted to say
pinMode(A0, INPUT); // set the analogue pin to input
Which is a useless statement, because pins are already set to input on bootup.

Problem could be ground currents.
Currents (from the fans) create a voltage difference between block/sensor ground and Arduino ground.
That difference is added or subtracted to the sensor voltage, and gives false readings.
If possible, connect two wires to the sensor, and connect sensor ground directly to Arduino ground.
Leo..

Please explain how the opto coupler with 5V connected to the emitter works.

Good catch.

Connect the opto transistor between pin and ground, with emitter to ground. NO resistors.
Then use internal pull up on the pin.

pinMode(optoPin, INPUT_PULLUP);

The pin is now normally HIGH, and LOW when the opto LED is lit.
Leo..

Ahh ground currents would make sense!

With the opto-coupler circuit, I'm assuming my slightly backwards circuit is not affecting the sensor readings.... only one way to find out.

I'll get this sorted along with the other suggestions and post some results.

Thanks again for your help :slight_smile: