DS18B20 inaccurate temperatures?

Hi all, having a bit of an issue (I think!)

I've got 4 DS18B20 sensors deployed in my house in a star network (not recommended I know..) with a 1k6 pullup at the arduino.

Now, what seems to be happening, is I've got 2 of the sensors which appear to be displaying odd values (not consistent with other thermometers.) The other two, I havent checked, but at a guess, would say they are the same......

Heres what I mean;

Outside - Current 1.26 (according to dallas) / Thermometers (car & mercury) -1 / 0

Office - Current 19.8 / Thermometer 21.2

I am using the sample code (albeit part of a bigger program - viewable here > http://www.dundeesmarthome.net/wp-content/uploads/2010/10/HeatingController.txt )

Anybody any ideas why I'd be seeing this?

Scott

First check if the unchecked sensors if they are correct, what are you using as reference? is it a calibrated temp. meter?

I have once taped two DS sensors together and they diff'd 0.125 C so minor diff's may be expected. From the datasheet http://pdfserv.maxim-ic.com/en/ds/DS18B20.pdf page 19 Note 3.

Thermometer -10°C to +85°C ±0.5
Error tERR -55°C to +125°C [glow]±2 °[/glow]

Which resolution do you use ? 9,10,11,12 bit?

With respect to the star network, are all lines equal in length?

When using DS18's I allways use this lib, you might give it a try. http://milesburton.com/index.php/Dallas_Temperature_Control_Library

the sensors which appear to be displaying odd values

Odd values would be thermometer 21, sensor 89. Small differences, as you reported, can be attributed to variations in sensors and thermometers, and to variations in voltage levels that the Arduino is seeing.

Some code, and a description of how you are powering the Arduino would be useful.

Hi,

I believe the sensors are currently running in 9 bit mode, havent changed anything else from the default sample code.

The arduino is powered from a 240vac wall adapter (outputting 7.5v into the regulator onboard the arduino)

Lines are more or less the same length, may be a few meters in it, but nothing major.

I know some temperature difference is inevitable, but for something marketed as a high-precision sensor I’m beginning to think something is out!

Code is below;

//Function: updateCurrentTempValues()
//Params: none
//Return: void
//Description:  Polls the One-wire temp sensors and
//              updates the sensor list with the new
//              values
void updateCurrentTempValues()
{
  int HighByte, LowByte, TReading, SignBit, Tc_100, Fract;
  double TReadingd;
  boolean isValidAddr = false;
  double curTemp;

  for (int count = 0; count < 8; count++)
  {
    byte i;
    byte present = 0;
    byte data[12];
    byte addr[8];
    int id = 0;

    if ( !ds.search(addr)) {
        ds.reset_search();
        return;
    }
    
    for(int i = 0; i < _gList.size; i++)
    {      
      if(memcmp(addr, _gList.list[i].sensorId, ADDRESS_SIZE) == 0)
      {                
        isValidAddr = true;    
        id = _gList.list[i].id;        
      }      
    }
    
    if(isValidAddr)
    {
      if ( OneWire::crc8( addr, 7) != addr[7] ||  addr[0] != 0x28)
      {
          //either wrong address or failed a CRC check, bail out
          return;
      }

      ds.reset();
      ds.select(addr);
      ds.write(0x44); // start conversion, with *NO* parasite power
      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();
      }
  
      LowByte = data[0];
      HighByte = data[1];
      TReadingd = (HighByte << 8) + LowByte;
      SignBit = TReading & 0x8000;  // test most sig bit
  
      if (SignBit) // negative
      {
        TReadingd *= -1.0;
      }
      curTemp = ((6 * TReadingd) + TReadingd / 4) / 100 ;    // multiply by (100 * 0.0625) or 6.25
      
      for(int i = 0; i < _gList.size; i++)
      {
        if (id == _gList.list[i].id)
        {
          _gList.list[i].prevTemp = _gList.list[i].curTemp;
          _gList.list[i].curTemp = curTemp;          
        }
      }
    }
    isValidAddr = false; //reset for next itter
  }
}

If the sensors are at differnt positions in the room that can account for a surprising variation. The difference between the temperature of the air close to an outside wall and the air close to an inside wall and at different heights can account for a 3 degree Celsius variation. I have my heating controlled by an arduino and Dallas Ds1820s and moving the sensor no more than a couple of feet dramatically affected the overall room temperature. I accept that what my ‘outside’ dallas tells me is often 3 degrees warmer than what the car says because whilst its open to the outside air its close to the house wall which is invariably warmer than in the road. On a cold morning like we’re having in the UK, the frost on the pavement nearest the house always thaws first…

I know some temperature difference is inevitable, but for something marketed as a high-precission sensor I'm beginning to think something is out!

Have you checked if the difference is a or predictable value ? That could be (easily) solved in code.

My experience is that the sensors are quite stable (not saying accurate), I am now using three of them to monitor my central heating behavior and they only fluctuate in the last bit (at 11 bit resolution)

An often used piece of code to prevent spikes is averaging with previous measurements. play with alpha to find a value that works for you. (pseudocode snippet)

  float alpha = 0.7;
  T = ReadTemp();
  Tavg = T * alpha + (1-alpha) * Tavg;
  Serial.println(T,3);
  Serial.println(Tavg,3);

Pluggy - that could well explain what I'm seeing - the outdoor dallas reads 1.87, whereas the mercury reads 0 - and the dallas is in 'free air' but still near the house.

The difference does seem to be predicatable, the only thing being it reads too high outside (by about 1.5 - 2 degrees) and low inside (by the same again)

I think the resolve is probably to add an offset in the software - I think we are maybe only reading at 9 bit resolution? Would there be any benefit in switching to 11?

Scott

9 bit resolution? Would there be any benefit in switching to 11?

As Pluggy's storie makes sense (and it does imho) it will not bring 1.87 nearer to 0. it will provide more digits behind the . e.g 1.8625 so you can read the diff more accurate.

As the proof is in the pudding test, you should read on 11 bits or even 12 and see how much it fluctuates. Takes less than 15 minutes to try I guess. If there is too much "noise" you will notice.

The difference does seem to be predicatable

If it is, even only partial, a software correction can be valuable.

In summer, when the heating isn't on, my 'outside' dallas and the car's thermometer often match. When its windy, and the air is being moved rapidly they move closer together as well. Software ain't so simple......

I ran all my DS1820 together as a trial before deploying them, they all read to within 0.125 degrees of each other and the same as a standard spirit thermometer (as close as I could see anyway) next to them. At 9 bit resolution they read to the nearest half a degree instead of the nearest 16th of a degree at 12 bit. Having run mine both ways, they behave as expected (it reads 9.5 instead of 9.625....)

http://pluggy.is-a-geek.com/

In my opinion, having stuff so accurate can often cause unnecessary worry. :)

      curTemp = ((6 * TReadingd) + TReadingd / 4) / 100 ;    // multiply by (100 * 0.0625) or 6.25

TReadingd is an integer. Dividing by 4 introduces some error there, as truncation occurs. curTemp is a float, but all the values on the right side are integers, so the calculation produces an integer, which is then stored in a float. I'm not sure this is what you want to have happening.

That treatment of negative values in that program is one way to handle the data for 32-bit integer data types, but is just flat wrong for 16-bit ints.

Furthermore…

Why the heck would the expression be so complicated? For 12-bit resolution, all you want to do is divide by 16, right? (Same as multiplying by 0.0625) Well, just do it. (And be sure to use floating point arithmetic as PaulS pointed out.)

For Arduino (avr-gcc) and its 16-bit ints, the entire calculation can look like:

    int HighByte, LowByte;
    byte data[12];
    int TReadingd;
    float curTemp;
.
.
.
      LowByte = data[0];
      HighByte = data[1];
      TReadingd = (HighByte << 8) + LowByte;
      curTemp = TReadingd / 16.0;

Regards,

Dave