DS18B20 strange measurements

Using an ESP32 based S2 mini board to interface to 3x DS18B20 in parallel

Arduino IDE

Using board 'lolin_s2_mini' from platform in folder: /home/martin/.arduino15/packages/esp32/hardware/esp32/3.3.6
Using library Preferences at version 3.3.6 in folder: /home/martin/.arduino15/packages/esp32/hardware/esp32/3.3.6/libraries/Preferences 
Using library DallasTemperature at version 4.0.5 in folder: /home/martin/Arduino/libraries/DallasTemperature 
Using library OneWire at version 2.3.8 in folder: /home/martin/Arduino/libraries/OneWire 
Using library WiFi at version 3.3.6 in folder: /home/martin/.arduino15/packages/esp32/hardware/esp32/3.3.6/libraries/WiFi 
Using library Networking at version 3.3.6 in folder: /home/martin/.arduino15/packages/esp32/hardware/esp32/3.3.6/libraries/Network 
Using library ESPmDNS at version 3.3.6 in folder: /home/martin/.arduino15/packages/esp32/hardware/esp32/3.3.6/libraries/ESPmDNS 
Using library ArduinoOTA at version 3.3.6 in folder: /home/martin/.arduino15/packages/esp32/hardware/esp32/3.3.6/libraries/ArduinoOTA 
Using library Update at version 3.3.6 in folder: /home/martin/.arduino15/packages/esp32/hardware/esp32/3.3.6/libraries/Update 
Using library espMqttClient at version 1.7.1 in folder: /home/martin/Arduino/libraries/espMqttClient-1.7.1 
Using library NetworkClientSecure at version 3.3.6 in folder: /home/martin/.arduino15/packages/esp32/hardware/esp32/3.3.6/libraries/NetworkClientSecure 
Using library Hash at version 3.3.6 in folder: /home/martin/.arduino15/packages/esp32/hardware/esp32/3.3.6/libraries/Hash 
Using library Async TCP at version 3.4.10 in folder: /home/martin/Arduino/libraries/Async_TCP 

It seems, that after some time of operation, the measurements of one of the three sensors (not always the same one) is not correct in a way that faulty measurements are not detectable automatically always.

At one event, the measurements are too low (-20°C instead of +20°C). That will be an inplausible measurement, perhaps can be "repaired" by a device reset.

Another event the readings were 8°C too high... that wrong measurement is not easy to filter by a plausibility check.

After disconnecting the ESP32 from power supply and reconnecting it, all went fine again

3-wire connection

Vcc = +5V, Gnd, DATA with pull up 3,3 kOhm to +3.3 V

It seems, that there is a newer DallasTemperature library version in Github (4.0.6 vs 4.0.5) Release notes and closed issues do not point to an issue similar to my problems ...

Some ideas?

I Googled DS18B20 and see they cost under $5. I bet an equivalent sensor that costs $100 to $500 will be much more accurate and reliable.

Another way is to use a running average algorithm. I have seen one or two but at 84 the details are not always remembered. Search the forum first as many projects use this kind of algorithm. This is also a good candidate for AI. I found 9 when I asked Google.

Could we see your code please.

1 Like

Writing outside array boundaries???
Huge industrial motor started running nearby and wires are long and not shielded???
Bad connection?
Please post pictures of your setup...
Huge hickup in mains power supply?
Memory leak?

These sensors might be cheap, but should be more accurate than 1 degC.
8 degC off means something is wrong...

Maybe browsing these documents would help.

https://www.analog.com/media/en/technical-documentation/data-sheets/DS18B20.pdf

https://www.analog.com/en/products/ds18b20.html

What is their measurement range. The standard quality classes are 20%, 10%, 5%, 1%

Both these cases look like a single bit error.
Q1: do you have pull up resistors in place?

As proposed by @sonofcy you could use a running average, but for these kind of outliers a runningMedian is far better as it is not affected by outliers.
Drawback is that the measurements do run a bit behind, how much depends on the volatility of the temperature and the size of the median window.

Search for "runningMedian library Arduino"

1 Like

Shorten and shield wires...
It is better to prevent rubbish than to clean up rubbish...

1 Like

Agree 100%

+/- 0.5ºC in the range -10ºC to +85ºC. Usable over a range of -55°C to +125°C. These sensors are accurate enough for many applications.

Unfortunately, clones or counterfeits abound.

The DS18B20 sensors are the variants with 1 meter cable

No additional cable length - The sensor cables lead all directly to the ESP32 boads GPIO-Pin..

Resistor was recently changed to 3.3 kOhm

void getTemperatures() {
  sensors.requestTemperatures(); 
    // Temperature in Celsius degrees
  Serial.print("DS18B20s:");
  for (int i=0; i<MAX_DS18B20_DEVICES; i++) {
    is_valid[i]=false;
    if (statDeviceAddress[i][6]!=0xFF) {
      float fTemp = sensors.getTempC(statDeviceAddress[i]);
      if (fTemp > DEVICE_DISCONNECTED_C) {
        temp[i] = fTemp;
        is_valid[i]=true;
      }
    }
    Serial.print(" ");
    printAddress(statDeviceAddress[i]);
    if (is_valid[i])
      Serial.print("(good");
    else
      Serial.print("(bad");
      
    if (is_valid[i] != is_old_valid[i]) {
      Serial.print("*) ");
      publishSensorState(i);
      is_old_valid[i] = is_valid[i];
#if 1        
      MQTTLogPrintf("Thermosensor[%d] %s (%02X%02X%02X%02X%02X%02X)", 
        i, 
        is_valid[i] ? "regained" : "lost",
        // statDeviceAddress[i][7], // omit crc
        statDeviceAddress[i][6], // begin serial number
        statDeviceAddress[i][5],
        statDeviceAddress[i][4],
        statDeviceAddress[i][3],
        statDeviceAddress[i][2],
        statDeviceAddress[i][1]);
        // statDeviceAddress[i][0]);  // omit family code 0x28
#endif     
    }
    else
      Serial.print(") ");
    // Temperature in Fahrenheit degrees
    //temp = sensors.getTempFByIndex(0);
    if (i==0)
    {
      avgRoomtemp(); // no respect to valid not valid....
    }
    // Publish an MQTT message on topic esp/ds18b20/temperature
    String Topic(MQTT_PUB_TEMP_PREFIX);
    Topic += TempsensRole[i];
    Topic += String(MQTT_PUB_TEMP_SUFFIX);
    if (is_valid[i] && (mqttClient.connected())) {
      uint16_t packetIdPub1 = mqttClient.publish(Topic.c_str(), 1, true, String(temp[i]).c_str());
      delay(10);                            
    }
    // Serial.printf("Publishing on topic %s at QoS 1, packetId: %i ", Topic.c_str(), packetIdPub1);
    // Serial.printf("Msg: %.2f \n", temp[i]);
  }
  Serial.println(" ");
  // DumpFreeRAM();
  DumpSysInfo();
}

What are you using for a reference, and how accurate is it?

Who did you buy them from? The ds18B20s inside could be from anywhere. If the sensors were under $5 then the chips are likely fakes.

The odds of the sensor in that assembly being, shall we say, a "free enterprise version" are depressingly high.

The sketch found at the link below will reveal the (quite likely) sorry truth:

1 Like

Yep. Adafruit have been testing theirs for authenticity since 2021 so that's a reliable source.

How do you mean in parallel?

Can you please post a copy of your circuit, a picture of a hand drawn circuit in jpg, png?
Hand drawn and photographed is perfectly acceptable.
Please include ALL hardware, power supplies, component names and pin labels.

Have you a simple bit of code that just shows this problem without all the MQTT junk around it?
In other words just reads the three sensors and outputs it on the ESP32 serial to the IDE serial monitor.
This will check if your problem is hardware or software.

Thanks... Tom.... :smiley: :+1: :coffee: :australia:

1 Like

Circuit is shown above the code ...

If I had your DS18B20's, I would hook them up to a Nano classic and test them with a basic, proven sketch.

#include <OneWire.h>

// OneWire DS18S20, DS18B20, DS1822 Temperature Example
//
// http://www.pjrc.com/teensy/td_libs_OneWire.html
//
// The DallasTemperature library can do all this work for you!
// https://github.com/milesburton/Arduino-Temperature-Control-Library

OneWire  ds(10);  // on pin 10 (a 4.7K resistor is necessary)

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

void loop(void) {
  byte i;
  byte present = 0;
  byte type_s;
  byte data[9];
  byte addr[8];
  float celsius, fahrenheit;
  
  if ( !ds.search(addr)) {
    Serial.println("No more addresses.");
    Serial.println();
    ds.reset_search();
    delay(250);
    return;
  }
  
  Serial.print("ROM =");
  for( i = 0; i < 8; i++) {
    Serial.write(' ');
    Serial.print(addr[i], HEX);
  }

  if (OneWire::crc8(addr, 7) != addr[7]) {
      Serial.println("CRC is not valid!");
      return;
  }
  Serial.println();
 
  // the first ROM byte indicates which chip
  switch (addr[0]) {
    case 0x10:
      Serial.println("  Chip = DS18S20");  // or old DS1820
      type_s = 1;
      break;
    case 0x28:
      Serial.println("  Chip = DS18B20");
      type_s = 0;
      break;
    case 0x22:
      Serial.println("  Chip = DS1822");
      type_s = 0;
      break;
    default:
      Serial.println("Device is not a DS18x20 family device.");
      return;
  } 

  ds.reset();
  ds.select(addr);
  ds.write(0x44, 1);        // start conversion, with parasite power on at the end
  
  delay(1000);     // maybe 750ms is enough, maybe not
  // we might do a ds.depower() here, but the reset will take care of it.
  
  present = ds.reset();
  ds.select(addr);    
  ds.write(0xBE);         // Read Scratchpad

  Serial.print("  Data = ");
  Serial.print(present, HEX);
  Serial.print(" ");
  for ( i = 0; i < 9; i++) {           // we need 9 bytes
    data[i] = ds.read();
    Serial.print(data[i], HEX);
    Serial.print(" ");
  }
  Serial.print(" CRC=");
  Serial.print(OneWire::crc8(data, 8), HEX);
  Serial.println();

  // Convert the data to actual temperature
  // because the result is a 16 bit signed integer, it should
  // be stored to an "int16_t" type, which is always 16 bits
  // even when compiled on a 32 bit processor.
  int16_t raw = (data[1] << 8) | data[0];
  if (type_s) {
    raw = raw << 3; // 9 bit resolution default
    if (data[7] == 0x10) {
      // "count remain" gives full 12 bit resolution
      raw = (raw & 0xFFF0) + 12 - data[6];
    }
  } else {
    byte cfg = (data[4] & 0x60);
    // at lower res, the low bits are undefined, so let's zero them
    if (cfg == 0x00) raw = raw & ~7;  // 9 bit resolution, 93.75 ms
    else if (cfg == 0x20) raw = raw & ~3; // 10 bit res, 187.5 ms
    else if (cfg == 0x40) raw = raw & ~1; // 11 bit res, 375 ms
    //// default is 12 bit resolution, 750 ms conversion time
  }
  celsius = (float)raw / 16.0;
  fahrenheit = celsius * 1.8 + 32.0;
  Serial.print("  Temperature = ");
  Serial.print(celsius);
  Serial.print(" Celsius, ");
  Serial.print(fahrenheit);
  Serial.println(" Fahrenheit");
}

DS18x20_Temperature.ino (3.0 KB)

1 Like

I am a little bit unsecure about my function requesting the temperature.

Found a hint:
Is requestTemperatures() synchronous? My code calls getTempC() directly after requestTemperatures.

Recent example found

void loop(void) { 
   sensors.requestTemperatures(); 
   
   delay(750); 
   
   float tempC = sensors.getTempCByIndex(0);
   Serial.print("Temperature: ");
   Serial.print(tempC);
   Serial.println("°C");
   delay(1000);
}

This is the one from Wiki - with no delay after requestTemperatures()

void loop(void)
{ 
  // call sensors.requestTemperatures() to issue a global temperature 
  // request to all devices on the bus
  Serial.print("Requesting temperatures...");
  sensors.requestTemperatures(); // Send the command to get temperatures
  Serial.println("DONE");
  
  Serial.print("Temperature for Device 1 is: ");
  Serial.print(sensors.getTempCByIndex(0)); // Why "byIndex"? You can have more than one IC on the same bus. 0 refers to the first IC on the wire
  
}

My code is more than 3 years in use. Recently I expanded the code for OTA updates and preferences library ....

But Version 3.7 introducing "async mode" is of 2015

I will try to use Delay(750);

Since the measurement errors are occuring quite seldom (several days of normal operation), it is not easy to get the cause....

I have checked serial numbers towards github repository about DS18B20 clones ...

3C5D04572015/28, 
3C610457DB22/28, 
3CE10457B759/28

Perhaps family G