Arduino temperature readings does not match thermometers

Hello everybody,

I made a thermometer for my school project using a arduino uno and some other components (lmt86, 2N7000, resistors, buzzer, buttons). My problem lies in the code (I think).
I have 2 thermometers from the same brand. When I compare the readings from my arduino and from the thermometers it is quite different (right it sits at 25.1C for arduino and 27.7C & 27.8C for the thermometers).

Temperature in Celsius: 25.10 °C
SensorValue: 375.00
Temperature in Celsius: 25.10 °C
SensorValue: 374.00
Temperature in Celsius: 25.50 °C
SensorValue: 376.00
Temperature in Celsius: 24.60 °C
SensorValue: 374.00
Temperature in Celsius: 25.50 °C
SensorValue: 375.00
Temperature in Celsius: 25.10 °C
SensorValue: 374.00
Temperature in Celsius: 25.50 °C
SensorValue: 376.00
Temperature in Celsius: 24.60 °C
SensorValue: 374.00
Temperature in Celsius: 25.50 °C

I was wondering if someone could help me find something wrong with my code.
this is the snippet that calculates the degrees Celsius or Fahrenheit.

//For serial command
void Stemp(){
  if(serial == "cel"){
     sensorValue = analogRead(LMT86); //read value of analogpin
     Serial.print("SensorValue: ");
     Serial.println(sensorValue);
     float voltageC = (sensorValue*5/1024.0);
     voltageC *= 1000;
     //Temp_C_or_F = voltageC - 2100; // 2100 comes from datasheet and is mV when 0 °C
     //Temp_C_or_F = Temp_C_or_F*50; // 50 is the max range (0 to 50 °C) and -442 is mV from T1 - mv from T2
     //Temp_C_or_F = Temp_C_or_F/(-442.0);

     Temp_C_or_F = sqrt(pow(-10.888,2) + 4*0.00347*(1777.3 - voltageC));
     Temp_C_or_F = (10.888 - Temp_C_or_F)/(2*-0.00347); 
     Temp_C_or_F = Temp_C_or_F + 30;
     Temp_C_or_F = round(Temp_C_or_F * 10);
     Temp_C_or_F = Temp_C_or_F/10;
     ptimeC = ctimeC;

     number(Temp_C_or_F);
     Serial.print("Temperature in Celsius: ");
     Serial.print(Temp_C_or_F);
     Serial.println(" °C");
  }
  else if(serial == "fahr"){
     sensorValue = analogRead(LMT86); //read value of analogpin
     Serial.print("SensorValue: ");
     Serial.println(sensorValue);
     float voltageF = (sensorValue*5/1024.0);
     voltageF *= 1000;
     //Temp_C_or_F = voltageF - 2100;
     //Temp_C_or_F = Temp_C_or_F*50;
     //Temp_C_or_F = Temp_C_or_F/(-442.0);
     Temp_C_or_F = sqrt(pow(-10.888,2) + 4*0.00347*(1777.3 - voltageF));
     Temp_C_or_F = (10.888 - Temp_C_or_F)/(2*-0.00347); 
     Temp_C_or_F = Temp_C_or_F + 30;
     Temp_C_or_F = (Temp_C_or_F*9/5) + 32;
     Temp_C_or_F = round(Temp_C_or_F*10);
     Temp_C_or_F = Temp_C_or_F/10;
     ptimeF = ctimeF;

     number(Temp_C_or_F);
     Serial.print("Temperature in Fahrenheit: ");
     Serial.print(Temp_C_or_F);
     Serial.println(" °F");
  }
}

//For manual command
void celsius(){
  ctimeC = millis();
  if(ctimeC - ptimeC >= debounceDuration){
    sensorValue = analogRead(LMT86) - 5; //read value of analogpin
    Serial.print("SensorValue: ");
     Serial.println(sensorValue);
    float voltageC = (sensorValue*5/1024.0);
    voltageC *= 1000;
    //Temp_C_or_F = voltageC - 2100; // 2100 comes from datasheet and is mV when 0 °C
    //Temp_C_or_F = Temp_C_or_F*50; // 50 is the max range (0 to 50 °C) and -442 is mV from T1 - mv from T2
    //Temp_C_or_F = Temp_C_or_F/(-442.0);

    Temp_C_or_F = sqrt(pow(-10.888,2) + 4*0.00347*(1777.3 - voltageC));
    Temp_C_or_F = (10.888 - Temp_C_or_F)/(2*-0.00347); 
    Temp_C_or_F = Temp_C_or_F + 30;
    Temp_C_or_F = round(Temp_C_or_F * 10);
    Temp_C_or_F = Temp_C_or_F/10;
    ptimeC = ctimeC;

    number(Temp_C_or_F);
    Serial.print("Temperature in Celsius: ");
    Serial.print(Temp_C_or_F);
    Serial.println(" °C");
  }
}

void fahrenheit(){
  ctimeF = millis();
  if(ctimeF - ptimeF >= debounceDuration){
    sensorValue = analogRead(LMT86) - 5; //read value of analogpin
    Serial.print("SensorValue: ");
     Serial.println(sensorValue);
    float voltageF = (sensorValue*5/1024.0);
    voltageF *= 1000;
    //Temp_C_or_F = voltageF - 2100;
    //Temp_C_or_F = Temp_C_or_F*50;
    //Temp_C_or_F = Temp_C_or_F/(-442.0);
    Temp_C_or_F = sqrt(pow(-10.888,2) + 4*0.00347*(1777.3 - voltageF));
    Temp_C_or_F = (10.888 - Temp_C_or_F)/(2*-0.00347); 
    Temp_C_or_F = Temp_C_or_F + 30;
    Temp_C_or_F = (Temp_C_or_F*9/5) + 32;
    Temp_C_or_F = round(Temp_C_or_F*10);
    Temp_C_or_F = Temp_C_or_F/10;
    ptimeF = ctimeF;

    number(Temp_C_or_F);
    Serial.print("Temperature in Fahrenheit: ");
    Serial.print(Temp_C_or_F);
    Serial.println(" °F");
}
}

this is the complete code (quite long)

unsigned long ctimeS;
unsigned long ptimeS = 0;
int timeS = 5;
String serial;
#include <string.h>
//leds 7 segment display 
#define A 7
#define B 6
#define C 4
#define D 3
#define E 2
#define F 8
#define G 9
#define Dp 5

//7 segment displays
#define display1 10
#define display2 11
#define display3 13
int h;

//buttons
#define change A5
bool Change = true;
int counterCF = 0;
#define plus A3
bool Plus = false;
#define min A2
bool Min = false;
#define buzzer A1
bool Buzzer = false;
float buzzT = 10.0;
//temps
float Serial_Temp_C, Passing_Temp, Temp_C_or_F, Temp, NUM, x, BuzzT;

//time
unsigned long ctime, ptime = 0, ctimeC, ptimeC = 0, ctimeF, ptimeF = 0;

//sensor
#define LMT86 A0
float sensorValue;

//serial
int ScounterCF = 0; //counter for switch from celsius to fahreneheit and opposite

//debouncing
unsigned long const debounceDuration = 500; //interval

void setup() {
  // put your setup code here, to run once:
  //Leds segment display
  Serial.begin(9600);
  Serial.setTimeout(10); //this will stop everything in serial to give you, and check, the infromation
  pinMode(A, OUTPUT);
  pinMode(B, OUTPUT);
  pinMode(C, OUTPUT);
  pinMode(D, OUTPUT);
  pinMode(E, OUTPUT);
  pinMode(F, OUTPUT);
  pinMode(G, OUTPUT);
  pinMode(Dp, OUTPUT);

  //Buttons
  pinMode(change, INPUT);
  pinMode(plus, INPUT);
  pinMode(min, INPUT);
  pinMode(buzzer, INPUT);

  //displays
  pinMode(display1, OUTPUT);
  pinMode(display2, OUTPUT);
  pinMode(display3, OUTPUT);

  celsius();
}

void loop() {
  // put your main code here, to run repeatedly:
  Passing_Temp = Temp_C_or_F;
  BuzzT = buzzT;
  if(Change == true){
    if(ScounterCF%2 == 0){
      celsius();
    }
    else if(ScounterCF%2 == 1){
      fahrenheit();
    }
  }
  buttons();
  which();
  tone();

  if(Serial.available() > 0){ //if number of bytes is greater than 0 read the string
  serial = Serial.readStringUntil("\n");
  serial.trim();
  Serial.println(serial);
  serial.toLowerCase();
  if(serial == "cel"){
  //Celsius
    Stemp();
    ScounterCF = 0;
  }
  else if(serial == "fahr"){
    //Fahrenheit
    Stemp();
    ScounterCF = 1;
  }
  else if(serial == "threshold"){
    //Switch to threshold changer
    buzzing();
  }
  else if(serial == "plus"){
    //temp +0.5
    buzzing();
  }
  else if(serial == "minus"){
    //temp -0.5
    buzzing();
  }
  else{
    Serial.println("Not a correct string. Choose from cel, fahr, threshold, plus and minus!");
  }
}
}

void buttons(){
  ctime = millis();
  if(ctime - ptime >= debounceDuration){
    if(digitalRead(change) == true){
      //change from c to f or f to c
      if(ScounterCF%2 == 0){
        celsius();
        ScounterCF++;
        ptime = ctime;
      }
      else if(ScounterCF%2 == 1){
        fahrenheit();
        ScounterCF++;
        ptime = ctime;
      }
      Change = true;
      Buzzer = false;
      Plus = false;
      Min = false;
    }
    else if(digitalRead(plus) == true){
      //increase limit +0,5 
      Change = false;
      Plus = true;
      Buzzer = true;
      number(buzzT);
      buzzing();
      ptime = ctime;
    }
    else if(digitalRead(min) == true){
      //decrease limit -0,5
      Change = false;
      Buzzer = true;
      Min = true;
      number(BuzzT);
      buzzing();
      ptime = ctime;
    }
    else if(digitalRead(buzzer) == true){
      //do something with the buzzer
      Change = false;
      Buzzer = true;
      number(BuzzT);
      buzzing();
      ptime = ctime;
    }
  }
} 

void which(){
  if (((Change == true) && (Buzzer == false)) || serial == "cel" || serial == "fahr"){
    number(Passing_Temp);
  }
  else if(((Buzzer == true) && (Change == false)) || serial == "plus" || serial == "minus" || serial == "threshold"){
    number(BuzzT);
    buzzing();
  }
}

void tone(){
  if(buzzT > Passing_Temp){
    tone(buzzer, 1000);
  }
  else{
    noTone(buzzer);
  }
}

void buzzing(){
  number(BuzzT);
  if(Plus == true || serial == "plus"){
    buzzT += 0.5;
    number(buzzT);
    Plus = false;
    serial = "threshold";
  }
  else if(Min == true || serial == "minus"){
    buzzT -= 0.5;
    number(buzzT);
    Min = false;
    serial = "threshold";
  }
  else if(Buzzer == true || serial == "threshold"){
    number(buzzT);
  }
}

//For serial command
void Stemp(){
  if(serial == "cel"){
     sensorValue = analogRead(LMT86); //read value of analogpin
     Serial.print("SensorValue: ");
     Serial.println(sensorValue);
     float voltageC = (sensorValue*5/1024.0);
     voltageC *= 1000;
     //Temp_C_or_F = voltageC - 2100; // 2100 comes from datasheet and is mV when 0 °C
     //Temp_C_or_F = Temp_C_or_F*50; // 50 is the max range (0 to 50 °C) and -442 is mV from T1 - mv from T2
     //Temp_C_or_F = Temp_C_or_F/(-442.0);

     Temp_C_or_F = sqrt(pow(-10.888,2) + 4*0.00347*(1777.3 - voltageC));
     Temp_C_or_F = (10.888 - Temp_C_or_F)/(2*-0.00347); 
     Temp_C_or_F = Temp_C_or_F + 30;
     Temp_C_or_F = round(Temp_C_or_F * 10);
     Temp_C_or_F = Temp_C_or_F/10;
     ptimeC = ctimeC;

     number(Temp_C_or_F);
     Serial.print("Temperature in Celsius: ");
     Serial.print(Temp_C_or_F);
     Serial.println(" °C");
  }
  else if(serial == "fahr"){
     sensorValue = analogRead(LMT86); //read value of analogpin
     Serial.print("SensorValue: ");
     Serial.println(sensorValue);
     float voltageF = (sensorValue*5/1024.0);
     voltageF *= 1000;
     //Temp_C_or_F = voltageF - 2100;
     //Temp_C_or_F = Temp_C_or_F*50;
     //Temp_C_or_F = Temp_C_or_F/(-442.0);
     Temp_C_or_F = sqrt(pow(-10.888,2) + 4*0.00347*(1777.3 - voltageF));
     Temp_C_or_F = (10.888 - Temp_C_or_F)/(2*-0.00347); 
     Temp_C_or_F = Temp_C_or_F + 30;
     Temp_C_or_F = (Temp_C_or_F*9/5) + 32;
     Temp_C_or_F = round(Temp_C_or_F*10);
     Temp_C_or_F = Temp_C_or_F/10;
     ptimeF = ctimeF;

     number(Temp_C_or_F);
     Serial.print("Temperature in Fahrenheit: ");
     Serial.print(Temp_C_or_F);
     Serial.println(" °F");
  }
}

//For manual command
void celsius(){
  ctimeC = millis();
  if(ctimeC - ptimeC >= debounceDuration){
    sensorValue = analogRead(LMT86) - 5; //read value of analogpin
    Serial.print("SensorValue: ");
     Serial.println(sensorValue);
    float voltageC = (sensorValue*5/1024.0);
    voltageC *= 1000;
    //Temp_C_or_F = voltageC - 2100; // 2100 comes from datasheet and is mV when 0 °C
    //Temp_C_or_F = Temp_C_or_F*50; // 50 is the max range (0 to 50 °C) and -442 is mV from T1 - mv from T2
    //Temp_C_or_F = Temp_C_or_F/(-442.0);

    Temp_C_or_F = sqrt(pow(-10.888,2) + 4*0.00347*(1777.3 - voltageC));
    Temp_C_or_F = (10.888 - Temp_C_or_F)/(2*-0.00347); 
    Temp_C_or_F = Temp_C_or_F + 30;
    Temp_C_or_F = round(Temp_C_or_F * 10);
    Temp_C_or_F = Temp_C_or_F/10;
    ptimeC = ctimeC;

    number(Temp_C_or_F);
    Serial.print("Temperature in Celsius: ");
    Serial.print(Temp_C_or_F);
    Serial.println(" °C");
  }
}

void fahrenheit(){
  ctimeF = millis();
  if(ctimeF - ptimeF >= debounceDuration){
    sensorValue = analogRead(LMT86) - 5; //read value of analogpin
    Serial.print("SensorValue: ");
     Serial.println(sensorValue);
    float voltageF = (sensorValue*5/1024.0);
    voltageF *= 1000;
    //Temp_C_or_F = voltageF - 2100;
    //Temp_C_or_F = Temp_C_or_F*50;
    //Temp_C_or_F = Temp_C_or_F/(-442.0);
    Temp_C_or_F = sqrt(pow(-10.888,2) + 4*0.00347*(1777.3 - voltageF));
    Temp_C_or_F = (10.888 - Temp_C_or_F)/(2*-0.00347); 
    Temp_C_or_F = Temp_C_or_F + 30;
    Temp_C_or_F = (Temp_C_or_F*9/5) + 32;
    Temp_C_or_F = round(Temp_C_or_F*10);
    Temp_C_or_F = Temp_C_or_F/10;
    ptimeF = ctimeF;

    number(Temp_C_or_F);
    Serial.print("Temperature in Fahrenheit: ");
    Serial.print(Temp_C_or_F);
    Serial.println(" °F");
}
}

void number(float x){
  x = x*10;
  int NUM = int(x);
  //hecto
  h = NUM/100;
  digitalWrite(display3, HIGH);
  digitalWrite(Dp, LOW);
  delay(5);
  segments(h);
  digitalWrite(display3, LOW);

  //deca
  h = (NUM%100)/10;
  digitalWrite(display1, HIGH);
  digitalWrite(Dp, LOW);
  delay(5);
  segments(h);
  digitalWrite(display1, LOW);

  //integer
  h = NUM%10;
  digitalWrite(display2, HIGH);
  digitalWrite(Dp, HIGH);
  delay(5);
  segments(h);
  digitalWrite(display2, LOW);

}

void ghost() {
  digitalWrite(A, LOW);
  digitalWrite(B, LOW);
  digitalWrite(C, LOW);
  digitalWrite(D, LOW);
  digitalWrite(E, LOW);
  digitalWrite(F, LOW);
  digitalWrite(G, LOW);  
}

void segments(int num){
  ctimeS = millis();
  if(ctimeS - ptimeS >= timeS){
    ghost();
  switch(num){
    case 0:
  digitalWrite(A, HIGH);
  digitalWrite(B, HIGH);
  digitalWrite(C, HIGH);
  digitalWrite(D, HIGH);
  digitalWrite(E, HIGH);
  digitalWrite(F, HIGH);
  digitalWrite(G, LOW);
    break;

    case 1:
  digitalWrite(A, LOW);
  digitalWrite(B, HIGH);
  digitalWrite(C, HIGH);
  digitalWrite(D, LOW);
  digitalWrite(E, LOW);
  digitalWrite(F, LOW);
  digitalWrite(G, LOW);
    break;

    case 2:
  digitalWrite(A, HIGH);
  digitalWrite(B, HIGH);
  digitalWrite(C, LOW);
  digitalWrite(D, HIGH);
  digitalWrite(E, HIGH);
  digitalWrite(F, LOW);
  digitalWrite(G, HIGH);
    break;

    case 3:
  digitalWrite(A, HIGH);
  digitalWrite(B, HIGH);
  digitalWrite(C, HIGH);
  digitalWrite(D, HIGH);
  digitalWrite(E, LOW);
  digitalWrite(F, LOW);
  digitalWrite(G, HIGH);
    break;

    case 4:
  digitalWrite(A, LOW);
  digitalWrite(B, HIGH);
  digitalWrite(C, HIGH);
  digitalWrite(D, LOW);
  digitalWrite(E, LOW);
  digitalWrite(F, HIGH);
  digitalWrite(G, HIGH);
    break;

    case 5:
  digitalWrite(A, HIGH);
  digitalWrite(B, LOW);
  digitalWrite(C, HIGH);
  digitalWrite(D, HIGH);
  digitalWrite(E, LOW);
  digitalWrite(F, HIGH);
  digitalWrite(G, HIGH);
    break;

    case 6:
  digitalWrite(A, HIGH);
  digitalWrite(B, LOW);
  digitalWrite(C, HIGH);
  digitalWrite(D, HIGH);
  digitalWrite(E, HIGH);
  digitalWrite(F, HIGH);
  digitalWrite(G, HIGH);
    break;

    case 7:
  digitalWrite(A, HIGH);
  digitalWrite(B, HIGH);
  digitalWrite(C, HIGH);
  digitalWrite(D, LOW);
  digitalWrite(E, LOW);
  digitalWrite(F, LOW);
  digitalWrite(G, LOW);
    break;

    case 8:
  digitalWrite(A, HIGH);
  digitalWrite(B, HIGH);
  digitalWrite(C, HIGH);
  digitalWrite(D, HIGH);
  digitalWrite(E, HIGH);
  digitalWrite(F, HIGH);
  digitalWrite(G, HIGH);
    break;

    case 9:
  digitalWrite(A, HIGH);
  digitalWrite(B, HIGH);
  digitalWrite(C, HIGH);
  digitalWrite(D, HIGH);
  digitalWrite(E, LOW);
  digitalWrite(F, HIGH);
  digitalWrite(G, HIGH);
    break;
  }
  ptimeS = ctimeS;
  }
}

How did you calibrate the Arduino temperature readings? If you think the thermometer readings are correct, then you MUST make calibration changes to your Arduino code.

2 Likes

All your calculations are based on the supply voltage being exactly 5V. This is unlikely to be the case.

Measure your supply voltage, and use that value instead of 5V.

3 Likes

thanks I will try it

1: You are taking a s ingle reading from the ADC - it would be much better to take and average multiple readings as explained here - to reduce the effect of noise

2: you are using some very complicated algorithms, which are not necessary in the limited temperature range

 Temp_C_or_F = sqrt(pow(-10.888,2) + 4*0.00347*(1777.3 - voltageC));
     Temp_C_or_F = (10.888 - Temp_C_or_F)/(2*-0.00347); 
     Temp_C_or_F = Temp_C_or_F + 30;
     Temp_C_or_F = round(Temp_C_or_F * 10);
     Temp_C_or_F = Temp_C_or_F/10;
     ptimeC = ctimeC;

See just above 7.4 in the data sheet

1 Like

You have to know what the accuracy or tolerance is. For cheap sensors +-20% is not uncommon, for expensive +-1%. You are about 10%, so I would consider that normal for non scientific results. If you want better, get out the chequebook.

1 Like

Yes you need to calibrate your thermometer, a 2 point calibration is ok.

  • set the termometer at temperature 1 ( it could be melting ice 0°C ) save temperature and reading from a/d
  • set the termometer at temperature 2 ( it could be boiling water 100°C ) save temperature and reading from a/d
  • Now use the map function to convert the value read from the a/d to calibrated temperature

NOTE
This calibration is needed ( as already said ) because the supply voltage of your circuit is not exactly 5V and also because the sensor itself hase some 'production tolerance' ( worst case +/-2.7°C ), this image is from the texas datasheet

lmt86a

Remember that if you are more than a couple of hundred feet above sea level you will need to do an altitude correction for the boiling point. For example if you are in Denver, CO USA the boiling point is about 10F lower. Here is a chart (yes you do have to make some changes in cooking at high altitudes).

Correct... but sorry, can't be in Denver ( to cook my spaghetti in boiling water at 100°C I should add 250g/liter of NaCl... too much for my taste ; - )

NOTE
Have to correct myself as the amount of NaCl to add is 500g/liter ( to have an increase of 5°C in boiling temperature )

thanks for your reply
But I wonder how am I supposed to do the calibration error? I checked the supply voltage and simplified the code according to the datasheet (thanks to johnerrington advice).
it is closer than before, but still not close enough.
can you please explain more in depth how to calibrate the sensor.

1 Like

How did you do that? What is the power supply - is it from the USB port? If so
"For USB 2.0 the spec says: • The voltage supplied by high-powered hub ports is 4.75 V to 5.50 V. • The voltage supplied by low-powered hub ports is 4.4 V to 5.50 V."

You can use the "secret voltmeter" to measure Vcc to ensure that the temperature readings are not affected by changes in Vcc.

The easiest way to calibrate the sensor is by comparison with an existing thermometer as its not always easy :rofl: to reproduce the conditions for "proper" standard references.

1 Like

As already explained the two point calibration is 'easy and fast' and quite good:

  • set your sensor at 'calibration temperature 1' save the calibration temperature in calTempC1 and the value read from ad in calRawAD1
  • repeat above for 'calibration temperature 2'
  • now to convert to °C a value read from the ad you simply call the mapf function:
float tempDegC = mapf(rawAD,calRawAD1,calRawAD2,calTempC1,calTempC2);
  • one line, one result, super simple, this is because there is a linear relation between the ad value read and the ( calibrated ) temperature, the map function exploits this relation for you ( if you look at the mapf function is super simple it is a 'proportion', at least in italian we call it 'proporzione' ), you don't even need to know that the sensor has a sensibility of 10.9mV/°C and bla bla bla, it's linear, it's enough

NOTE
I've seen in your code that you repeat temperature calculation/conversion in 4 different places, it is always better having a single place ( as shown in the GetTempC function ) where you do the calculation, call the function and you are done ( if you need °C ), if you need °C call a convC2F and you are ok ( you need to write this function... but I can see you are doing good )

NOTE 2
I've defined a mapf function that is more 'handy' as it returns a floating point value, but it is not needed you could have used the predefined arduino map function but...

// first cal point
float calTempC1=0;      // 0.0°C
int calRawAD1=430;

// second cal point
float calTempC2=100.0;  // 100.0°C
int calRawAD2=204;


float mapf(long x, float in_min, float in_max, float out_min, float out_max) 
  {return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;}


float GetTempC()
  {
  int rawAD = analogRead(LMT86); //read value of analogpin
  float tempDegC = mapf(rawAD,calRawAD1,calRawAD2,calTempC1,calTempC2);
  Serial.print("rawAD: ");
  Serial.print(rawAD);
  Serial.print("  tempDegC: ");
  Serial.println(tempDegC);
  return tempDegC;
  }

2 Likes

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.