CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to CCS Technical Support

DS18B20 16-bit sign-extended two's complement to degrees C

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
Freddie



Joined: 06 Sep 2003
Posts: 49

View user's profile Send private message

DS18B20 16-bit sign-extended two's complement to degrees C
PostPosted: Sat Jan 17, 2004 2:29 pm     Reply with quote

I'm using the DS18B20 1-wire temperature sensor in the 12 bit resolution mode (default mode). I have no problems communicating with the device, but I do not understand how to convert the 16-bit sign-extended two's complement to degrees C. I searched this forum and using Google but could not find any help for the DS18B20. (I did find tons of stuff for the DS1820 though).

If someone understands 16-bit sign-extended two's complement and could post a CCS code snip I'd appreciate it. Thanks.

Here are some example conversions from the data sheet, but they don't step through how they get the conversion.
07D0 hex = +125C
0191 hex = +25.0625C
0008 hex = +0.5C
0000 hex = 0C
FFF8 hex = -0.5C
FE6F hex = -25.0625C
newguy
Guest







Temp sensor
PostPosted: Sat Jan 17, 2004 2:46 pm     Reply with quote

I think I can help you out, as I've used quite a few of the DS temp sensors.

Think of the 3 most significant nibbles (nibble = 4 bits) as the whole portion of the temperature. The least significant nibble is the fractional portion of the temperature (.5, .25, etc.).

So, examining the values from the data sheet:

0x07D0 - last nibble (fractional part) 0 = 0x07D = 7 x 16 + 13 = 125. Follow?

0x0191 - last nibble 1 = 0x019 = 1 x 16 + 9 = 25. Now for the fractional part: that last nibble is broken down into four bits. The most significant bit is .5C (half), followed by 0.25C (quarter), then 0.125C (eighth), and the least significant bit of the fractional nibble is 0.0625C (sixteenth). So, 0x0191 = 25C + 1/16C = 25.0625C. Easy, right?

So, 0xFFF8 - last nibble 8 = 0xFFF which is -1C, right? We still add to that the fractional part, 8 = 0.5C, and end up with -0.5C.

Finally, 0xFE6F - last nibble = 0XFE6 = -26C. We add the fractional part, F = 0.5C + 0.25C + 0.125C + 0.0625C = 15/16C = 0.9375C. So -26C + 0.9375C = -25.0625C.

Hope this helps.

-- Mark
Ttelmah
Guest







Re: DS18B20 16-bit sign-extended two's complement to degrees
PostPosted: Sun Jan 18, 2004 9:25 am     Reply with quote

Freddie wrote:
I'm using the DS18B20 1-wire temperature sensor in the 12 bit resolution mode (default mode). I have no problems communicating with the device, but I do not understand how to convert the 16-bit sign-extended two's complement to degrees C. I searched this forum and using Google but could not find any help for the DS18B20. (I did find tons of stuff for the DS1820 though).

If someone understands 16-bit sign-extended two's complement and could post a CCS code snip I'd appreciate it. Thanks.

Here are some example conversions from the data sheet, but they don't step through how they get the conversion.
07D0 hex = +125C
0191 hex = +25.0625C
0008 hex = +0.5C
0000 hex = 0C
FFF8 hex = -0.5C
FE6F hex = -25.0625C


The 'good news', is that the format will simply convert, if you divide by 16.
So if you have the data stored in a signed long int called (say) 'value', and do this:

temp=(float)(value)/16.0;

you will get the right result (assuming 'temp' is a float).

It is effectively a signed integer number of 1/16th degrees.

Best Wishes
Freddie



Joined: 06 Sep 2003
Posts: 49

View user's profile Send private message

DS18B20 Working Code, Posted Here.
PostPosted: Sun Jan 18, 2004 3:19 pm     Reply with quote

Thanks "newguy".

I got the DS18B20 working and thought I would post the code here so others can use it. It may not be optimized but it does work. As stated in the header, this code uses the CCS 1-wire driver file <touch.c> and assumes one DS18B20 on RB0. The code reads the Serial Number (not necessary for the temperature conversion), performs a Skip ROM temperature read, converts the digital temperature to C and F, and sends data to a PC. My temperature conversion routine is in bold below.

If anyone has more efficient code that converts the DS18B20 16 bit tempertaure to degrees C, please share it here.


//
// DS18B20 Temperature.
// Reads DS18B20 Serial number, performs a skip ROM temperature conversion,
// sends serial number, digital, C and F temperature data to PC serial port.
//
// May not be optimized but it is tested and works. Use at your own risk.
// Future updates to include CRC calculation, specific ROM temperature reads and search ROM.
//
// 16F876A Pin 33 (RB0) connected to DS18B20 Pin2 (DQ).
// 16F876A Pin 33 (RB0) also connect to 4.7K resistor pulled up to +5V.
// 16F876A Pin 25 (RC6/Tx) connected to MAX232 or Max233 which is then connected to PC Parallel Port.
// DS18B20 Pin1(grd) and Pin2(Vdd) connected to ground.
//
// Uses the CCS low level DS 1-wire drivers found in <touch.c>.
//

#include <16F876a.h>

#fuses HS,NOWDT,NOPROTECT,NOLVP
#use delay(clock=10000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7)

#include <touch.c>
#include <string.h>
#include <stdlib.h>


void main() {
int8 buffer[10];
int16 temp_digital;
float temp_c, temp_f;

printf("\r\nWaiting for a device...\r\n");

while (1)
{

//read SN command.
if(touch_present())
{
touch_write_byte(0x33); //read ROM command
buffer[0] = touch_read_byte(); //family code
buffer[1] = touch_read_byte(); //SN1 LSByte
buffer[2] = touch_read_byte(); //SN2
buffer[3] = touch_read_byte(); //SN3
buffer[4] = touch_read_byte(); //SN4
buffer[5] = touch_read_byte(); //SN5
buffer[6] = touch_read_byte(); //SN6 MSByte
buffer[7] = touch_read_byte(); //CRC

printf ("S/N READ: %X %X %X %X %X %X %X %X \r\n",buffer[0],buffer[1],buffer[2],buffer[3],buffer[4],buffer[5],buffer[6],buffer[7]);

delay_ms (1000);

} //end if

//read Temperature.
if(touch_present())
{
touch_write_byte(0xCC); //skip ROM
touch_write_byte(0x44); //temperature convert command
output_float(TOUCH_PIN); //strong pullup
delay_ms(1000);

touch_present();
touch_write_byte(0xCC); //skip ROM
touch_write_byte(0xBE); //copy scratchpad command

//get scratchpad data
buffer[0] = touch_read_byte();
buffer[1] = touch_read_byte();
buffer[2] = touch_read_byte();
buffer[3] = touch_read_byte();
buffer[4] = touch_read_byte();
buffer[5] = touch_read_byte();
buffer[6] = touch_read_byte();
buffer[7] = touch_read_byte();
buffer[8] = touch_read_byte();

printf ("Temp READ: %X %X %X %X %X %X %X %X %X \r\n",buffer[0],buffer[1],buffer[2],buffer[3],buffer[4],buffer[5],buffer[6],buffer[7],buffer[8]);
temp_digital = make16(buffer[1],buffer[0]);
printf( "temp_digital= %LX \r\n", temp_digital);

if (temp_digital >= 0x800) //temperture is negative
{
temp_c = 0;
//calculate the fractional part
if(temp_digital & 0x0001) temp_c += 0.06250;
if(temp_digital & 0x0002) temp_c += 0.12500;
if(temp_digital & 0x0004) temp_c += 0.25000;
if(temp_digital & 0x0008) temp_c += 0.50000;

//calculate the whole number part
temp_digital = (temp_digital >> 4) & 0x00FF;
temp_digital = temp_digital - 0x0001; //subtract 1
temp_digital = ~temp_digital; //ones compliment
temp_c = temp_c - (float)(temp_digital & 0xFF);
}
else //temperture is positive
{
temp_c = 0;
//calculate the whole number part
temp_c = (temp_digital >> 4) & 0x00FF;
//calculate the fractional part
if(temp_digital & 0x0001) temp_c = temp_c + 0.06250;
if(temp_digital & 0x0002) temp_c = temp_c + 0.12500;
if(temp_digital & 0x0004) temp_c = temp_c + 0.25000;
if(temp_digital & 0x0008) temp_c = temp_c + 0.50000;
} //end if else

printf( "TempC= %7.3f degrees C \r\n", temp_c ); // print temp C
temp_f = (temp_c* 9.00000)/5.00000 + 32.00000;
printf( "TempF= %7.3f degrees F \r\n\r\n", temp_f ); // print temp F

delay_ms (1000);

} //end if

} //end while(1)

} //end main
Guest_X44
Guest







PostPosted: Mon Feb 02, 2004 7:21 pm     Reply with quote

The datasheet of DS1631 shows that for a digital output of 0xE6F0 equivalent temperature in degrees celsius is -25.0625.

For a digital output of 0xF5E0 the equivalent temperature in degrees celsius is -10.125.



I don't quite get it. For positive temperatures the explanation in this thread seems right. For negatives, I'm at a loss.

Could someone spell out.
Guest_X44
Guest







PostPosted: Mon Feb 02, 2004 7:51 pm     Reply with quote

I forgot to mention that bit 15 is the sign bit (S). S=0 if temperature is positive, and S=1 if temperature is negative.

Also, bits 3 through 0 are hardwired to 0.
Neutone



Joined: 08 Sep 2003
Posts: 839
Location: Houston

View user's profile Send private message

PostPosted: Tue Feb 03, 2004 7:45 am     Reply with quote

Guest_X44 wrote:
I forgot to mention that bit 15 is the sign bit (S). S=0 if temperature is positive, and S=1 if temperature is negative.

Also, bits 3 through 0 are hardwired to 0.


It is a basic signed number with units of 1/16 degrees C.
jds-pic2
Guest







Re: DS18B20 Working Code, Posted Here.
PostPosted: Tue Feb 10, 2004 10:13 am     Reply with quote

Freddie wrote:

// May not be optimized but it is tested and works. Use at your own risk.
// Future updates to include CRC calculation, specific ROM temperature reads and search ROM.
/


freddie,

you can find the onewire CRC calc routine and related info here:

http://losdos.dyndns.org:8080/public/onewire/lib-onewire.h
Guest








PostPosted: Wed Dec 29, 2004 4:00 am     Reply with quote

Freddie,
first thanks the codes, i use ur program and modify a little bit(only change it to PIC16F877A), finally i got the program running, but the temperature is not quit accurate about 12 degree C different, i use a DS1820 sensor. here is the codes:

//
// DS18B20 Temperature.
// Reads DS18B20 Serial number, performs a skip ROM temperature conversion,
// sends serial number, digital, C and F temperature data to PC serial port.
//
// May not be optimized but it is tested and works. Use at your own risk.
// Future updates to include CRC calculation, specific ROM temperature reads and search ROM.
//
// 16F877A Pin 33 (RB0) connected to DS18B20 Pin2 (DQ).
// 16F877A Pin 33 (RB0) also connect to 4.7K resistor pulled up to +5V.
// 16F877A Pin 25 (RC6/Tx) connected to MAX232 or Max233 which is then connected to PC serial Port.
// DS18B20 Pin1(grd) and Pin2(Vdd) connected to ground.
//
// Uses the CCS low level DS 1-wire drivers found in <touch.c>.
//

//#include <16F876a.h>
#include <16F877a.h>
#fuses HS,NOWDT,NOPROTECT,NOLVP
#use delay(clock=20000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7)

#include <touch.c>
#include <string.h>
#include <stdlib.h>


void main() {
int8 buffer[10];
int16 temp_digital;
float temp_c, temp_f;

printf("\r\nWaiting for a device...\r\n");

while (1)
{

//read SN command.
if(touch_present())
{
touch_write_byte(0x33); //read ROM command
buffer[0] = touch_read_byte(); //family code
buffer[1] = touch_read_byte(); //SN1 LSByte
buffer[2] = touch_read_byte(); //SN2
buffer[3] = touch_read_byte(); //SN3
buffer[4] = touch_read_byte(); //SN4
buffer[5] = touch_read_byte(); //SN5
buffer[6] = touch_read_byte(); //SN6 MSByte
buffer[7] = touch_read_byte(); //CRC

printf ("S/N READ: %X %X %X %X %X %X %X %X \r\n",buffer[0],buffer[1],buffer[2],buffer[3],buffer[4],buffer[5],buffer[6],buffer[7]);

delay_ms (1000);

} //end if

//read Temperature.
if(touch_present())
{
touch_write_byte(0xCC); //skip ROM
touch_write_byte(0x44); //temperature convert command
output_float(TOUCH_PIN); //strong pullup
delay_ms(1000);

touch_present();
touch_write_byte(0xCC); //skip ROM
touch_write_byte(0xBE); //copy scratchpad command

//get scratchpad data
buffer[0] = touch_read_byte();
buffer[1] = touch_read_byte();
buffer[2] = touch_read_byte();
buffer[3] = touch_read_byte();
buffer[4] = touch_read_byte();
buffer[5] = touch_read_byte();
buffer[6] = touch_read_byte();
buffer[7] = touch_read_byte();
buffer[8] = touch_read_byte();

printf ("Temp READ: %X %X %X %X %X %X %X %X %X \r\n",buffer[0],buffer[1],buffer[2],buffer[3],buffer[4],buffer[5],buffer[6],buffer[7],buffer[8]);
temp_digital = make16(buffer[1],buffer[0]);
printf( "temp_digital= %LX \r\n", temp_digital);

if (temp_digital >= 0x800) //temperture is negative
{
temp_c = 0;
//calculate the fractional part
if(temp_digital & 0x0001) temp_c += 0.06250;
if(temp_digital & 0x0002) temp_c += 0.12500;
if(temp_digital & 0x0004) temp_c += 0.25000;
if(temp_digital & 0x0008) temp_c += 0.50000;

//calculate the whole number part
temp_digital = (temp_digital >> 4) & 0x00FF;
temp_digital = temp_digital - 0x0001; //subtract 1
temp_digital = ~temp_digital; //ones compliment
temp_c = temp_c - (float)(temp_digital & 0xFF);
}
else //temperture is positive
{
temp_c = 0;
//calculate the whole number part
temp_c = (temp_digital >> 4) & 0x00FF;
//calculate the fractional part
if(temp_digital & 0x0001) temp_c = temp_c + 0.06250;
if(temp_digital & 0x0002) temp_c = temp_c + 0.12500;
if(temp_digital & 0x0004) temp_c = temp_c + 0.25000;
if(temp_digital & 0x0008) temp_c = temp_c + 0.50000;
} //end if else

printf( "TempC= %7.3f degrees C \r\n", temp_c ); // print temp C
temp_f = (temp_c* 9.00000)/5.00000 + 32.00000;
printf( "TempF= %7.3f degrees F \r\n\r\n", temp_f ); // print temp F
delay_ms (1000);

} //end if

} //end while(1)

} //end main


Jay
jds-pic



Joined: 17 Sep 2003
Posts: 205

View user's profile Send private message

PostPosted: Thu Dec 30, 2004 11:56 am     Reply with quote

Anonymous wrote:
Freddie,
first thanks the codes, i use ur program and modify a little bit(only change it to PIC16F877A), finally i got the program running, but the temperature is not quit accurate about 12 degree C different, i use a DS1820 sensor. here is the codes:

[...snip...]

Jay


DS1820 != DS18B20

compare table 2 in
http://pdfserv.maxim-ic.com/en/ds/DS1820-DS1820S.pdf
to table 2 in
http://pdfserv.maxim-ic.com/en/ds/DS18B20.pdf

n.b.
to the original author you *should* be able to use my simple driver for the DS1822 with the DS18B20 device, PROVIDED that you only need positive temps...
http://www.ccsinfo.com/forum/viewtopic.php?t=19520

see
http://pdfserv.maxim-ic.com/en/ds/DS1822.pdf
for details on the DS1822.


jds-pic
hayri
Guest







PostPosted: Wed Jan 12, 2005 5:03 am     Reply with quote

My convertion code:


Code:


void ConvertTemp(int hbyte, int lbyte)
{
   char tsign;
   int tint;
   int16 tfloat;
   int16 temperature;
   char mystring[16];

   temperature = make16(hbyte,lbyte);

   tsign = '+';

   if (bit_test(temperature,11))
   {
      tsign='-';
      temperature = ~temperature + 1 ;
   }

   tint   = ((temperature >> 4) & 0x7F);
   tfloat = ((temperature & 0x000F) * 625);

   sprintf(mystring,"%C%U.%04lu", tsign, tint, tfloat);
   lcd_putstr(mystring);

   //printf("%C%U.%04lu", tsign, tint, tfloat);

}


it is working:)
hayri
Guest







PostPosted: Wed Jan 12, 2005 8:40 am     Reply with quote

note:


you can call converttemp:

int8 buff[9];
...
...
...

buff[0] = DS1820_Read_FIRST_TEMPERATURE_Byte();
buff[1] = DS1820_Read_SECOND_TEMPERATURE_Byte();
//Read other 7 bytes

ConvertTemp(buff[1],buff[0]);
jds-pic



Joined: 17 Sep 2003
Posts: 205

View user's profile Send private message

PostPosted: Wed Jan 12, 2005 1:56 pm     Reply with quote

hayri wrote:
My convertion code:
Code:

void ConvertTemp(int hbyte, int lbyte)
{
   char tsign;
   int tint;
   int16 tfloat;
   int16 temperature;
   char mystring[16];
   temperature = make16(hbyte,lbyte);
   tsign = '+';

   if (bit_test(temperature,11))
   {
      tsign='-';
      temperature = ~temperature + 1 ;
   }
   tint   = ((temperature >> 4) & 0x7F);
   tfloat = ((temperature & 0x000F) * 625);
   sprintf(mystring,"%C%U.%04lu", tsign, tint, tfloat);
   lcd_putstr(mystring);
   //printf("%C%U.%04lu", tsign, tint, tfloat);
}


hayri,
can i make a suggestion regarding your function structure?

in general, you will find that your programs are simultaneously easier to implement and easier to debug if you separate "data manipulation" from "data presentation". i can explain this best by example...

your conversion function definition might instead look as
int16 ConvertTemp(int 16 along) {
// data manipulation here, but NO presentation
return(tempval);
}

second, you have a new function, called GetRawTemp():
int16 GetRawTemp() {
buff[0] = DS1820_Read_TEMPERATURE_Byte(0);
buff[1] = DS1820_Read_TEMPERATURE_Byte(1);
return((buff[1]<<8) | buff[0])
}

next, you have another new function, lets call it DisplayTemp():
null DisplayTemp() {
tempval=ConvertTemp(GetRawTemp());
sprintf(blah blah blah);
}


then you simply call
DisplayTemp(); // fetch, format, then print out current temperature

note that doing it this way makes it FAR FAR FAR easier to reuse code, so over time you can build up a nice library of proven "manipulation" functions which can be trivially plugged into new programs without having to worry about mucking with the function itself. and, done this way, those same library functions can just be #include'd rather than being inlined.

jds-pic
hayri
Guest







PostPosted: Fri Jan 28, 2005 8:44 am     Reply with quote

every corrections or suggestions are welcome Smile

infact i'm using routines like you decribe. at least since i switched pic18f452. when i using pic16f628A and %100 rom space i have to write something like that. and when i saw this topic i post this one because it is better to understand whats going on with this one.

stucture likes jds-pic's suggestion is easy to use and more self-describted.
i also suggest this approach. For ds1820 raw reading routines please search the forum. you will find!
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group