DS18B20 and occasional bogus readings

Hi all,

I have two DS18B20 digital temp sensors hooked up to my Arduino (for indoor and outdoor temps) which then displays each onto my 20x4 LCD.

All works nicely, except occasionally, very occasionally I'll get bogus readings for one or both of the sensors. Usually the reading is -127.00C but occasionally it'll jump up to 85.00C.

Now the outdoor sensor is attached to a piece of cat5 cable which is around 5 metres long, so I thought maybe this was the problem. But I'm wondering if there's any way I can code it to "ignore" these readings?

I wouldn't be so fussed if it didn't affect the LCD's readout, i.e.:

The display shows "20.50c" for instance, but when the -127.00 reading occurs, it writes these chars to the LCD which don't get 'erased' so the next correct reading will show up as "20.50c0" for example.

I hope that makes sense. I'm a total Arduino and programming noob so these questions may be very dumb. And here's my code for you to all laugh at:

#include <OneWire.h>
#include <DallasTemperature.h>
#include <LiquidCrystal.h>
int reLED=13;
int blLED=12;
int grLED=11;

LiquidCrystal lcd(4, 5, 6, 7, 8, 9);
#define   CONTRAST_PIN   9
#define   BACKLIGHT_PIN  7
#define   CONTRAST       100

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

// Setup a oneWire instance to communicate with any OneWire devices (not just Maxim/Dallas temperature ICs)
OneWire oneWire(ONE_WIRE_BUS);

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

void setup(void){

  pinMode(reLED, OUTPUT);
  pinMode(blLED, OUTPUT);
  pinMode(grLED, OUTPUT);
  pinMode(CONTRAST_PIN, OUTPUT);
  pinMode(BACKLIGHT_PIN, OUTPUT);
  digitalWrite(BACKLIGHT_PIN, HIGH);
  analogWrite (CONTRAST_PIN, CONTRAST);    
  lcd.begin(4,20);               // initialize the lcd 
  lcd.setCursor(0,0);
  lcd.print("----TEMPERATURES----");
  lcd.setCursor(0,1);
  lcd.print("Outdoors is");
  lcd.setCursor(0,2);
  lcd.print("Indoors  is");
  lcd.setCursor(0,3);
  lcd.print("====================");
  
  // Start up the library
  sensors.begin(); // IC Default 9 bit. If you have troubles consider upping it 12. Ups the delay giving the IC more time to process the temperature measurement
}
void loop(void)
{ 
  float outdoors = sensors.getTempCByIndex(0);
  float indoors = sensors.getTempCByIndex(1);
  // call sensors.requestTemperatures() to issue a global temperature 
  // request to all devices on the bus
  sensors.requestTemperatures(); // Send the command to get temperatures
  Serial.print(sensors.getTempCByIndex(0)); // Why "byIndex"? You can have more than one IC on the same bus. 0 refers to the first IC on the wire
  lcd.setCursor(12,1);
  lcd.print(sensors.getTempCByIndex(0));
  lcd.setCursor(12,2);
  lcd.print(sensors.getTempCByIndex(1));
      lcd.setCursor(0,1);
  lcd.print("Outdoors is");
  lcd.setCursor(0,2);
  lcd.print("Indoors  is");
    lcd.setCursor(17,1);
  lcd.print ("c");
    lcd.setCursor(17,2);
  lcd.print ("c");
  
  if (indoors>= 25)
  {
    digitalWrite (reLED, HIGH);
    digitalWrite (grLED, LOW);
  }
  else
  {
    digitalWrite (reLED, LOW);
    digitalWrite (grLED, HIGH);
  }  
  
  if (outdoors< 1.0)
  {
    digitalWrite (blLED, HIGH);
  }
  else
  {
    digitalWrite (blLED, LOW);
  }
    
    delay(5000);

}

Oh I should add that if I power it from USB the bogus readings are frequent, but if I power it from my usual source of a 12v wall wart, they're very infrequent. I left it running all evening and it was fine but I got up this morning and saw one :slight_smile:

You can use an if to wrap around your lcd code so you don't print for extreme values:

sensors.requestTemperatures(); // Send the command to get temperatures
Serial.print(sensors.getTempCByIndex(0)); // Why "byIndex"? You can have more than one IC on the same bus. 0 refers to the first IC on the wire
if(sensors.getTempCByIndex(0) > -125.0 && sensors.getTempCByIndex(0) < 85.0)  
  {
  lcd.setCursor(12,1);
  lcd.print(sensors.getTempCByIndex(0));
  }

Nicer to use the indoors & outdoors variables rather than calling sensors.getTempCByIndex(0) repeatedly, but they're set before the temp request, so they're stale.

Simpler still though, just overwrite the characters after "c" with spaces:

  lcd.print ("c  ");

That's great, food for thought and something to work from, thanks. :slight_smile:

Actually one more thing..

How would I go about getting it to display the temperature to only one decimal point? It doesn't need to be quite as precise as 20.59C! 20.5, 20.3, etc would do nicely :wink:

Thanks :blush:

I'd also like to know how to just display a single decimal point.. XX.X F is all I need.

I wrote code a couple months ago to do just that, it only displays one number after the decimal point but sure with some slight modifications you could make it have two. The code is available from arduinogrc.blogspot.com

You have 100nF or similar decoupling capacitor between 5V/Gnd at the sensor end of the cable?

You have a strong pullup (2k2 perhaps rather than 4k7) between 5V and the data line at the Arduino end of the cable?

You run the data and ground on the same twisted pair of the Cat5 cable?

All of these precautions should reduce chance of interference/noise corrupting the signal on the OneWire bus.

How would I go about getting it to display the temperature to only one decimal point? It doesn't need to be quite as precise as 20.59C! 20.5, 20.3, etc would do nicely smiley-wink

I'd also like to know how to just display a single decimal point.. XX.X F is all I need.

chance line to lcd.print(sensors.getTempCByIndex(0), 1); // 1 decimal place => Note : 2 is the default

For Fahrenheit the trick is similar :wink: lcd.print(sensors.getTempCByIndex(0)*1.8 +32, 1);

Regarding the spurious values.

There is a crc error check you can do, that should sort this out but Ive not seen any published code using this.
Have a look at the data sheet.http://datasheets.maxim-ic.com/en/ds/DS18B20.pdf
Ive been lazy and just ignored the obvious spurious values.
So far All ive seen is the value 85.00 which is way out of bounds for internal or external temperature on my set up.

Just a
do
..
while(temp == 85.00)

Around your code to get the temp value from the sensor.

Gordon

I also have problems with occasional false readings of DS18B20. I read values every 2 minutes and write values (and possible errors) in MySQL database over ethernet. In average I have 3-5 false readings per day. I have 4 sensors on same bus, but use 4 wire phone cable instead of twisted wire Cat5. Maybe I should change my cable...

I was thinking to use DS2480B - serial to 1-Wire Line driver, but I couldn't find any library for Arduino for this IC.

Best regards, Matej

Im using about 3 metres of telephone wire, but only get the errors at start up.
None during the day or night while its running constantly.
Ive got mine running a web server and showing the last 24 hours readings.
Ive assumed its something to do with running it parasitic and something is happening with the power over the pins Ive connected it to.
But as its only on start up and the errors are obvious Im living with it.

Gordon

I've not used parasite power mode, but on normal powered mode with short cables the DS18B20 is extremely reliable (I've got 502,000 readings from 11 different sensor nodes over the last 4 months and no rogue values).

This is almost certainly a cable length, screening or decoupling issue. Parasite mode is obviously very sensitive as you can't place a decoupling cap at the device end. I'd recommend screened cable for parasite mode (coax or STP).

robtillaart:

How would I go about getting it to display the temperature to only one decimal point? It doesn't need to be quite as precise as 20.59C! 20.5, 20.3, etc would do nicely smiley-wink

I'd also like to know how to just display a single decimal point.. XX.X F is all I need.

chance line to lcd.print(sensors.getTempCByIndex(0), 1); // 1 decimal place => Note : 2 is the default

For Fahrenheit the trick is similar :wink: lcd.print(sensors.getTempCByIndex(0)*1.8 +32, 1);

Awesome!!

void printTemperature(DeviceAddress deviceAddress)
{
float tempC = sensors.getTempC(deviceAddress);
lcd.print(DallasTemperature::toFahrenheit(tempC), 1);
}

Worked like a charm!

Greatly appreciated.. and Happy New year! :smiley:

GordonEndersby:
Im using about 3 metres of telephone wire, but only get the errors at start up.
None during the day or night while its running constantly.
Ive got mine running a web server and showing the last 24 hours readings.
Ive assumed its something to do with running it parasitic and something is happening with the power over the pins Ive connected it to.
But as its only on start up and the errors are obvious Im living with it.

Gordon

Gordon, you should use some time at start to read them without printing, smth like:

void loop()
{

  kp = sensors.getTempC (kpp);
  kg = sensors.getTempC (kgg);
  sp = sensors.getTempC (spp);
  sg = sensors.getTempC (sgg);
  ap = sensors.getTempC (app);
  tl = sensors.getTempC (tll);
  tb = sensors.getTempC (tbb);
  x2 = sensors.getTempC (x11);
  x4 = sensors.getTempC (x22);
  x3 = sensors.getTempC (x33);
 
  sensors.requestTemperatures();

 

if (millis() > 2000) {
//and here you start your programme