Default DS18S20 example returns perplexing results

Greetings,

I am just beginning to play with the Dallas Semiconductor DS18S20 and the OneWire library and out of the gate seeing some strange results.

I am using the default temperature sensor example. I’m connecting a single DS18S10 to pin 10 of my Leonardo with a 4.7K pullup resistor, not using parasitic power. The sketch compiles, uploads, and runs just fine from either Arduino 1.0.5 or 1.5.7 on my Mac with OS X Mavericks. It seems to see the DS18S20 and extract its serial number, which seems to pass the CRC check. But the temperatures are well into the negative territory. They do respond to temperature changes, so it’s clear that data is being read, but not interpreted correctly.

At first blush I’d guess there is a byte order problem or byte misalignment or something of that type, but without a proper debugger I’m just stabbing in the dark. Is there something peculiar about Arduino on the Mac that perhaps was missed when the library was made? My best Googling skills are not helping.

Here’s the output from a few runs with the sensor between my fingers to raise the temperature.

ROM = 10 3D AE 62 0 8 0 2C
  Chip = DS18S20
  Data = 1 BE FF 0 0 FF FF C 10 38  CRC=38
  Temperature = -33.00 Celsius, -27.40 Fahrenheit
No more addresses.

ROM = 10 3D AE 62 0 8 0 2C
  Chip = DS18S20
  Data = 1 C0 FF 0 0 FF FF F 10 61  CRC=61
  Temperature = -32.19 Celsius, -25.94 Fahrenheit
No more addresses.

ROM = 10 3D AE 62 0 8 0 2C
  Chip = DS18S20
  Data = 1 C1 FF 0 0 FF FF 1 10 FE  CRC=FE
  Temperature = -31.31 Celsius, -24.36 Fahrenheit
No more addresses.

ROM = 10 3D AE 62 0 8 0 2C
  Chip = DS18S20
  Data = 1 C3 FF 0 0 FF FF 7 10 D2  CRC=D2
  Temperature = -30.69 Celsius, -23.24 Fahrenheit
No more addresses.

ROM = 10 3D AE 62 0 8 0 2C
  Chip = DS18S20
  Data = 1 C4 FF 0 0 FF FF F 10 74  CRC=74
  Temperature = -30.19 Celsius, -22.34 Fahrenheit
No more addresses.

ROM = 10 3D AE 62 0 8 0 2C
  Chip = DS18S20
  Data = 1 C4 FF 0 0 FF FF A 10 8B  CRC=8B
  Temperature = -29.87 Celsius, -21.77 Fahrenheit
No more addresses.

The example code:

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

Please post the code, using code tags ("#" button).

jremington: Please post the code, using code tags ("#" button).

It is the unmodified default example which I have posted thusly.

not using parasitic power

But the code does use parasite power. Change this:

ds.write(0x44, 1);

to this:

ds.write(0x44, 0);

Pete

el_supremo: Change this:

ds.write(0x44, 1);

to this:

ds.write(0x44, 0);

No dice, sadly. With the power parameter at zero, the behavior is the same. I will also note that I tried a different DS18S20 to rule out the sensor putting out bogus readings.

I recognise that you are using a Leonardo, but I imagine they are similar enough to the usual stuff that the software may require no more than a different pin call. I also understand the code for DS18B20 is may be used for the S20,. but you may need to omit or change the resolution command. In the light of that, I submit that the only useful line of code in this thread is

 // The DallasTemperature library can do all this work for you!
           // http://milesburton.com/Dallas_Temperature_Control_Library

and it’s time to stop abusing yourself.

Here is something that works on a Uno, should work on a Leo, and may be of value to the extent that will wonder why on earth you contemplated anything else.

/* 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. 
http://www.hacktronics.com/Tutorials/arduino-1-wire-tutorial.html
Stay away from using 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

// these three may be omitted
  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;
}

Nick_Pyner: // The DallasTemperature library can do all this work for you!           // http://milesburton.com/Dallas_Temperature_Control_Library

and it's time to stop abusing yourself.

Here is something that works on a Uno, should work on a Leo, and may be of value to the extent that will wonder why on earth you contemplated anything else.

Thanks, but it's garbage in-garbage out. The Miles Burton library uses the OneWire library, gets garbage from it and outputs garbage.

I'm going to set up a Linux VM today and see if there is any difference.

This may be true, but using it might assist you to identify the garbage you have but nobody else does. It would certainly be more constructive than hoping Linux will solve an Arduino problem.

I have a Teensy 3 with 3 DS18B20 (with a 4.7k pullup). The example code in your first post correctly identifies each one and reads the temperature with no problem.

Pete

The 9 byte message you are getting from that device has a suspiciously large number of FF's in it.

That tends to suggest to me that the electrical characteristics of your circuit are unsuitable somehow.

Nick_Pyner: This may be true, but using it might assist you to identify the garbage you have but nobody else does. It would certainly be more constructive than hoping Linux will solve an Arduino problem.

Adding a library is adding variables. I am interested in eliminating variables, one of them being platform. A surprising amount of code still assumes Macs are big-endian when they are not.

That being said, I still get the same screwy results on Windows (I wasn't able to get my Linux VM to talk to the USB port), so platform is eliminated.

I have also tried using my Uno and got the same screwy results, so the Leonardo is also eliminated.

michinyon:
The 9 byte message you are getting from that device has a suspiciously large number of FF’s in it.

That tends to suggest to me that the electrical characteristics of your circuit are unsuitable somehow.

I agree that the data looks suspect but I don’t know how much more simply this could be hooked up. It’s not a complicated circuit in the least. One sensor, one 4K7 resistor, three wires. Pin 1 connected to ground, pin 3 connected to 5V, pin 2 connected to pin 2 on the Arduino (or pin 10, I’ve tried both–same result), and a 4K7 resistor between pins 2 & 3 on the sensor. See attached diagram.

janus303:
Adding a library is adding variables.

No it isn’t. Adding a library is adding a fixed and well-established procudure, which is quite the oppoosite and, most importantly, puts you in the same arena as the majority who don’t have a problem. This is a rather good arena to be in as your only priority is to find out why you have a problem where nobody else does. It also means that the work that the library does can be eliminated from the analysis of the problem. As it is, I and many who don’t have a problem, won’t bother to look at your junk code because there is no point in doing so, and thus leave you out in the cold simply because you opt for self-flagellation.

It so happens that elSupremo does use your code and declares it fine, but you can only put that down to good luck, and so you can now come to the most likely conclusion - if the code is kosher, the wiring isn’t. As you rightly point out, the circuit is not complicated.

It is just faintly possible that there is some other mechanical problem. I wouldn’t recommend it as standard procedure, but the link below might help sort it out. It uses no libraries at all, not even one-wire.

http://sheepdogguides.com/arduino/ar3ne1tt.htm