|
|
View previous topic :: View next topic |
Author |
Message |
Freddie
Joined: 06 Sep 2003 Posts: 49
|
DS18B20 16-bit sign-extended two's complement to degrees C |
Posted: Sat Jan 17, 2004 2:29 pm |
|
|
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 |
Posted: Sat Jan 17, 2004 2:46 pm |
|
|
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 |
Posted: Sun Jan 18, 2004 9:25 am |
|
|
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
|
DS18B20 Working Code, Posted Here. |
Posted: Sun Jan 18, 2004 3:19 pm |
|
|
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
|
|
Posted: Mon Feb 02, 2004 7:21 pm |
|
|
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
|
|
Posted: Mon Feb 02, 2004 7:51 pm |
|
|
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
|
|
Posted: Tue Feb 03, 2004 7:45 am |
|
|
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. |
Posted: Tue Feb 10, 2004 10:13 am |
|
|
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
|
|
Posted: Wed Dec 29, 2004 4:00 am |
|
|
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
|
|
|
hayri Guest
|
|
Posted: Wed Jan 12, 2005 5:03 am |
|
|
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
|
|
Posted: Wed Jan 12, 2005 8:40 am |
|
|
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
|
|
Posted: Wed Jan 12, 2005 1:56 pm |
|
|
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
|
|
Posted: Fri Jan 28, 2005 8:44 am |
|
|
every corrections or suggestions are welcome
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! |
|
|
|
|
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
|