Go Down

Topic: 1 Wire DS18B20 (Read 3 times) previous topic - next topic

NickPyner

Keep us posted, Greg.

Needless to say, my remote installations will be on the internet. In one station this is going to be painless. In another, it might not be and I need to plan for any contingency. This is not about such huge distances, just local built environment making the internet connection difficult.  Right now I am about to explore bluetooth but I will be very interested to hear how you go.

stoopkid

I am powering the sensor from the arduino's 5v.

I have applied the patches, the second results I posted are from after patching. They are the same results as the Dallas Library.

The sketch I used for the last results is this:
Code: [Select]
#include <OneWire.h>
#include <DallasTemperature.h>

// Data wire is plugged into port 2 on the Arduino
#define ONE_WIRE_BUS 2
#define TEMPERATURE_PRECISION 9

// 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);

// arrays to hold device addresses
DeviceAddress insideThermometer, outsideThermometer;

void setup(void)
{
  // start serial port
  Serial.begin(9600);
  Serial.println("Dallas Temperature IC Control Library Demo");

  // Start up the library
  sensors.begin();

  // locate devices on the bus
  Serial.print("Locating devices...");
  Serial.print("Found ");
  Serial.print(sensors.getDeviceCount(), DEC);
  Serial.println(" devices.");

  // report parasite power requirements
  Serial.print("Parasite power is: ");
  if (sensors.isParasitePowerMode()) Serial.println("ON");
  else Serial.println("OFF");

  // assign address manually.  the addresses below will beed to be changed
  // to valid device addresses on your bus.  device address can be retrieved
  // by using either oneWire.search(deviceAddress) or individually via
  // sensors.getAddress(deviceAddress, index)
  //insideThermometer = { 0x28, 0x1D, 0x39, 0x31, 0x2, 0x0, 0x0, 0xF0 };
  //outsideThermometer   = { 0x28, 0x3F, 0x1C, 0x31, 0x2, 0x0, 0x0, 0x2 };

  // search for devices on the bus and assign based on an index.  ideally,
  // you would do this to initially discover addresses on the bus and then
  // use those addresses and manually assign them (see above) once you know
  // the devices on your bus (and assuming they don't change).
  //
  // method 1: by index
  if (!sensors.getAddress(insideThermometer, 0)) Serial.println("Unable to find address for Device 0");
  if (!sensors.getAddress(outsideThermometer, 1)) Serial.println("Unable to find address for Device 1");

  // method 2: search()
  // search() looks for the next device. Returns 1 if a new address has been
  // returned. A zero might mean that the bus is shorted, there are no devices,
  // or you have already retrieved all of them.  It might be a good idea to
  // check the CRC to make sure you didn't get garbage.  The order is
  // deterministic. You will always get the same devices in the same order
  //
  // Must be called before search()
  //oneWire.reset_search();
  // assigns the first address found to insideThermometer
  //if (!oneWire.search(insideThermometer)) Serial.println("Unable to find address for insideThermometer");
  // assigns the seconds address found to outsideThermometer
  //if (!oneWire.search(outsideThermometer)) Serial.println("Unable to find address for outsideThermometer");

  // show the addresses we found on the bus
  Serial.print("Device 0 Address: ");
  printAddress(insideThermometer);
  Serial.println();

  Serial.print("Device 1 Address: ");
  printAddress(outsideThermometer);
  Serial.println();

  // set the resolution to 9 bit
  sensors.setResolution(insideThermometer, TEMPERATURE_PRECISION);
  sensors.setResolution(outsideThermometer, TEMPERATURE_PRECISION);

  Serial.print("Device 0 Resolution: ");
  Serial.print(sensors.getResolution(insideThermometer), DEC);
  Serial.println();

  Serial.print("Device 1 Resolution: ");
  Serial.print(sensors.getResolution(outsideThermometer), DEC);
  Serial.println();
}

// function to print a device address
void printAddress(DeviceAddress deviceAddress)
{
  for (uint8_t i = 0; i < 8; i++)
  {
    // zero pad the address if necessary
    if (deviceAddress[i] < 16) Serial.print("0");
    Serial.print(deviceAddress[i], HEX);
  }
}

// function to print the temperature for a device
void printTemperature(DeviceAddress deviceAddress)
{
  float tempC = sensors.getTempC(deviceAddress);
  Serial.print("Temp C: ");
  Serial.print(tempC);
  Serial.print(" Temp F: ");
  Serial.print(DallasTemperature::toFahrenheit(tempC));
}

// function to print a device's resolution
void printResolution(DeviceAddress deviceAddress)
{
  Serial.print("Resolution: ");
  Serial.print(sensors.getResolution(deviceAddress));
  Serial.println();   
}

// main function to print information about a device
void printData(DeviceAddress deviceAddress)
{
  Serial.print("Device Address: ");
  printAddress(deviceAddress);
  Serial.print(" ");
  printTemperature(deviceAddress);
  Serial.println();
}

void loop(void)
{
  // call sensors.requestTemperatures() to issue a global temperature
  // request to all devices on the bus
  Serial.print("Requesting temperatures...");
  sensors.requestTemperatures();
  Serial.println("DONE");

  // print the device information
  printData(insideThermometer);
  printData(outsideThermometer);
}


Nick, your code gives me these results:
Code: [Select]
  Input temp : -36.06      Output temp   : -36.50      diff  : -0.44      flow  l/min   : 10.00      power (kW)   : 10.16
  Input temp : -36.06      Output temp   : -36.50      diff  : -0.44      flow  l/min   : 10.00      power (kW)   : 10.16
  Input temp : -36.06      Output temp   : -36.50      diff  : -0.44      flow  l/min   : 10.00      power (kW)   : 10.16
  Input temp : -36.00      Output temp   : -36.50      diff  : -0.50      flow  l/min   : 10.00      power (kW)   : 10.11



This code from the hacktronics page give me a similar result(yes these are my addresses):
Code: [Select]
// This Arduino sketch reads DS18B20 "1-Wire" digital
// temperature sensors.
// Tutorial:
// http://www.hacktronics.com/Tutorials/arduino-1-wire-tutorial.html

#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);

// Assign the addresses of your 1-Wire temp sensors.
// See the tutorial on how to obtain these addresses:
// http://www.hacktronics.com/Tutorials/arduino-1-wire-address-finder.html

DeviceAddress insideThermometer = { 0x28, 0x18, 0x9E, 0xCF, 0x00, 0x00, 0x00, 0x52 };
DeviceAddress outsideThermometer = { 0x28, 0x6F, 0x73, 0xD1, 0x00, 0x00, 0x00, 0x54 };

void setup(void)
{
  // start serial port
  Serial.begin(9600);
  // Start up the library
  sensors.begin();
  // set the resolution to 10 bit (good enough?)
  sensors.setResolution(insideThermometer, 10);
  sensors.setResolution(outsideThermometer, 10);
}

void printTemperature(DeviceAddress deviceAddress)
{
  float tempC = sensors.getTempC(deviceAddress);
  if (tempC == -127.00) {
    Serial.print("Error getting temperature");
  } else {
    Serial.print("C: ");
    Serial.print(tempC);
    Serial.print(" F: ");
    Serial.print(DallasTemperature::toFahrenheit(tempC));
  }
}

void loop(void)
{
  delay(2000);
  Serial.print("Getting temperatures...\n\r");
  sensors.requestTemperatures();
 
  Serial.print("Inside temperature is: ");
  printTemperature(insideThermometer);
  Serial.print("\n\r");
  Serial.print("Outside temperature is: ");
  printTemperature(outsideThermometer);
  Serial.print("\n\r\n\r");
}

results:
Code: [Select]
Getting temperatures...

Inside temperature is: C: -35.75 F: -32.35

Outside temperature is: C: -36.25 F: -33.25




So basically with all of these different codes and libraries, I am getting consistent results but they are not accurate. Could there be a problem with my chips? What else could be going on?

Thanks

dhenry

There are something seriously wrong with your code (some of which are quite obvious).

For example, the first sensor returns 0xf801 -> that should have been translated into a negative temperature but you got 1000+c.

Read the datasheet and  understand what 9-bit or 10-bit resolution means, and what 2's complement means.

NickPyner

Quote from: stoopkid

Could there be a problem with my chips? What else could be going on?


I don't think there is the slightest need to understand two complements in order to work that out. The answer is "very probably" to the first, and "not much" to the second.

I'm afraid I sent you a later version of my sketch with some dummy commands in it but that is irrelevant. What is relevant is that the Hacktronics DS18B20 section works perfectly. In the light of that, the fact that your code gives results consistent with mine clearly suggests there is nothing wrong with that either. Further, even in the unlikely event that your code isn't kosher, that is not your real problem.

So there are really only three things that can be wrong.

1. The Arduino, presumably proven OK by other means

2. The chips

3. The connection between them.

Addressing item 3 first, if you wire the chips the wrong way round, they get seriously hot. Unfortunately, I can't recall what reading they produce, if any. If this is what has happened, you won't be left in any doubt about it, but they will also survive - if you wake up to it reasonably quickly. If you have done a sloppy job soldering up a proto shield, I guess it is possible to get spurious signals. I don't know anything about that but I suspect they would not be consistent.

After that, I can't see that there is much left, and the bone points to item 2.

On reflection, The only thing that points away from faulty chips is the consistency. That would suggest that both are faulty, and the fault is the same, which sounds a bit too much of a coincidence.
Hummm... In the light of that, I suggest you check the wiring order. Trust me, if one is wrong, the other will be too. That's consistency.... You might even get a quick test by touching the probe - briefly. Indeed I suggest you do this before you read up on twos complements.

el_supremo

Let's start with something that is known to work. The code below works on a Duemilanove wired as described here.
For parasite power the DS18B20 is wired so that the two outer leads are connected to ground. The middle lead has a 1.5k pullup resistor to +5V. The middle lead is also connected to pin 8 on the Arduino. Then run this code:
Code: [Select]

#include <OneWire.h>

// http://datasheets.maxim-ic.com/en/ds/DS18B20.pdf

// OneWire DS18S20, DS18B20, DS1822 Temperature Example
//
// http://www.pjrc.com/teensy/td_libs_OneWire.html
// The two bugs in the conversion of the temperature have been fixed.
// The first bug didn't handle the precision correctly for anything
// other than 12 bits.
// The second bug was that the temperature was converted as an
// unsigned int which meant that it wouldn't convert a negative
// temperature correctly.

OneWire  ds(8);

// SELECT a precision here
// t_precision #bits -  delay(ms)
//      0        9   -   93.75
//      1       10   -  187.5
//      2       11   -  375
//      3       12   -  750
#define ds18b20_PRECISION 2
unsigned char t_precision = ds18b20_PRECISION;

// DS18B20 address data
byte addr[8][8];
byte data[12];
const unsigned char t_mask[4] = {
  0x7, 0x3, 0x1, 0x0};

void print_rom(byte *p)
{
  Serial.print("ROM =");
  for(int i = 0; i < 8; i++) {
    Serial.write(' ');
    if(*p < 10)Serial.print(" ");
    Serial.print(*p++, HEX);
  }
  Serial.println(" "); 
}


void setup(void)
{
  byte i,numdev;
  byte present = 0;
  byte type_s;
  float celsius, fahrenheit;

  Serial.begin(9600);
  i = 0;
  Serial.println("");
  Serial.println("");
  while(ds.search(addr[i])) {
    if (OneWire::crc8(addr[i], 7) != addr[i][7]) {
      print_rom(addr[i]);
      Serial.println("CRC is not valid! - ignored");
      continue;
    }
    print_rom(addr[i]);
    i++;
  }
  if(i == 0) {
    Serial.println("Nothing found");
    Serial.println();
    ds.reset_search();
    delay(250);
    return;
  }
  numdev = i;

  for(int j=0;j<numdev;j++) {
    Serial.println();
    // This clears the alarm registers and sets the precision
    ds.select(addr[j]);   
    ds.write(0x4E,0);
    // write zero into the alarm registers
    ds.write(0,0);
    ds.write(0,0);
    // and write t_precision into the configuration register
    // to select the precision of the temperature
    ds.write(t_precision << 5,0);
    // Write them to the EEPROM
    ds.write(0x48,1);

    delay(20);
    ds.depower();
    // the first ROM byte indicates which chip
    switch (addr[j][0]) {
    case 0x10:
      Serial.print("  Chip = DS18S20 ");  // or old DS1820
      type_s = 1;
      break;
    case 0x28:
      Serial.print("  Chip = DS18B20 ");
      type_s = 0;
      break;
    case 0x22:
      Serial.print("  Chip = DS1822  ");
      type_s = 0;
      break;
    default:
      Serial.println("Device is not a DS18x20 family device.");
      continue;
    }
    print_rom(addr[j]);

    ds.reset();
    ds.select(addr[j]);
#define PARASITE
#ifdef PARASITE
    ds.write(0x44,1);         // start conversion, with parasite power on at the end
#else
    ds.write(0x44,0);
#endif
    delay(1000);

    // we might do a ds.depower() here, but the reset will
    // take care of it.
    present = ds.reset();
    ds.select(addr[j]);   
    ds.write(0xBE,0);         // Read Scratchpad

    Serial.print("present=");
    Serial.print(present,HEX);
    Serial.print(" prec=");
    Serial.print(t_precision);
    Serial.print(" Data = ");
    for ( i = 0; i < 9; i++) {           // we need 9 bytes
      data[i] = ds.read();
      Serial.print(data[i], HEX);
      Serial.print(" ");
    }
    Serial.print(" CRC=");
    Serial.print(OneWire::crc8(data, 8), HEX);
    Serial.println();

    // BUG - this must NOT be unsigned otherwise it won't handle
    // negative temperatures.
    int raw = (data[1] << 8) | data[0];
    // The original version of this code had a bad bug here which
    // only worked when it was reading with 12-bit precision.
    // This code fixes it (and emailed the author).
    //  int cfg = (data[4] & 0x60) >> 5;
    // For now, override the precision stored in the device until I can
    // figure out why the code is not setting it.
    int cfg = t_precision;
    raw &= ~t_mask[cfg];
    celsius = (float) raw / 16.0;
    Serial.print("  Temperature = ");
    Serial.print(celsius,4);
    Serial.println(" Celsius");
    //  fahrenheit = celsius * 1.8 + 32.0;
    //  Serial.print(fahrenheit);
    //  Serial.println(" Fahrenheit");

  } // END OF FOR J LOOP

}


void loop(void)
{
}


It produces this output:
Code: [Select]

ROM = 28 B9 E6 79  3  0  0 16

  Chip = DS18B20 ROM = 28 B9 E6 79  3  0  0 16
present=1 prec=2 Data = 53 1 4B 46 7F FF D 10 E9  CRC=E9
  Temperature = 21.1250 Celsius


This code scans the bus so you don't need to know the address of the chip.

Pete

Go Up