DS18B20 return 0.00°C

Hello,

I've built a system to regulate the temperature and humidity in my cellar, using 2 DS18B20 for the temp and 2 DHT21 for the humidity. To regulate the temperature, it has an ext to int fan and an electric heater for the winter ; and a classic dehumidifier for the humidity.

It has worked really fine since October 2013, but I recently decided to log the different sensors and output state using the serial port (and a PC) to see what the system was doing during the night... And this morning, when I entered the cellar, it was like 25°C and the heater was on ! When I looked up the log file from the night, I saw that suddenly both external and internal temperature (from the 2 DS18B20) fell to zero, and stayed that way for the rest of the night (which explains the heater...). After rebooting and resetting the EEPROM, it return to normal... I managed to get the problem once again doing the following : - Powering the arduino with its usual AC-DC adapter (9V) AND plugging the USB on the PC - (As the temp was to high, the fan was automatically on) - Turning manually ON the electric heater using a simple switch mounted on the arduino

Instantaneously, both temp fell down to zero and the heater stayed automatically on... I tried the same thing with only the AC-DC adapter or the USB, and no problem. However, when I tried again with both power source, no problem either !

In short, I suspect a failure from the 2 DS18B20, but I read that in that case we usually get -127 (no device found) or 85 (start-up value)... In which case could they return a constant exact zero value (0.00°C) ? They are powered with the +5V pin (and GND), and the data wire is connected to the PIN 7 using a 4.7kOhm resistor.

I hope this isn't too long and clear enough... Please ask if you have any question !

Thanks in advance

Hi TIbzor

the data wire is connected to the PIN 7 using a 4.7kOhm resistor.

Is the resistor in series between the sensor data pin and digital pin 7 of the Arduino, or is it a pullup resistor connecting the data pins to +5V?

Thanks

Ray

Hi,

It's a pullup resistor, linking both PIN 7 and the data wire to +5V ;) One sensor has around 5m of wire and the other around 2 or 3m.

A small precision regarding the 0°C error : I think it has happened before, since it occurred 2 or 3 times this night and I sometimes get a 0.00°C value for the min temperature... but it's definitely the first time it doesn't correct itself rapidly ! I have a "security" in my program which test the temp value, and if not "normal" (below -15 or above 40) makes it measure it again. It didn't have a "delay" feature until this morning, so it would ask a new temperature immediately after getting a wrong one... This might explain why it had a hard time getting a normal value again, but not why it happened especially this night and not before of why it gets a 0.00 value in the first place !

Thanks !

Tibzor

Oh, and it case it helps…
Here is the part of my program where I actually ask for the temperatures :

t_recup=millis();    // initializing data collection chrono
 
 sensors.requestTemperatures();  // Getting temperatures
 Tint = sensors.getTempC(insideThermometer);
 Text = sensors.getTempC(outsideThermometer);

 if (Text == 0.00)    // If temp ext equal to 0.00°C (possible but not likely), we wait 1s and ask temp again (only one time)
 {
   delay(1000);
   sensors.requestTemperatures();  
   Text = sensors.getTempC(outsideThermometer);
 }

 while (Tint < 3.00 || Tint > 40.00 || Text < -15.00 || Text > 40.00)    // If temp not normal, we get them again
 {
   delay(1000);
   sensors.requestTemperatures();  
   Tint = sensors.getTempC(insideThermometer);
   Text = sensors.getTempC(outsideThermometer);
   if (millis()-t_recup > 2000) ALARMTEMP();    // If it takes more than 2s to get a correct temp, ring alarm (likely a problem with the temp collection)
 }

The initializing of the temp library (Dallastemp) is made before in my program, but I took it directly from the internet so it most likely is right :wink:

The code is clouded but looks kosher enough to conclude that maybe the problem is actually in the stuff you don’t show.

Here is some almost totally stripped-down code you might check it against. It’s probably from the same source you use

/* 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. 
Stay away from using parasite power
-127C means bad connection
85 means you haven't gotten a read, 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

  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;
}

So you say, this system was working OK for a year, and then malfunctioned all by itself without you messing with it ?

That surely points to some kind of failure of the sensor(s) or wiring to the sensors themselves.

Or secondly, some climatic condition which had just occured, which your code doesn't handle properly, and you didn't find out for a whole year until that condition occurs.

Or thirdly, some kind of condition in the arduino which caused it. Things that come to mind, are an improperly handled millis() rollover. Or some kind of very slow memory leak which eventually causes you to run out ram.

I re-read the original post. So you are saying that this fault occured, the night right after you messed with you working code, to do some logging ? [ If it ain't broke, don't mess with it... ]

Can you post the part of your code, which includes the modifications which you made to do the logging ?

Swap the sensor....

void loop() {
 sensors.requestTemperatures();  // call readings from the addresses
  Temp1 = sensorValue(Thermo1);
  Temp2 = sensorValue(Thermo2);  
  Temp3 = sensorValue(Thermo3); 
   diff = Temp2 - Temp1;
   Serial.println(Temp3);

delay(1000);
}

//sensorValue function
float sensorValue (byte deviceAddress[])
{
     Temp = sensors.getTempC (deviceAddress);
}

I don't see how this code can possibly work. The function sensorValue( ) does not return a value, and the variable that it purports to assign a value to, Temp, is a global variable in the sketch. So how can this function be used to set the value of Temp1, Temp2, and Temp3, with the function calls made to it, in loop( ) ?

Surely sensorValue( ) should look something more like this:

//sensorValue function
float sensorValue (byte deviceAddress[])
{
     float temp = sensors.getTempC (deviceAddress);
     return temp ;
}

Then, the code in loop( ) will work.

Here is a news item:

I uploaded that programme and I am looking at the screen right now, and what I see is exactly what I expect to see.

It works.

I thought I had made a mistake, for different reasons, but apparently not.

Well perhaps you can explain how, in your magical version of C, the function sensorValue( ) does not return a value. Is there some hidden default behaviour where, if there is no return statement in a function which is not a void function, a C function returns the last value that was calculated by the function . Is this a defined behaviour of some variant of C, or does it occur because that variable happens to be sitting around on the stack or in register 0, or something ?

Or if you ignore the issue of the lack of a return statement in the non-void function sensorValue( ), and assume that the actual functionality of the function is acheived by its modification of global variables instead of by returning a value, how does the value of the global variable , "Temp" ,assigned by the statement inside sensorValue( ), magically get transfered to the other three global variables Temp1 , Temp2 and Temp3, at the point where sensorValue( ) gets called three times in loop( ) ?

There is a discussion here

http://stackoverflow.com/questions/4644860/function-returns-value-without-return-statement

of how this may seem to work on x86 architecture, which Arduino isn't. It seems much less plausible that it would work on an 8-bit processor with a 32-bit float.

And here

http://msdn.microsoft.com/en-us/library/sta56yeb.aspx

It asserts that if a function has a non-void return type, but no return statement, then the value returned by the function is undefined.

michinyon: Well perhaps you can explain how, in your magical version of C ?

Magical. . [u]That's[/u] the word.

Say it a thousand times, then appreciate the value of the picture.

To create a function with a non-void return type, and then exit from that function without a return statement, or with a return statement that has no value associated with it, is wrong.

Apparently, some compilers tolerate this, because in old-C, you could do this, as long as the calling function does not actually attempt to use the (missing) return value of the function for anything. In the absence of any return statement in the function, the return value is undefined. The compiler cannot always check this loophole, because it cannot necessarily see all the other code where this function is being called from. In C++, it should always be invalid.

In this case, your calling function ( loop( ) ), is attempting to use the return value of the function, it is trying to assign it to a variable. So, the old-C loophole doesn't apply to you. You are assigned an undefined value to Temp1, Temp2, and Temp3 in loop( ).

Apparently, your code works because of two reasons. Firstly, because the compiler unwisely allows it, although the value is undefined. And secondly, because of a coincidence that the last calculation made, has the value still hanging around in the same register that the calling program expects to find its ( undefined ) return value in. This coincidence seems to happen on x86 processors and , as you have apparently demonstrated, on arduino processors too, at least some of the time. You are relying on random undefined behaviour. This might not happen if an interrupt or something happens just at the time that your function is completing its execution.

This sort of coding should not be encouraged. You move your code to a different platform, like a Due, and it will suddenly not work in ways that might not be obvious.

The OP of this thread has not posted the relevant parts of his code. This could explain his problem. After he added the logging function to his code, the lucky coincidence that allows this bogus code of yours to work, no longer applies.

michinyon:
I re-read the original post. So you are saying that this fault occured, the night right after you messed with you working code, to do some logging ? [ If it ain’t broke, don’t mess with it… ]

Can you post the part of your code, which includes the modifications which you made to do the logging ?

To be more precise, I think the error occurred before without me noticing it : I save the min and max value of each parameter in the EEPROM, and read them sometimes via the serial port ; and it has happened several times that I get a 0.00 value for the min external temperature for example… which did not alarm me at the time, as we were in winter !
And, it has happened 2 times the same night before the “fatal” one ! You can see my log of the night attached to this post if you want to take a look at it :wink:

Regarding the modification of the code, I didn’t do anything vital : just added a serial.read function to get a single number (0, 1 or 2) that allow me to chose the way my program displays the data via the serial port, and a IF function to actually display the right thing. Here is the part of the code (some few words are in french, but not important):

if (Serial.available() > 0)
 {
   Mode = Serial.read();
 }
 
 if (Mode == 49)
 {
   Serial.print("Tint ");
   Serial.print(Tint);
   Serial.print(" Text ");
   Serial.print(Text);
   Serial.print(" Hint ");
   Serial.print(Hint);
   Serial.print(" Hext ");
   Serial.print(Hext);
   Serial.print(" Venti ");
   Serial.print(ventilation);
   Serial.print(" Deshum ");
   Serial.print(deshumidification);
   Serial.print(" Radia ");
   Serial.print(chauffage);
   Serial.println();
 }
 else if (Mode == 50)
 {
   Serial.print("Tint : ");
   Serial.print(Tint);
   Serial.println();
   Serial.print("Text : ");
   Serial.print(Text);
   Serial.println();
   Serial.print("Hint : ");
   Serial.print(Hint);
   Serial.println();
   Serial.print("Hext : ");
   Serial.print(Hext);
   Serial.println();
   Serial.print("Venti : ");
   Serial.print(ventilation);
   Serial.println();
   Serial.print("Deshum : ");
   Serial.print(deshumidification);
   Serial.println();
   Serial.print("Radia : ");
   Serial.print(chauffage);
   Serial.println();
   Serial.print("Position servo : ");
   Serial.println();
   Serial.print("Mesuree : ");
   Serial.print(pos);
   Serial.print(" |  Requise : ");
   if (ventilation == 1) Serial.print("326");
   if (ventilation == 0) Serial.print("265");
   Serial.println();
   Serial.println();
 }
 else
 {
   Serial.println();
   Serial.print("Temp interieure : ");  // Affichage des données sur port série 9600
   Serial.println();
   Serial.print("Actuelle : ");
   Serial.print(Tint);
   Serial.print("    ");
   Serial.print("Min : ");
   Serial.print(Tintmin);
   Serial.print("    ");
   Serial.print("Max : ");
   Serial.print(Tintmax);
   Serial.println();
   Serial.println();
   Serial.print("Temp exterieure : ");
   Serial.println();
   Serial.print("Actuelle : ");
   Serial.print(Text);
   Serial.print("    ");
   Serial.print("Min : ");
   Serial.print(Textmin);
   Serial.print("    ");
   Serial.print("Max : ");
   Serial.print(Textmax);
   Serial.println();
   Serial.println();
   Serial.print("Hygrometrie interieure : ");
   Serial.println();
   Serial.print("Actuelle : ");
   Serial.print(Hint);
   Serial.print("    ");
   Serial.print("Min : ");
   Serial.print(Hintmin);
   Serial.print("    ");
   Serial.print("Max : ");
   Serial.print(Hintmax);
   Serial.println();
   Serial.println();
   Serial.print("Hygrometrie exterieure : ");
   Serial.println();
   Serial.print("Actuelle : ");
   Serial.print(Hext);
   Serial.print("    ");
   Serial.print("Min : ");
   Serial.print(Hextmin);
   Serial.print("    ");
   Serial.print("Max : ");
   Serial.print(Hextmax);
   Serial.println();
   Serial.println();
   Serial.print("Energie consommee : ");
   Serial.println();
   Serial.print("Ventil : ");
   Serial.print(Event);
   Serial.print("KWh    ");
   Serial.print("Chauf : ");
   Serial.print(Erad);
   Serial.print("KWh    ");
   Serial.print("Deshum : ");
   Serial.print(Ehum);
   Serial.print("KWh");
   Serial.println();
   Serial.print("TOTALE : ");
   Serial.print(Etot);
   Serial.print("KWh");
   Serial.println();
   Serial.println();
 }

log_RS232.txt (1.1 MB)

You could do it this way, which would still be wrong, but less wrong that what you have got.

void loop()
{
    sensorValue(  Thermo1 );
    Temp1 = Temp ;
    sensorValue( Thermo2 );
    Temp2 = Temp;
    sensorValue ( Thermo3 );
    Temp3 = Temp ;

     // ....
}

Here you are relying on the global value Temp to contain the calculated result of the function, and not using the return value of the non-void function at all. So you still have an undefined function result, but since you don't actually attempt to use it anywhere, it is OK. This version does not rely on any lucky coincidences about how the compiler or the processor manages its registers.

Regarding the modification of the code, ...

If you added all of that code, you might have run out of memory, which can cause strange things to happen.

michinyon: If you added all of that code, you might have run out of memory, which can cause strange things to happen.

No, the biggest part of it (after "else") was already there, and the whole prog is around 21ko out of 30 if I'm correct.

Regarding the temperature request, I don't really understand the problem... I'm using the DallasTemperature library, of which I hopefully used the right syntax at the time... But here is apparently a new one: http://www.milesburton.com/?title=Dallas_Temperature_Control_Library, will that be okay ? :)

Well the comments in posts 5-14 on this thread, were about the dodgy code in post 4, not about your code.

The problem with the code in post 4, was not about any problem with the one-wire library code, but with what was done in the sketch right after getting the temperature using he one-wire library code.

So, as far as I know, there isn't an issue with the one-wire code. But if you originally followed the same bad advice or bad example as the other poster did, you may have the same issue. There are a lot of very bad examples of how to access sensors on the internet, on youtube, github, instructables, etc. So you might want to check your part of the code, to see if you had the same issue.

As for the code you added, all of those extra strings in the print( ) and println( ) function calls, go into the ram memory, not the flash memory. So you might be running out of ram memory, even though you have plenty of flash memory available. The solution to this is to use the method of forcing those strings to be placed into the flash memory, not the ram memory, using the PROGMEM and F macros. Lots of other threads about this.

There is also a method to find out how much ram you are actually using.

I don't know if the "new" version of that library is better. It doesn't seem to have a clear date.

Note that there are two levels of library for these devices. For example, the onewire.h library and then the DallasTemperature.h library. The description of that miles burton library mentions a newer version called "Onewire 2" which is newer and better.

I don't know if messing with the libraries will solve your problem, because we don't know for sure what your problem is. It might.

I notice odd readings from my ds18b20 devices from time to time, perhaps it is inevitable, a better approach might be to make your own logic for turning your heater on and off, more robust, somehow.