0

I just got an DS18B20 Temperature sensor and am trying to modify the example code to use a function instead. Below is my getTemp function. It's working but returning results with a 0 value part of the time for example:

Temperature = 72.39
Temperature = 0.00

If I add Serial.print(fahrenheit); within the function I am always provided with the correct temperature. I though this may have to do with needing a delay but adding delay(5000); in my loop didn't help.

I'm assuming it's something simple I'm not understanding about how floats return.

#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(2);  // on pin 10 (a 4.7K resistor is necessary)

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

float getTemp(char tScale) {
  byte i;
  byte present = 0;
  byte type_s = 0;
  byte data[12];
  byte addr[8];
  float celsius, fahrenheit;

  if ( !ds.search(addr)) {
    ds.reset_search();
    delay(250);
    return false;
  }

  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

  for ( i = 0; i < 9; i++) {           // we need 9 bytes
    data[i] = ds.read();

  }

  // 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;
  if (tScale == 'C') {
    return celsius;
  }
  else if (tScale == 'F') {
    return fahrenheit;
  }

}
void loop(void) {
    Serial.print("Temperature = ");
    Serial.println( getTemp( 'F' ) );


}

Edit: Interesting enough, adding an if statement to the loop fixes this, however. I'd still like to understand what is going on:

void loop(void) {
  if ( getTemp( 'F' ) == 0 ){
    Serial.print( "Temperature = " );
    Serial.println( getTemp( 'F' ) );
  }
}
5
  • Could you please clarify what you mean by 'fixes it' in your edit? Since your getTemp() occasionally returns 0, it's clear that you filter for zero by checking for getTemp('F') == 0.
    – sekdiy
    Mar 11, 2016 at 7:24
  • I guess what I mean is that if getTemp is set to 0 then the correct temperature is being displayed to serial (never showing Temperature = 0.00 It only returns the actual temperature.
    – Brooke.
    Mar 11, 2016 at 7:42
  • So you skip the problematic instances of !ds.search(addr) (by just polling the sensor twice in close succession), ignoring the underlying problem. :)
    – sekdiy
    Mar 11, 2016 at 7:50
  • There are apparently a lot of alleged "DS18B20" devices on the market which do not meet the timing of the published spec. To try to use them you will need to slow things down. You can somewhat offset the time cost of doing so by running in a lower bits mode, but some of the published example code which appears to handle various bit widths in fact horribly misinterprets anything but the widest, and has to be fixed. No, I don't have a repaired copy at hand to quote from. Mar 11, 2016 at 16:52
  • @Chris Stratton: I think it's a good idea to look into the actual issue of the DS18B20 communication failing. BandonRandon: Why don't you try the DallasTemperature library? It even comes with a Tester sketch and other useful stuff.
    – sekdiy
    Mar 11, 2016 at 20:45

1 Answer 1

1

You have intermittent communication problems.

Your address search occasionally fails and getTemp() returns false. In C++ (and many other languages) false will be implicitly cast to (int) 0, (float) 0.0f, and so on.

Your getTemp() function also is difficult to debug because the multiple return statements have different meaning.

After the delay(250); you do a return false; in order to skip the rest.

In the example at https://www.pjrc.com/teensy/td_libs_OneWire.html the meaning of the return statement(s) is different. There the return happens within the void loop() function, where it simply means to interrupt the current execution (without returning a value) and continue with the next loop.

While it is generally okay to have multiple return, it can sometimes be problematic and I recommend to avoid it.

If you want to clean this up while still preserving the ability to detect a fault, you have a couple of options (order from most to least recommended):

  • do the setup/checking in a different function (and only call the second one if the first one succeeded), i.e. if (isReady()) { Serial.println(getTemp()); }
  • set a separate error variable, i.e. error = true; return 0; (and then check error later)
  • define a 'default' value that you interpret as an error (and never expect to be a temperature), i.e. return NAN; // not a number
4
  • 1
    Is there actually a reason why you use the sensor the hard way and not employ a library for it (like you do with OneWire)? There are Dallas temperature libraries that employ OneWire, e.g. github.com/milesburton/Arduino-Temperature-Control-Library.
    – sekdiy
    Mar 11, 2016 at 7:53
  • Rather than -460.0f, which looks like a silly value, I would return NAN (i.e. not a number). It more clearly conveys the meaning of “not a valid value”. Serial.print() displays it as “nan”. Mar 11, 2016 at 8:49
  • Yeah, out-of-range was just the first thing I came up with. And since it's my least recommended solution, I still regard it as inferior, even when using NAN. I edit my answer accordingly.
    – sekdiy
    Mar 11, 2016 at 8:52
  • Thanks switched to the Miles Burton Library and everything is working as expected and my code looks much cleaner.
    – Brooke.
    Mar 12, 2016 at 23:32

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.