DS18S20 reading -39 deg C at room temp... why?

Hello!

I have a challenge with a DS18S20. It is reading -39 deg C at room temp.

Here are the details:

  • Single DS18S20 temperature sensor with an Arduino Uno.
  • Code I am using is below. It is the example code from the onewire web site.
  • Input is on Pin 10 of the Uno, with a 5K resistor pullup to 5V.
  • Power is from USB.
  • Nothing else is connected to the Uno.
  • The sensor is working... if I heat it, the output temp rises as I would expect.
  • I have tried multiple DS1820 parts, and all are doing the same.
  • I have tried DS18S20 pin 3 grounded and pin 3 open... makes no difference in the result.

Here is the output I get on the serial port (this is in a 70 deg F room):

ROM = 10 1A F5 62 0 8 0 FA
Chip = DS18S20
Data = 1 B1 FF 0 0 FF FF 1 10 4B CRC=4B
Temperature = -39.31 Celsius, -38.76 Fahrenheit
No more addresses.

The code is below.

Your thoughts greatly appreciated!!

#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(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[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");
}

When using parasite power, pin 3 must be grounded.
But I'd suggest that you try non-parasite power. Connect +5V to pin 3, and change the code so that it does a non-parasite power conversion.

Pete

Hi Pete,

Thank you for the suggestion. I tried it and achieved the same result however...

Here is the output with 5 volts on pin 3 and the code modified for non-parasite power...

Chip = DS18S20
Data = 1 B2 FF 0 0 FF FF C 10 7 CRC=7
Temperature = -39.00 Celsius, -38.20 Fahrenheit
No more addresses.

This is really strange... I have not seen anyone else online with the same problem.

  • Jon

The sample code DS18X20 in the one wire library (and indeed your sketch) works perfectly with a DS18B20. You are using a DS18S20.

Do you have a DS18B20 to test?
Have you absolutely confirmed continuity with the the pull up resistor.

Here is the part of the code which handles the different types and resolutions. DS18S20 type_s = 1

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
  }/code]

The "B2 FF" in the data output corresponds to a temperature of -39C, so it really is sending a large negative temperature. I have no idea why it would be doing this.

Pete

Cattledog,

Thanks! I have 3 parts... sadly, all of them are ds18S20. And all are exhibiting the same behavior.

I swapped out the resistor... no change in the result.

Thank you for your suggestions.

  • Jon

Yes, the FF value in the MSB (data[1]) is very strange.

The device is supposed to reset to 85C on power up.

Here’s something to try.

Comment out the following line of code in the sketch.

//ds.write(0x44, 1); // start conversion, with parasite power on at the end

Cycle power to the DS18S20 and run the sketch. The temperature should be 85C.

What does your print out show?

Cattledog,

You are indeed correct. Commenting out that line produced the result you anticipated:

ROM = 10 EA B7 62 0 8 0 E2
Chip = DS18S20
Data = 1 AA 0 0 0 FF FF C 10 7F CRC=7F
Temperature = 85.00 Celsius, 185.00 Fahrenheit
No more addresses.

Returning the line sets the result back to where it was:

ROM = 10 EA B7 62 0 8 0 E2
Chip = DS18S20
Data = 1 AE FF 0 0 FF FF E 10 FD CRC=FD
Temperature = -41.13 Celsius, -42.03 Fahrenheit
No more addresses.

I’m pretty sure the sensor is working… a quick blast of hot air sends the temp readout rising nicely. So your test would further confirm that the sensor is alive and well… I think!

Thanks,

  • Jon

have you tried the Dallas Control Library

from your original post...

// The DallasTemperature library can do all this work for you!
// Miles Burton - Innovative engineering for pretty much anything

This maybe:

This library supports the following devices :

    DS18B20
    DS18S20 - Please note there appears to be an issue with this series.
    DS1822
    DS1820

And this:

Supported Devices

    DS18B20 

    DS1822 

    DS18S20* 

    DS1820 

Additional devices can be implemented through different temperature strategies. Refer to the code for more information.

*Problems reported on this series

DS18S20 problems stated in both libraries.

I would agree with elac and the more I look at this problem the more I think there is a problem with the OneWire library and the DS18S20.

Indeed, there once may have been a problem with the DS18B20 as well because in OneWire.cpp Version 2.2 it says "Fix DS18B20 example negative temperature".

Here are links to the DS18S20 data sheet (http://datasheets.maximintegrated.com/en/ds/DS18S20.pdf) and a comparison to the DS18B20 (http://www.maximintegrated.com/en/app-notes/index.mvp/id/4377)

The data as it is read out of the MSB (before it is ever used by the sketch) is not correct. In the data provided by losgatosarduino the MSB was FF and the LSB was AE and the temperature printed out as -41.13. The MSB should not be FF.

I believe that the problem must lie in the read_bit or read() functions in the OneWire library.

The FF in the MSB is taken as a negative number, and is carried into bit7 of the LSB which is also a sign bit. The program then thinks AE = B1010 1110 is a negative number. Ignore the .5C bit0, and taking the twos complement of 010111, which is 101001 or 41. That's where the -41.xxC is coming from.

If we just take 010111 as a positive number, then the temperature is 23C which is a reasonable room temperature.

I don't know how to fix root of this problem, but there is a possible work around, to show a limited set of positive temperatures (1C-64C)

Test the highest bit of MSB (if MSB & 0x80 ==1) to see of there is a negative number. If so, then set bit7 of the LSB to 0. Then bit6 through bit1 will give the temperature in degrees C. You can test bit0 to see if there is .5C.

I'm not entirely sure yet how to pull the remaining available bits from "count remains", but the library uses

if (data[7] == 0x10) {
      // "count remain" gives full 12 bit resolution
      raw = (raw & 0xFFF0) + 12 - data[6];

That's great insight, thanks!

Given that... as long as I'm willing to accept a limited range (1C to 64C, as you say), wouldn't a correction factor do the trick?

The error would be the same across that range, correct? It's now reading about 58 deg C low. If I add that to the result (and stay within the 1 to 64C range), it should do what I need.

Am I missing something?

Thank you all for the help.

  • Jon

Do you have another thermometer to calibrate with?
Raise and lower the temp. x degrees from ambient temp. and see if the difference is a constant 58.

It's not clear to me how the device will actually respond, but the mathematics of the two's complement for negative and positive 6 bit binary numbers is that the absolute value of the negative number and the positive number will add up to 64. Or 64 - abs (negative temp) = positive temperature. When the fractions are added in, it should be the same. For example a negative temperature of -41.25 should convert to a positive value of 22.75.

P.S. The DS18B20's are pretty inexpensive. Why don't you treat yourself to a handful of those. The definitely work with both the OneWire and Dallas Temperature libraries.

You are right, of course. Get the part that works.

But I did the experiment... it's consistently reading 58 to 60 deg C low in the range I need. So I'll add that on and call it a day, for now.

Would be great to finish the job and correct the code.

Thank you for your help!