DS18B20 Question

hi there
i have DS18B20 displaying the temp in one of my project but every now and then it display 0.00, -127 or 85 degrees for a short period of time, i think the reason is because the cable run is about 100m. but it is wired in screened cable and earthed at one end.
so is there something i can do software wise? maybe like looking at the new temp and comparing against the old one or something what do you lot think and how would i go about doing it?

thanks Joe

Errors do occur and your software should remove them. If only specific wrong values show up, simply check for those and discard them. Otherwise, a check for "reasonable differences" from one reading to the next, or from one reading to a running average, should work.

o ok i see, what would be a good way of including that into my code?

here is my code at mo:

int encoderPin1 = 2;
int encoderPin2 = 3;

volatile int lastEncoded = 0;
volatile float encoderValue = 30;

long lastencoderValue = 0;

int lastMSB = 0;
int lastLSB = 0;

int led = 13;
/*-----( Import needed libraries )-----*/
#include <Wire.h>
#include <OneWire.h>
#include <DallasTemperature.h>

/*-----( Declare Constants )-----*/
#define ONE_WIRE_BUS 7 /*-(Connect to Pin 7 )-*/

/*-----( Declare objects )-----*/
/* Set up a oneWire instance to communicate with any OneWire device*/
OneWire ourWire(ONE_WIRE_BUS);

/* Tell Dallas Temperature Library to use oneWire Library */
DallasTemperature sensors(&ourWire);



#define _Digole_Serial_UART_  //To tell compiler compile the special communication only, 
//all available are:_Digole_Serial_UART_, _Digole_Serial_I2C_ and _Digole_Serial_SPI_
#include <DigoleSerial.h>
//--------UART setup, if you don't use UART, use // to comment following line
#if defined(_Digole_Serial_UART_)
DigoleSerialDisp mydisp(&Serial, 9600); //UART:Arduino UNO: Pin 1(TX)on arduino to RX on module
#endif

#define LCDCol 16
#define LCDRow 2

const unsigned char fonts[] = {
  6, 10, 18, 51, 120, 123};

void setup() 
{
  pinMode(led,        OUTPUT);
  pinMode(encoderPin1, INPUT); 
  pinMode(encoderPin2, INPUT);

  digitalWrite(encoderPin1, HIGH); //turn pullup resistor on
  digitalWrite(encoderPin2, HIGH); //turn pullup resistor on

  attachInterrupt(0, updateEncoder, CHANGE); 
  attachInterrupt(1, updateEncoder, CHANGE);
  
    mydisp.begin();
    mydisp.clearScreen(); //CLear screen
    mydisp.drawStr(5, 0, "Hello"); 
    delay(1000);

    mydisp.clearScreen(); //CLear screen
    mydisp.drawStr(0, 0, "Temp:");
    mydisp.drawStr(0, 1, "Set :");

/*-( Start up the DallasTemperature library )-*/
sensors.begin();

}


void loop() 
{


sensors.requestTemperatures(); 


       mydisp.setPrintPos(5, 0);
       mydisp.print(sensors.getTempCByIndex(0)); 
       
       mydisp.setPrintPos(5, 1);
       mydisp.print(encoderValue); // display a char array 
       
       if (encoderValue < sensors.getTempCByIndex(0)) {
         digitalWrite(led,    HIGH);
       }
       else {
         digitalWrite(led,    LOW);
       }
}

void updateEncoder(){
 int MSB = digitalRead(encoderPin1); //MSB = most significant bit
 int LSB = digitalRead(encoderPin2); //LSB = least significant bit

  int encoded = (MSB << 2) |LSB; //converting the 2 pin value to single number
  int sum  = (lastEncoded << 2) | encoded; //adding it to the previous encoded value

  if(sum == 0b1101 || sum == 0b0100 || sum == 0b0010 || sum == 0b1011) encoderValue = encoderValue + 0.1;
  if(sum == 0b1110 || sum == 0b0111 || sum == 0b0001 || sum == 0b1000) encoderValue = encoderValue - 0.1;

  lastEncoded = encoded; //store this value for next time
}

It's pretty hard to tell what's going on, and seems to be somewhat more than getting the temperature, but I'm surprised you are getting anything at all with it.

Of the three results:

I can't explain the 0.00. I have had it twice in recent months after running perfectly for about a year. I have not looked into it yet and it may be due to weather conditions. I just fixed it with the reset button.

-127 indicates a bad connection or, in your case, perhaps an inadequate one. Such long runs are problematic but there has been plenty of discussion about it on the forum. Since it works sometimes, you might find that changing the pullup resistor to 2.2k is all that is needed.

The 85 indicates the sensor hasn't had time to do its job. Since you defaulting to 12 bit resolution, the sensor needs about 750ms to stay in play, and you seem to be giving it nothing, hence my surprise. You can probably fix this by adding a quick'n'dirty.

delay(1000);

in the loop, thereby giving readings approx once per second, which I bet is as frequent as you really need.

Your problems may be caused by using parasitic power, which always seems to be more trouble than it is worth. I recognise your code can work, but you might be better off with that in the Hacktronics tutorial.

-127 indicates a bad connection or, in your case, perhaps an inadequate one. Such long runs are problematic but there has been plenty of discussion about it on the forum. Since it works sometimes, you might find that changing the pullup resistor to 2.2k is all that is needed.

i have a 1k at the arduino end and at the sensor end i have 1k as well, the only way i could get it to work

The 85 indicates the sensor hasn't had time to do its job. Since you defaulting to 12 bit resolution, the sensor needs about 750ms to stay in play, and you seem to be giving it nothing, hence my surprise. You can probably fix this by adding a quick'n'dirty.

i see yes i will at a delay there :slight_smile:

Your problems may be caused by using parasitic power, which always seems to be more trouble than it is worth. I recognise your code can work, but you might be better off with that in the Hacktronics tutorial.

i'm not using parasitic power as could not get it to work at all over the length

another quick question i have is how can i get it just to display max of one decimal place?

thanks for your reply and help
thanks Joe

Joes:
i have a 1k at the arduino end and at the sensor end i have 1k as well, the only way i could get it to work

1+1 = 2.2 but you should be able to have a single resistor at the Arduino end. That will cover all sensors.

i'm not using parasitic power as could not get it to work at all over the length

No surprise there and hence my comment

another quick question i have is how can i get it just to display max of one decimal place?

I don't really know but I guess you have assemble a string of the int and a rounded frac, using the dtostrf command. i don't think setting the resolution of the sensor is the answer.

another quick question i have is how can i get it just to display max of one decimal place?

// Fetch temperature for device index
float DallasTemperature::getTempCByIndex(uint8_t deviceIndex)
{
  DeviceAddress deviceAddress;
  getAddress(deviceAddress, deviceIndex);
  return getTempC((uint8_t*)deviceAddress);
}

getTempCByIndex() is returning a float, and your display looks like it knows how to print it as a number without conversion to a character string. If it is inheriting from the general print class, then you can try

mydisp.print(sensors.getTempCByIndex(0),1);

which I think should print one dp.

Joes:
hi there
i have DS18B20 displaying the temp in one of my project but every now and then it display 0.00, -127 or 85 degrees for a short period of time, ...

If you look at the source, it returns DEVICE_DISCONNECTED if it couldn't read the device, so getting -127 isn't too surprising.

#define DEVICE_DISCONNECTED -127

thanks for all your feedback

// Fetch temperature for device index
float DallasTemperature::getTempCByIndex(uint8_t deviceIndex)
{
DeviceAddress deviceAddress;
getAddress(deviceAddress, deviceIndex);
return getTempC((uint8_t*)deviceAddress);
}

what am i looking at here, confused on what I'm looking at could you explain?

mydisp.print(sensors.getTempCByIndex(0),1);

this seems to work fine apart from if you disconnect the sensor you get -127 and when reconnected you get the temp back but if the sensor is reading 25.5 it will display 25.5.0 how can i over come that?

If you look at the source, it returns DEVICE_DISCONNECTED if it couldn't read the device, so getting -127 isn't too surprising.

o i see that makes a bit of sense

thanks all

what am i looking at here, confused on what I'm looking at could you explain?

That is the code from the Dallas Temperature library showing that the function returns a float.

I am confused as well. Does mydisp.print(sensors.getTempCByIndex(0),1);
display one decimal place, like 25.5 or does it display 25.5.0?

That is the code from the Dallas Temperature library showing that the function returns a float.

right ok, so should i stick with trying to get your other suggestion working first?

i would like it to just to display one decimal place not one decimal place and then .0 after it
does that make more sense?

thanks for your help

I do not understand why mydisp.print(sensors.getTempCByIndex(0),1) is giving you xx.x.x

I do not have your display hardware or use the library, but a google review would lead me to believe that the xxx.print(float,1) should give you one decimal place.

You could try print a transfer variable like this

float value = sensors.getTempCByIndex(0);
mydisp.print (value,1);

If that doesn't work, I think you should try Nick Pynor's suggestion of converting the float to a character string with dtostrf and printing the string. The format for dtostrf is dtostrf(floatvar, StringLengthIncDecimalPoint, numVarsAfterDecimal, charbuf);

where

floatvar float variable
StringLengthIncDecimalPoint This is the length of the string that will be created
numVarsAfterDecimal The number of digits after the decimal point to print
charbuf the array to store the results

void setup() {
  
char t[6]; //should handle xxx.x and null terminator
float x = 123.456;

dtostrf(x, 5, 1, t);

Serial.begin(9600);
Serial.println(t);
}

void loop() {
}

cattledog:
I am confused as well. Does

mydisp.print(sensors.getTempCByIndex(0),1);

display one decimal place, like 25.5 or does it display 25.5.0?

In all likelihood it is the simple error of not clearing the display before redisplaying. For example if you display -127.0 and then 25.5 without clearing you will get that effect, eg.

-127.0
25.5
    ^^  <--- left over from last time

Simply displaying a couple of trailing spaces would fix it.

Nick_Pyner:
The 85 indicates the sensor hasn't had time to do its job. Since you defaulting to 12 bit resolution, the sensor needs about 750ms to stay in play, and you seem to be giving it nothing, hence my surprise. You can probably fix this by adding a quick'n'dirty.

delay(1000);

The requestTemperatures() function already adds a delay which varies depending on the selected resolution, there shouldn't be a need to add an extra delay.

I find the 85 appears when I first get a temp from the sensor. Maybe it is losing connection/power temporarily.

Where did you get the library exactly? One version I have, at least, gets the CRC check from the device and then ignores it. Without checking the CRC you have no way of knowing if the data is good. There is a difference between not finding the device at all, and finding it and getting corrupt data.

ChrisHigs:
The requestTemperatures() function already adds a delay which varies depending on the selected resolution, there shouldn't be a need to add an extra delay.

I find the 85 appears when I first get a temp from the sensor. Maybe it is losing connection/power temporarily.

I submit this is nonsense. The function is code, and the code doesn't add the delay, the delay is in the sensor and is caused by the conversion time required - the more converting, the more time.

The 85 you see is the power-on reset value. It is not telling you something is wrong, quite the opposite - plus the fact that you are too eager. The reason why you see it when you "first get a temperature" is that you are asking for a temperature before the sensor has had enough time to give you one. This is common enough in simple programmes and not really a problem. You sometimes see a delay(1000); thrown into the Setup to avoid this, and called settle-down time. In a more comprehensive programme, there will be more stuff like initialising SD, naming files, setting up Ethernet etc., thus more code between power-up and requestTemperature(), hence more time taken, and the 85s go away.

I imagine you would would be a bit unlucky if you ever saw an 85 and were calling for 9 or 10 bit resolution, but OP wasn't calling anything and hence getting 12 bit by default.

This is from DallasTemperature.cpp. When request temperature() is called it calls blockTilConversionComplete() which ask millisToWaitForConversion how long to wait. 12 bit returns 750. Then delays that long. Maybe it doesn’t delay long enough on the first call of it.

int delms = millisToWaitForConversion(bitResolution);
    if (deviceAddress != NULL && checkForConversion && !parasite)
    {
        unsigned long timend = millis() + delms;
        while(!isConversionAvailable(deviceAddress) && (millis() < timend));
    }
    else
    {
        delay(delms);
    }

Somewhat off topic but 100m is a long cable. Consider wireless

Roger

i don't no where i got the library now. would it be worth deleting the library and putting one on that you recommend?

i have added the space before printing the temp seems to work :slight_smile: think i will stick with that at mo as it is easy

unfortunately wireless is unsuitable for my application but that is another topic

so should i have a delay in my loop or not then?
or just stick it in and see how i get on?

I'm not sure where I got mine either. :stuck_out_tongue:

However the one mentioned at http://playground.arduino.cc/Learning/OneWire as the "latest" is probably a good one to try.