DS18B20 gives unexpected readings below 0C 32F freezing

I have a half dozen or so DS18B20 temperature sensors in different places in my house and they seem to work like a champ unless the temperature falls below freezing. The temperature value reads as something in the 7300-7400 range in either C or F (same value for both oddly enough).

Initially I just assumed my outside temp sensor was bad but when I hit one of the internal ones with some canned air held upside down it also displayed the 7XXX temp.

Any ideas?

Here is an example of the most recent readings (it is below freezing outside at the moment)

61.25,7398.50,39.76,58.44,59.56,68.90,59.90

Here is the code I am using:

#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(53);  // on pin 53

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

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(60000);
    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.print(",");

  // convert the data to actual temperature

  unsigned int 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);
    if (cfg == 0x00) raw = raw << 3;  // 9 bit resolution, 93.75 ms
    else if (cfg == 0x20) raw = raw << 2; // 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");
}

Hello,

I’m really not sure, but try changing:

unsigned int raw = (data[1] << 8) | data[0];
//to
int raw = (data[1] << 8) | data[0];
//or
long raw = (data[1] << 8) | data[0];

Unsigned values will never go below 0, they will overflow, so I think that’s your problem :slight_smile:

You sir are correct! :)

I changed to long and viola it worked wonderfully. The canned air test resulted in -42 F (and I also confirmed Cosm supports negative numbers in the process).

Thanks so much!

There are two known bugs in that library. See:
http://www.pjrc.com/teensy/td_libs_OneWire.html

Pete