Go Down

Topic: Please update OneWire page for DS18B20 (Read 6 times) previous topic - next topic

jerseyguy1996

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 http://www.arduino.cc/playground/Learning/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)
Arduino Uno;
Mega328

jerseyguy1996

Quote
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 http://www.arduino.cc/playground/Learning/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?  
Arduino Uno;
Mega328

TomP

Quote
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
Code: [Select]
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
Code: [Select]
double tempc, tempf;
tempc = (double)rawtemp / 16.0;
tempf = (tempc * 1.8) + 32.0;


jerseyguy1996

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
Arduino Uno;
Mega328

TomP

Quote
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...
Code: [Select]
 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.

Go Up