DS18B20 reports -196.60°F when temp < 4.1°F w/ DallasTemp library only

Running an Uno with Adafruit WiFi shield, 20x4 LCD display (on I2C), a single DHT22 and two DS18B20 probes.

The DHT22 is for room temp/humidity and the two DS18B20 probes go in the refrigerator and freezer respectively.
DHT22 is on pin 2 and the DS18B20s are on pin 7.
Everything works great until the probe in the freezer goes below 4.1°F. At that point that particular probe just returns the value -196.60°F until the temp rises to 4.1 or greater again.
I tried physically swapping the probes to eliminate hardware issues, and no change. Whichever probe is in the freezer gives the -196.60 value below 4.1°F
Both DS18B20 probes are wired together, and I've tried 4.7k and 2.2k pullup resistors (+5VDC to data).
I'm using the DallasTemperature and OneWire libraries for the DS18B20.
The specs of the DS18B20 are -55°C to +125°C (-67°F to +257°F) which is well within the range of a freezer.

I'm hoping this is some strange math issue. Let me know if you have any ideas. My code is below. I've removed unrelated sections because the whole thing wouldn't fit.

Thanks!

#include <Adafruit_CC3000.h>    // WiFi stuff
#include <SPI.h>
#include "utility/debug.h"
#include "utility/socket.h"


#include <Wire.h>
#include <LiquidCrystal_I2C.h>  //LCD
#include <OneWire.h>
#include <DallasTemperature.h>  //Temp Probes
#include <DHT.h>                // DHT Temp
#define ONE_WIRE_BUS 7 // Pin for Temp Probes

#define I2C_ADDR    0x27 //Address for LCD
#define BACKLIGHT_PIN     3  //LCD Don't need this but code breaks without it
#define En_pin  2    // LCD
#define Rw_pin  1    // LCD
#define Rs_pin  0    // LCD
#define D4_pin  4    // LCD
#define D5_pin  5    // LCD
#define D6_pin  6    // LCD
#define D7_pin  7    // LCD
#define DHTPIN 2     // DHT Pin
#define DHTTYPE DHT22   // DHT 22  (AM2302)

OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire); // Pass our oneWire reference to Dallas Temperature.

DHT dht(DHTPIN, DHTTYPE);

  float probeAF;  // floating pt variables for probes in F and C
  float probeAC;
  float probeBF;
  float probeBC;

  float dhtTF;    // DHT Temp in F
  float dhtDP;    // DHT DP in C
  float dhtDPF;   // DHT DP in F
void setup()
{

  sensors.begin();
  dht.begin();
  lcd.begin(20,4);               // initialize the lcd 


  lcd.clear();
  lcd.home ();                   
  lcd.print("Room:    |REF: ");    //Line 0 Base Text
  lcd.setCursor (0, 1);
  lcd.print ("T:       |FRZ: ");   //Line 1 Base Text
  lcd.setCursor(0,2);    
  lcd.print("DP:      |");         //Line 2 Base Text
  lcd.setCursor(9,3);
  lcd.print("|");                  //Line 3 Base Text


}


void loop()
{

  sensors.requestTemperatures(); // Send the command to get PROBE temperatures

  float h = dht.readHumidity();
  float t = dht.readTemperature();
delay(1000);
dhtTF = ((t*9)/5)+32;
dhtDP = (dewPointFast(t, h));
dhtDPF= ((dhtDP*9)/5)+32;


  probeAC = (sensors.getTempCByIndex(0)); // Get 1st probe temp
  probeBC = (sensors.getTempCByIndex(1)); // Get 2nd probe temp
  
  probeAF = probeAC * 1.8 + 32.0;
  probeBF = probeBC * 1.8 + 32.0;
  
  lcd.setCursor(15,0);
  lcd.print(probeBF);  // Refrigerator Temp
  lcd.setCursor(19,0);
  lcd.print(char(223));// Degree Symbol
  lcd.setCursor(15,1);
  lcd.print(probeAF);  // Freezer Temp
  lcd.setCursor(19,1);
  lcd.print(char(223));

  lcd.setCursor(3,1);  // Room Temp and DP
  lcd.print(dhtTF);
  lcd.setCursor(8,1);
  lcd.print(char(223));
  lcd.setCursor(3,2);
  lcd.print(dhtDPF);
  lcd.setCursor(8,2);
  lcd.print(char(223));
  

}

double dewPointFast(double celsius, double humidity)
{
 double a = 17.271;
 double b = 237.7;
 double temp = (a * celsius) / (b + celsius) + log(humidity*0.01);
 double Td = (b * temp) / (a - temp);
 return Td;
}

The environment is probably outside the range for accurate reporting from the DS18B20, but that seems unreasonably inaccurate. It may have something to do with the power supply but you might try testing the probes with standard code that does nothing else first - just temperature to serial monitor.

Thanks Nick, the DS18B20 is spec'd at -55°C to +125°C (-67°F to +257°F) which is well within the range of a freezer.
But I ran the DS18x10_Temperature example from the OneWire library and it shows temps below 4.1 just fine.

So it looks now like the DallasTemp library doesn't work, however reading the DS18B20 with the OneWire library needs a huge amount of supporting code (converting from HEX, etc).

I guess that is my next project :~

Thanks again,
Rich

It would be interesting to see what's magic about that temperature. I'm speculating it's when another bit was brought into play in a variable or something like that, overflow kind of thing?

I emailed Miles Burton of the Dallas Temp Control library
http://milesburton.com/Dallas_Temperature_Control_Library

And I'll see what he has to say.

The sensor value of -196.60 equals a Celsius temperature of -127 C.
from the code DallasTemperature.h:

// Error Codes
#define DEVICE_DISCONNECTED_C -127
#define DEVICE_DISCONNECTED_F -196.6

So at your sensor gets disconnected because of the cold. You should check your wiring/soldering if it is cold resistant.
The sensor (watretight version) can handle it.

Do you use the watertight version of the DS18B20?

Rob, indeed this is the watertight probe.

Per my previous post, this only happens when using the Dallas Temp library. The OneWire test code example for DS18x20 devices returns temps just fine under 4.1 °. I'd rather not using though. because of the excessive amount of code required to convert the info from HEX.

Miles Burton responded and asked me to raise this issue on GitHub but I'm not familiar with using that site aside from reference.

If the code thinks it is disconnected, it doesn't matter which library you use.

michinyon:
If the code thinks it is disconnected, it doesn't matter which library you use.

Per my previous, previous post, this only happens when using the Dallas Temp library. The OneWire test code example for DS18x20 devices returns temps just fine under 4.1 °. I'd rather not using though. because of the excessive amount of code required to convert the info from HEX.

RichXKU:
Rob, indeed this is the watertight probe.

Per my previous post, this only happens when using the Dallas Temp library. The OneWire test code example for DS18x20 devices returns temps just fine under 4.1 °. I'd rather not using though. because of the excessive amount of code required to convert the info from HEX.

Miles Burton responded and asked me to raise this issue on GitHub but I'm not familiar with using that site aside from reference.

I've created an issue for you here - DS18B20 reports -196.60°F when temp < 4.1°F w/ DallasTemp library only · Issue #22 · milesburton/Arduino-Temperature-Control-Library · GitHub -

some note:

  • 4.1F = -15.5 C
  • -196.60 = -127 C ==> DEVICE_DISCONNECTED

I'd rather not using though. because of the excessive amount of code required to convert the info from HEX.

This doesn't make much sense. Hex is just one way of representing of a binary value. To which example are you referring, what do you need to convert and why does it take lots of code?

The code in this tutorial is compact, clearly described and works over the temperature range of the device: Arduino 1-Wire Tutorial

I've created an issue for you here - DS18B20 reports -196.60°F when temp < 4.1°F w/ DallasTemp library only · Issue #22 · milesburton/Arduino-Temperature-Control-Library · GitHub -

Thanks, Rob!

This doesn't make much sense. Hex is just one way of representing of a binary value. To which example are you referring, what do you need to convert and why does it take lots of code?

The code in this tutorial is compact, clearly described and works over the temperature range of the device: Arduino 1-Wire Tutorial

jremington: The hacktronics code uses the Dallas Temp library, which is the cause of the problem.

The DS18x20_Temperature example (below) included with OneWire.h works fine.

Is there a way to modify the code below to remove unnecessary bits and simply store the values of my 2 probes as, say, probeA and probeB?
I don't need to Serial.print anything.

#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!
// http://milesburton.com/Dallas_Temperature_Control_Library

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

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

void loop(void) {
  byte i;
  byte present = 0;
  byte type_s;
  byte data[12];
  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");
}

RichXKU:
I don't need to Serial.print anything.

So how do you find out if it is working properly?
It seems that the only thing of value in the code you list is the third line of comment, and about the only constructive thing to come out of all this is that Miles Burton hasn't actually denied there is a problem. But now, after the masterful comment from Robtillart, who actually took the trouble to convert -196.6 to celcius, you really ought to take clear steps to assure everybody that getting the problem when you use the library is not a coincidence.

I wouldn't touch that code you are using with a long shovel. You might at least weed out the junk, of which there is quite a lot but, if you really can't get along with the proper stuff, you might try this, which uses no libraries at all.

So how do you find out if it is working properly?

I'm passing the variables to an LCD and webclient.

But now, after the masterful comment from Robtillart, who actually took the trouble to convert -196.6 to celcius, you really ought to take clear steps to assure everybody that getting the problem when you use the library is not a coincidence.

I really don't see how it's a coincidence. At any temp under exactly 4.1°F the DallasTemp library causes the sensor to report that its disconnected. As soon as the temp rises to exactly 4.1°F again it starts reporting as normal.

I wouldn't touch that code you are using with a long shovel.

Why? It's the standard example included with the OneWire library. It has no glitches at any temperature, but I just need it to store in variables rather than Serial.print the values.

you might try this, which uses no libraries at all.
Using a DS18B20 Temperature sensor with an Arduino- ar3ne1tt

That's going in the complete opposite direction then. Why abandon the OneWire library if it works?

The hacktronics code, with its attendant library, works fine for me at temperatures less that 4.1 F. So, why doesn't it work for you?

RichXKU:
I'm passing the variables to an LCD and webclient.

A plain vanilla Serial.print enables you get rid of all that stuff and, right now, staying as plain vanilla as possible is a good idea.

I really don't see how it's a coincidence. At any temp under exactly 4.1°F the DallasTemp library causes the sensor to report that its disconnected. As soon as the temp rises to exactly 4.1°F again it starts reporting as normal.

I think Remmington is right, The sensor senses mechanical failure, so you really need to check that the library is involved. I recognise that you are working in exceptionally cold conditions, but the first question you need to ask is how come you are the first to have this problem.

Why? It's the standard example included with the OneWire library.

The comment therein is good advice. The rest should be clear when you read the Hacktronics tutorial already referred to.

you might try this, which uses no libraries at all.
Using a DS18B20 Temperature sensor with an Arduino- ar3ne1tt

That's going in the complete opposite direction then. Why abandon the OneWire library if it works?
[/quote]

While I have used Sheepdog, I don't really recommend it, but I submit the code is better to read than yours.

jremington:
The hacktronics code, with its attendant library, works fine for me at temperatures less that 4.1 F. So, why doesn't it work for you?

I would REALLY like to know! :frowning:

I ran the hacktronics code, modifying ONLY the hex values to reflect the values of my two probes. I commented out the 3rd variable since I only have two probes.
I noticed the hacktronics selects a different resolution for the sensors (0.25 instead of 0.5) so I had a glimmer of hope when we reached 3.65°F. However it failed below that.
So the bottom line is exactly -16°C and below causes the error.

Here is the code I used:

// This Arduino sketch reads DS18B20 "1-Wire" digital
// temperature sensors.
// Tutorial:
// http://www.hacktronics.com/Tutorials/arduino-1-wire-tutorial.html

#include <OneWire.h>
#include <DallasTemperature.h>

// Data wire is plugged into pin 7 on the Arduino
#define ONE_WIRE_BUS 7

// Setup a oneWire instance to communicate with any OneWire devices
OneWire oneWire(ONE_WIRE_BUS);

// Pass our oneWire reference to Dallas Temperature. 
DallasTemperature sensors(&oneWire);

// Assign the addresses of your 1-Wire temp sensors.
// See the tutorial on how to obtain these addresses:
// http://www.hacktronics.com/Tutorials/arduino-1-wire-address-finder.html

DeviceAddress insideThermometer = { 0x28, 0xFF, 0x21, 0xB7, 0x14, 0x14, 0x00, 0x69 };
DeviceAddress outsideThermometer = { 0x28, 0xFF, 0x00, 0xA4, 0x14, 0x14, 0x00, 0xEC };
//DeviceAddress dogHouseThermometer = { 0x28, 0x59, 0xBE, 0xDF, 0x02, 0x00, 0x00, 0x9F };

void setup(void)
{
  // start serial port
  Serial.begin(57600);
  // Start up the library
  sensors.begin();
  // set the resolution to 10 bit (good enough?)
  sensors.setResolution(insideThermometer, 10);
  sensors.setResolution(outsideThermometer, 10);
//  sensors.setResolution(dogHouseThermometer, 10);
}

void printTemperature(DeviceAddress deviceAddress)
{
  float tempC = sensors.getTempC(deviceAddress);
  if (tempC == -127.00) {
    Serial.print("Error getting temperature");
  } else {
    Serial.print("C: ");
    Serial.print(tempC);
    Serial.print(" F: ");
    Serial.print(DallasTemperature::toFahrenheit(tempC));
  }
}

void loop(void)
{ 
  delay(2000);
  Serial.print("Getting temperatures...\n\r");
  sensors.requestTemperatures();
  
  Serial.print("Inside temperature is: ");
  printTemperature(insideThermometer);
  Serial.print("\n\r");
  Serial.print("Outside temperature is: ");
  printTemperature(outsideThermometer);
  Serial.print("\n\r");
  Serial.print("Dog House temperature is: ");
//  printTemperature(dogHouseThermometer);
  Serial.print("\n\r\n\r");
}

And here is the result from serial output (redundant entries removed). You can see it cooling down until the inevitable.

Getting temperatures...
Inside temperature is: C: 24.75 F: 76.55
Outside temperature is: C: -13.50 F: 7.70
Dog House temperature is:

Getting temperatures...
Inside temperature is: C: 24.75 F: 76.55
Outside temperature is: C: -13.75 F: 7.25
Dog House temperature is:

Getting temperatures...
Inside temperature is: C: 24.75 F: 76.55
Outside temperature is: C: -14.00 F: 6.80
Dog House temperature is:

Getting temperatures...
Inside temperature is: C: 24.75 F: 76.55
Outside temperature is: C: -14.25 F: 6.35
Dog House temperature is:

Getting temperatures...
Inside temperature is: C: 24.75 F: 76.55
Outside temperature is: C: -14.50 F: 5.90
Dog House temperature is:

Getting temperatures...
Inside temperature is: C: 24.75 F: 76.55
Outside temperature is: C: -14.75 F: 5.45
Dog House temperature is:

Getting temperatures...
Inside temperature is: C: 24.75 F: 76.55
Outside temperature is: C: -15.00 F: 5.00
Dog House temperature is:

Getting temperatures...
Inside temperature is: C: 24.75 F: 76.55
Outside temperature is: C: -15.25 F: 4.55
Dog House temperature is:

Getting temperatures...
Inside temperature is: C: 24.75 F: 76.55
Outside temperature is: C: -15.50 F: 4.10
Dog House temperature is:

Getting temperatures...
Inside temperature is: C: 24.75 F: 76.55
Outside temperature is: C: -15.75 F: 3.65
Dog House temperature is:

Getting temperatures...
Inside temperature is: C: 24.75 F: 76.55
Outside temperature is: Error getting temperature
Dog House temperature is:

(Only one probe was in the freezer, the other was in the room.) I swapped the probes and had the same result.

Nick_Pyner:
While I have used Sheepdog, I don't really recommend it, but I submit the code is better to read than yours.

Again, that isn't my code, just the example that comes with the OneWire library, and readability aside, it's the only code that provides accurate readings at all temperatures with no errors.

And yes, it is a bit confusing to follow, that's why I'm asking at this point for help to simply forget the DallasTemp library, and modify the OneWire example to store my two readings as variables.

RichXKU:
I swapped the probes and had the same result.

Swap it again. I didn't realise that Remmington actually had a result at that temperature and, if it works for him, it should for you. Your code looks kosher, so everything points to a mechanical problem.

I can't see it helping much, but this is as basic as I can get.

/* Basic 3xDS18B20 code for serial monitor, bluetooth, Excel or w.h.y.
Derived from Hacktronics. Use their address sniffer and substitute your 
numbers. Use Hacktronics connections diagram. 
Stay away from parasite power
-127C means bad connection
85 means you haven't gotten a read yet, probably wrong order of commands
*/

#include <OneWire.h>
#include <DallasTemperature.h>

// Data wire is plugged into pin 3 on the Arduino
#define ONE_WIRE_BUS 3

// Setup a oneWire instance to communicate with any OneWire devices
OneWire oneWire(ONE_WIRE_BUS);

// Pass our oneWire reference to Dallas Temperature.
DallasTemperature sensors(&oneWire);
  
byte Thermo1[8] = {0x28, 0x39, 0xFD, 0x50, 0x04, 0x00, 0x00, 0X69};
byte Thermo2[8] = {0x28, 0x09, 0xA9, 0xC0, 0x03, 0x00, 0x00, 0x95};
byte Thermo3[8] = {0x28, 0x62, 0xA5, 0x2D, 0x04, 0x00, 0x00, 0x21};   

float tempC,Temp1,Temp2,Temp3,diff;  

void setup(){

  Serial.begin(9600);
  sensors.begin();

  delay(500);//Wait for newly restarted system to stabilize

  sensors.setResolution(Thermo1, 12); 
  sensors.setResolution(Thermo2, 12);
  sensors.setResolution(Thermo3, 12);
}

void loop() {
 sensors.requestTemperatures();  // call readings from the addresses
  Temp1 = sensorValue(Thermo1);
  Temp2 = sensorValue(Thermo2);  
  Temp3 = sensorValue(Thermo3); 
       diff = Temp2 - Temp1;

Serial.print("      Temp1 = ");
Serial.print(Temp1);
Serial.print("      Temp2 = "); 
Serial.print(Temp2);
Serial.print("      difference = ");
Serial.print(diff);
Serial.print("      Temp3 = ");
Serial.println(Temp3);

delay(1000);
}

//sensorValue function
float sensorValue (byte deviceAddress[])
{
  tempC = sensors.getTempC (deviceAddress);
  return tempC;
}

So the bottom line is exactly -16°C and below causes the error.

Except that according to your results at the lower device resolution, 4.1 F = -15.5 C. So it would seem that the breakpoint depends on the number of bits in the conversion.

In the first experiment that I did (which was some time ago), the hacktronics code worked at well below -20 C. Lately I've been using my own much more compact code, but I'll repeat the experiment. Unfortunately, my home freezer doesn't go below about -15 C, so I'll have to get some dry ice and report back.