Please update OneWire page for DS18B20

So I am very excited because I plugged a DS18B20 into my arduino and it worked. It is happily spitting out these values.

R=28 9E 91 8C 1 0 0 A6 P=1 A2 1 4B 46 7F FF E 10 CRC=D8

I know next to nothing about programming and got this to work by simply copying and pasting the code from this page Arduino Playground - OneWire and changing the family code to 0X28 and adding the one wire library to the arduino programming environment. The next thing I would like to know is how to write the code to have the arduino convert the hex data above to a readable temperature format (i.e. 35 degrees C or something.....better yet....a farenheit conversion)

Okay I'm starting to figure out the format of the data. The first two HEX numbers after the P=1 is the LSByte and MSbyte respectively. So that gives us 1A2 or 418 and converting to Celsius means 418*.0625 = 26.125 degrees celsius. So the question is how do I write the C code to first pull out those two bytes, switch them around from LSB MSB to MSB LSB and then multiply that number by .0625?

So the question is how do I write the C code to first pull out those two bytes, switch them around from LSB MSB to MSB LSB and then multiply that number by .0625?

In AVR C, an 'int' is a two-byte integer, and so you can combine the MSB and LSB of the temperature value into an 'int' value by saying

int rawtemp = (data[1] << 8) + data[0];

That's it - 'rawtemp' is now the signed temperature, multiplied by 16 (for the DS18B20). To get floating point fahrenheit and centigrade temperatures, you would say

double tempc, tempf;
tempc = (double)rawtemp / 16.0;
tempf = (tempc * 1.8) + 32.0;

Excellent. That worked great. I did run into the problem of Serial.print dropping off everything after the decimal. Is there a command similar to Serial.print that doesn't truncate the number? I put in a few extra lines of code to increase the precision of the number I was seeing but of course there is no decimal.

double tempc, tempf;
tempc = (double)rawtemp / 16;
tempc = tempc * 1000;
tempf = (((tempc / 1000) * 1.8) + 32.0) * 1000;
Serial.print("tempc=");
Serial.print(tempc,DEC);
Serial.print(" tempf=");
Serial.print(tempf,DEC);

Now this is the output of my two DS18B20's

tempc=22875 tempf=73175 R=28 9E 91 8C 1 0 0 A6 P=1 6E 1 4B 46 7F FF 2 10 CRC=71

tempc=22875 tempf=73175 R=28 36 71 8C 1 0 0 81 P=1 6E 1 4B 46 7F FF 2 10 CRC=71

Is there a command similar to Serial.print that doesn't truncate the number?

Not that I'm aware of, but I'm not an expert. What I did when I first wanted to get nicely formatted temperatures output to the console was the following...

  int temp_raw = (data[1] << 8) + data[0];
  if (temp_raw > 0) {
    temp_int = temp_raw >> 4;
    temp_frac = temp_raw & 0x0F;
  }
  else {
    int temp_abs = -temp_raw;
    temp_int = - (temp_abs >> 4);
    temp_frac = temp_raw & 0x0F;
  }
  tempc = (double)temp_raw / 16.0;
  tempf = (tempc * 1.8) + 32.0;

  int tempf_int, tempf_tenths;
  tempf_int = int(tempf);
  if (tempf > 0) {
    tempf_tenths = tempf*10 - tempf_int*10;
  } 
  else {
    tempf_tenths = tempf*10 + tempf_int*10;
  }

  Serial.print(count);
  Serial.print("  Temperature = ");
  Serial.print(temp_int);
  Serial.print(" ");
  Serial.print(temp_frac);
  Serial.print("/16 C (");

  Serial.print(tempf_int);
  Serial.print(".");
  Serial.print(tempf_tenths);
  Serial.println(" F)");

It's not elegant, but it gets the job done. For my temperature logger, I leave the temperature as a scaled integer on the Arduino and convert it to deg Fahrenheit only after it's been uploaded to my laptop.

Okay I think I understand what most of those lines of code do but can you explain what this line is saying?

temp_frac = temp_raw & 0x0F;

You also have this line but I don't see an integer called "count".

Serial.print(count);

Does this have something to do with the fact that you are using it as a temperature logger? As in you have an integer called count somewhere in there that increments +1 every iteration of the program to keep track of the temperatures?

Sorry for all of the questions. I am very green when it comes to any kind of programming but I am catching on slowly.

Okay I think I understand what most of those lines of code do but can you explain what this line is saying?

temp_frac = temp_raw & 0x0F;

This copies the least-significant four bits of temp_raw to temp_frac. The '&' operator does a bitwise AND between its two arguments, and 0x0F is the hexadecimal for 00001111.

You also have this line but I don't see an integer called "count".

Serial.print(count);

Does this have something to do with the fact that you are using it as a temperature logger? As in you have an integer called count somewhere in there that increments +1 every iteration of the program to keep track of the temperatures?

Sorry about that! I didn't notice I had left that in there. Yes, this is the count of the number of temperature readings I've taken.

Sorry for all of the questions. I am very green when it comes to any kind of programming but I am catching on slowly.

You never need to apologize for asking questions. The only way to learn is to try stuff out and ask questions when you run into problems.

temp_frac = temp_raw & 0x0F;

I must say.....that is a really slick way to pull out just the bits that you want and throw out the rest. I appreciate this.

Having fun learning to use the DS18B20. It looks like it can take a while to read the temperature via the library. A second or more and the Arduino can't do anything else during this time. I guess the library calls delay().

I think I'll see if there is a way to read the data in a non-blocking manner. I think most of the time is just holding the line high to provide power in parasitic mode, other things could be done during that time.

I'd like to read the temperature fairly often, but still service 5 buttons.

It looks like it can take a while to read the temperature via the library. A second or more and the Arduino can't do anything else during this time. I guess the library calls delay().

The reason it takes so long is that you need to give the DS18B20 750ms to take a temperature reading. The commands to start that process and to actually read the temperature from the device are fairly quick. Luckily for you, this delay is executed in user code (not in the OneWire library functions), so it should be easy for you to do other things in that period; just be sure not to try to read the temperature before the chip has been given enough time to record it.

If you have any more detailed questions about how to do this, just post your code here and I'll try to help.

Hello, im new here! thanks for all the inforrmation. can anyone please help me make the VB6 code for the pc thermometer ds1820. Thank you very much for your reply..

Hi i did a web server showing all the DS18B20 attach and printint the temperature on a web page.
If anyone wants it!
Actually i just grab some code here and there (on this site) and match every thing so it work for my application

/*
 * Multiport Web Server
 *
 * A simple web server that shows
 * the value of the analog and digital input pins.
 *
 * port 80: human readable page
 * port 8080: machine readable page (csv format)
 */
#include <OneWire.h>
#include <Ethernet.h>
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
byte ip[] = { 192, 168, 1, 123 };
//byte gateway[] = { 192, 168, 0, 254 };
//byte subnet[] = { 255, 255, 255, 0 };

Server server1(80); // server for human beings
Server server2(8080); // server for machines
// DS18S20 Temperature chip i/o

OneWire ds(9);  // on pin 10

void setup()
{
  for (int i = 2 ; i < 8; i++){
    pinMode(i, INPUT);
    //digitalWrite(i, HIGH);
  }
  //Ethernet.begin(mac, ip, gateway, subnet);
  Ethernet.begin(mac, ip);
  server1.begin();
  server2.begin();
}

void loop()
{
  byte i;
  byte present = 0;
  byte data[12];
  byte addr[8];


  Client client1 = server1.available();
  Client client2 = server2.available();
  if (client1) {
    boolean current_line_is_blank = true;
    while (client1.connected()) {
      if (client1.available()) {
        char c = client1.read();
        if (c == '\n' && current_line_is_blank) {
          client1.println("HTTP/1.1 200 OK");
          client1.println("Content-Type: text/html");
          client1.println();

          
//            if ( !ds.search(addr)) {
//              // No more adresses
//              ds.reset_search();
//            }
            
            //else {
            while (ds.search(addr)) {
              client1.print("A=");
              for( i = 0; i < 8; i++) {
                client1.print(addr[i], HEX);
                client1.print(" ");
              }

              if ( OneWire::crc8( addr, 7) != addr[7]) {
                client1.print("CRC is not valid!\n");
                client1.println("
");

                //      return;
              }

              if ( addr[0] != 0x28) {
                client1.print("Device is not a DS18S20 family device.\n");
                client1.println("
");

                //      return;
              }

              ds.reset();
              ds.select(addr);
              ds.write(0x44,1);         // start conversion, with parasite power on at the end

              delay(1000);     // maybe 750ms is enough, maybe not
              // we might do a ds.depower() here, but the reset will take care of it.

              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();
              }
              int rawtemp = (data[1] << 8) + data[0];
              int tempca = rawtemp / 16.0;
              int tempcb = rawtemp % 16;

              client1.print(" Celcius = ");
              client1.print(tempca);
              client1.print(".");
              client1.print(tempcb);
              client1.println("
");
            }
            // No more device then reset the search
            ds.reset_search();




/*
          for (int i = 0; i < 6; i++) {
            client1.print("analog input ");
            client1.print(i);
            client1.print(" is ");
            client1.print(analogRead(i));
            client1.println("
");
          }
          for (int i = 2; i < 8; i++) {
            client1.print("digital input ");
            client1.print(i);
            client1.print(" is ");
            if (digitalRead(i)) {
              client1.print("HIGH");
            } else {
              client1.print("LOW");
            }
            client1.println("
");
          }
*/
          break;
        }
        if (c == '\n') {
          current_line_is_blank = true;
        } else if (c != '\r') {
          current_line_is_blank = false;
        }

      }
    }
  
    delay(10);
    client1.stop();
  }
  
  if (client2) {
    boolean current_line_is_blank = true;
    while (client2.connected()) {
      if (client2.available()) {
        char c = client2.read();
        if (c == '\n' && current_line_is_blank) {
          client2.println("HTTP/1.1 200 OK");
          client2.println("Content-Type: text/html");
          client2.println();
          for (int i = 0; i < 6; i++) {
            if (i != 0)
              client2.print(",");
            client2.print(analogRead(i));
          }
          for (int i = 2; i < 8; i++) {
            client2.print(",");
            client2.print(digitalRead(i));
          }
          break;
        }
        if (c == '\n') {
          current_line_is_blank = true;
        } else if (c != '\r') {
          current_line_is_blank = false;
        }
      }
    }
    delay(10);
    client2.stop();
  }

}

Can you get this to work in Flash??

where do i get the onewire.h?

Onewire.h is included with the ide.

Just use:
#include <OneWire.h>

As per Patgadget's example.

Gordon

You need to download and install the OneWire library - it's not included as part of the Arduino distribution. You should download the most recent version of the library from
this page

http://homepage.mac.com/wtpollard/Software/FileSharing7.html

unzip it, and copy the OneWire directory into your Arduino hardware/libraries folder. There's a page on the Arduino playground with some examples of how to use the library.

http://www.arduino.cc/playground/Learning/OneWire

Hi all,

I have a project that is way beyond my capabilites (because they are non-exisitant at this point) using the Adruino with a C#
I'm trying to do something similar to this

but, using 2 to 4 DS18B20s and C# instead of processing.

I got the Arduino talking to C# via serial but I have no idea how to format the data into something usable.

Thanks for any help.

-Wes

Hi,

has anyone run into a problem using both the DS1307 (sparkfun rtc module) with the DS18B20 temp sensor? Im prototyping a data logger that writes temp, light, wind speed and voltage values to an sd card running on an atmega 168. Seems to be some interference between the wire.h and the OneWire.h libraries since I can get either to work without the other. Is it an I2C communication problem and/or ram?
I am using the ds18b30 code from the playground with modifications and the ds1307 from: Hobby Robotics » Page not found.

at the moment the temp is reading and only part of the time/date working, but after much trial and error.

any suggestions would be super helpful.
thanks in advance!

first thank you guys for the above info. what really helped me was tkbyd's first link: http://www.phanderson.com/arduino/ds18b20_1.html. its much simpler IMO than the OneWire library, however its made to talk to only one sensor per input pin... but thats cool with me.

the only thing i'm wondering about (in hope to speed up the sensor read time) is why the DS18B20 has to wait a full second when pulling the bus high after the 0x44 command and then why you need to do a reset followed by a 0xCC BEFORE you send the read command 0xBE. can anyone explain this?

the only thing i'm wondering about (in hope to speed up the sensor read time) is why the DS18B20 has to wait a full second when pulling the bus high after the 0x44 command and then why you need to do a reset followed by a 0xCC BEFORE you send the read command 0xBE. can anyone explain this?

Actually, you only need to wait a maximum of 750-milliseconds for
the 18B20 to perform the digitization of the current temperature.
This is the maximum time needed for all 12-bits of precision BUT
if you can get by with 9-bit precision (+/- 0.5 degree C and I don't
see why you couldn't) then the wait is at most 93.75-milliseconds.
These numbers come from the 18B20 spec sheet. Keep in mind
that you need to tell the 18B20 that you want only 9-bits of precision
by appropriately setting its configuration register in the scratchpad.

Why do you need to issue a 0xCC after the reset but before the 0xBE?
After a 1-wire bus reset all attached devices are listening to hear which
one gets selected with a SELECT command (0x55). This presumes
multilple devices on the bus and will determine which of the devices on
the bus the ReadScratchPad command (0xBE) will apply to so you can
read the temperature. Since you've only got one sensor on each pin you
don't need to select which sensor to read so the SkipROM command
(0xCC) is issued to tell the lone sensor that the next set of commands
are for you. If you don't do this your 18B20 will merrily sit there waiting
to be selected.

How's that?

I've tested the sample code of converting HEX to Temperature
http://www.arduino.cc/playground/Learning/OneWire

and found a slip of the pen

 LowByte = data[0];
  HighByte = data[1];

should be

 LowByte = data[0];
  HighByte = present;

otherwise got a wrong temperature like the following

R=28 90 9 60 0 0 0 CC P=1 CD 1 4B 46 7F FF 3 10 4A CRC=4A
28.81
R=28 CC FA 5F 0 0 0 A5 P=1 D3 1 4B 46 7F FF D 10 7B CRC=7B
29.18
R=28 2 ED 5F 0 0 0 4 P=1 E5 5 FF FF 7F FF B 10 2D CRC=2D
94.31
No more addresses.

0x01E5=30.31/6.25 0x05E5=94.31/6.25