Pages: [1]   Go Down
Author Topic: DS18B20 and occasional bogus readings  (Read 1998 times)
0 Members and 1 Guest are viewing this topic.
South-East UK
Offline Offline
Newbie
*
Karma: 0
Posts: 31
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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:

Code:
#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 smiley
« Last Edit: December 11, 2011, 04:25:10 am by hcanning » Logged

New Jersey
Offline Offline
Faraday Member
**
Karma: 49
Posts: 3420
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

You can use an if to wrap around your lcd code so you don't print for extreme values:
Code:
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:
Code:
  lcd.print ("c  ");
Logged

South-East UK
Offline Offline
Newbie
*
Karma: 0
Posts: 31
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

That's great, food for thought and something to work from, thanks. smiley
Logged

South-East UK
Offline Offline
Newbie
*
Karma: 0
Posts: 31
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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 smiley-wink


Thanks  smiley-red
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 4
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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

Oregon, USA
Offline Offline
Newbie
*
Karma: 0
Posts: 15
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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
Logged

0
Offline Offline
Shannon Member
****
Karma: 161
Posts: 10445
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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.
Logged

[ I won't respond to messages, use the forum please ]

Global Moderator
Netherlands
Offline Offline
Shannon Member
*****
Karma: 170
Posts: 12465
In theory there is no difference between theory and practice, however in practice there are many...
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset


Quote
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
Quote
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 smiley-wink     lcd.print(sensors.getTempCByIndex(0)*1.8 +32, 1);
Logged

Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

London
Offline Offline
Sr. Member
****
Karma: 0
Posts: 330
Arduino rocks
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

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
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 1
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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
Logged

London
Offline Offline
Sr. Member
****
Karma: 0
Posts: 330
Arduino rocks
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset


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
Logged

0
Offline Offline
Shannon Member
****
Karma: 161
Posts: 10445
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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).
Logged

[ I won't respond to messages, use the forum please ]

Offline Offline
Newbie
*
Karma: 0
Posts: 4
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset


Quote
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
Quote
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 smiley-wink     lcd.print(sensors.getTempCByIndex(0)*1.8 +32, 1);



Awesome!!

Quote
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-grin
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 34
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset


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:
Code:
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

Logged

Pages: [1]   Go Up
Jump to: