PDA

View Full Version : DS18S20 reading negative temperature



srob
- 23rd December 2007, 21:39
I need to extend the range of the DS18S20 below zero, to one decimal place. My current program uses the "onewire.bas" routine to calculate this:

' Calculate temperature in degrees C to 2 decimal places (not valid for negative temperature)
temperature = (((temperature >> 1) * 100) - 25) + (((count_per_c - count_remain) * 100) / count_per_c)
Lcdout $fe, 1, DEC (temperature / 100), ".", DEC2 temperature, " C"

Is it possible for negative temperatures to just XOR before the calculation. i.e.

IF temperature.15=1 then
temperature=temperature XOR %1111111111111111 'convert to possitive value
endif

Or am I missing something?

mister_e
- 24th December 2007, 04:02
If i'm not too drunk... try SDEC in you LCDOUT

Darrel Taylor
- 24th December 2007, 04:45
... Is it possible for negative temperatures to just XOR before the calculation. i.e. ...
Well, that's half way there ...

That would be what's called the "1's compliment".
But to get the positive value of a negative number, you need the "2's compliment".

So add 1 to it.
Add 1 to 1's compliment and you get 2's compliment.


Or there's PBP's built in function ABS (Absolute Value).
Does the same thing to negative numbers, and still preserves positive ones.

But there's more to your problem, because PBP can't multiply or divide negative numbers. (unless you are using PBPL on an 18F).

So you need to change the formula considerably to make it work.
There's a few examples in here somewhere.

Try searching for "negative DS1820"

Once you get the correct negative result ...
then you can use mister_e's suggestion.
<br>

presario1425
- 27th December 2007, 15:13
srob - try going through the following program. It worked for me.



'Program: TsensDS18B20.bas
'Notes: Temperature sensing with DS18B20 chip.
'Hardware Used: PIC18F2620 and DS18B20 Temp sensor
'Connections:
'Using default pin connections between LCD and PIC
'D4 -> RA0, D5 -> RA1, D6 -> RA2, D7 ->RA3
'E -> RB3, RS -> RA4, Vee (Pin 3) to GND

'************************************************* ***************

'DS18B20 connected to RB4 (pin 25) and Vcc with a 4.7k pull-up resistor.
'PIC18F2620 programmed with the "INTRC" switch for clock setting.
'MUST SET OSCCON to %01100000 to set the internal clock to 4-MHz

'************************************************* ***************



Comm_Pin VAR PortB.4 ' One-wire Data-Pin on PortB.4
SignC VAR BYTE ' +/- sign for Celcius temp display
SignF VAR BYTE ' +/- sign for F temp display
RAWTEMP VAR WORD 'Read raw temperature from DS18B20
SignBit VAR RAWTEMP.Bit11 'Read sign bit. 0=positive, 1=negative
TempC VAR WORD 'Converted temp in C
TempF var word 'Converted temp in F
Busy VAR BIT 'Busy bit
dummy var word

OSCCON = %01100000 'Internal clock set to 4-MHz (MUST DO THIS!!!)

CMCON = 7 ' RA0-RA3 are digital I/O. Turn off camparators

TRISA = 0 'PORTA is output
TRISB = 0 'PORTB is output
ADCON1 = 15 'All PORTB pins are digital

PAUSE 500 ' Wait 0.5 second to initialize LCD
LCDOUT $FE,1 ' Clear LCD

Loop:
gosub ReadDS18B20 'Initiate talk with & read DS18B20
gosub CalcC 'Calculate Celsius from RAWTEMP
gosub CalcF 'Calculate Fahrenheit from Celsius
LCDOUT $FE,2 'Home cursor
LCDOUT "Temp=",SignC,dec TempC/100,".",DEC2 TempC," C"
LCDOUT $FE,$C0 'Go to beginning of 2nd row
lcdout "Temp=",SignF,dec TempF/100,".",DEC2 TempF," F"
goto Loop


ReadDS18B20:
OWOUT Comm_Pin, 1, [$CC, $44] ' Skip ROM search & do temp conversion
ReadBusy:
OWIN Comm_Pin, 4, [Busy] ' Read busy-bit
IF Busy = 0 THEN ReadBusy ' Loop until Busy=1 (Temp conversion complete)
OWOUT Comm_Pin, 1, [$CC, $BE] ' Skip ROM search & read scratchpad memory
OWIN Comm_Pin, 2, [RAWTEMP.LowByte, RAWTEMP.HighByte] ' Read the raw temperature from DS18B20
return

CalcC:
if SignBit=0 then
SignC="+"
else
SignC="-"
rawtemp = ~rawtemp+1 'Negative temp stored in 2's complement format
endif
dummy = rawtemp*625 'DS18B20's resolution is 0.0625 C
TempC=DIV32 100
return

CalcF:
If SignC="-" then
If TempC>1777 then 'When Tc is <(-17.77), Tf is finally negative
SignF="-"
Dummy=TempC*18
TempF= DIV32 10
TempF=TempF-3200
Else
SignF="+" 'Tf is still positive when Tc>= (-17.77)
Dummy=TempC*18
TempF=DIV32 10
TempF=3200-TempF
Endif
Else
SignF="+" 'Positive Tc always gives positive Tf
Dummy=TempC*18
TempF=DIV32 10
TempF=TempF+3200
Endif
return

END

srob
- 27th December 2007, 21:38
Thanks for the input.

Unfortunatly I'm using a DS18S20, and not DS18B20, so don't think the DIV32 route will work.

Also, I only used 1's compliment as the LSB is truncated. Basically I wondered if the equation in the DS18S20 datasheet was still valid for negative values of TEMP_READ, if I converted it to the Absolute (positive) value using XOR, or do the values within COUNT_REMAIN and COUNT_PER_C affect the result, also would I have to reverse the addition and subtraction sign? eg

IF temperature.15=1 then
temperature=temperature XOR %1111111111111111 'convert to possitive value

' Calculate temperature in degrees C to 2 decimal places (for negative temperature)
temperature = (((temperature >> 1) * 100) + 25) - (((count_per_c - count_remain) * 100) / count_per_c)

ELSE

' Calculate temperature in degrees C to 2 decimal places (for positive temperature)
temperature = (((temperature >> 1) * 100) - 25) + (((count_per_c - count_remain) * 100) / count_per_c)

ENDIF

presario1425
- 28th December 2007, 15:53
Actually, the solution to your problem is easier than I thought. DS18S20's resolution is 0.5 C. So, you can use the following algorithm for negative temps -

Lets say RAWTEMP is where you stored the raw data out of the DS18S20. If bit#8 of RAWTEMP is 1, then you know that the temp is negative. In that case, invert RAWTEMP and add 1 to it (RAWTEMP = ~RAWTEMP + 1). If you multiply this number by 5 and store it in a variable, say TempC, you'll see that TempC will be the actual temperature, only multiplied by 10. For example, when TempC reads 450, then your actual temperature is -45 C. Let's try to do this with a real raw binary reading out of the DS18S20 -

Let's say that the raw binary reading out of your DS18S20 is

1111 1111 0101 1101

Since bit#8 is 1, we know that this is some negative temperature reading. Now we invert and then add 1 to the reading-


RAWTEMP = 1111 1111 0101 1101
~RAWTEMP = 0000 0000 1010 0010
+1 = 0000 0000 1010 0011


"0000 0000 1010 0011" represents a decimal value of 163. Multiply this number by 5 and we get 815. So, this really is -81.5C (of course this is out of the range of your sensor, but you get the idea). For example, take one of the readings from DS18S20's datasheet. -55C is represented by the raw binary value of "1111 1111 1001 0010". Inverting and then adding 1 reselts in "0000 0000 0110 1110" whis is 110 in decimal. Multiply this number by 5 and you get 550, which is -55C.

Hope this helps.

srob
- 28th December 2007, 21:21
This is true presario, and is perfectly adequate for my needs - the circuit needs to trigger an alarm when the ambient temperature falls below zero, and another alarm if the temperature reaches -7 degrees C. So I was going to use a spare indoor thermostat that I make previously, and reprogramme the PIC to suit (saving time and build cost). However, my pride would like me to display the temperature to the same resoultion of 0.1 degree, both in the negative and possitive, the formula used in onewire.bas, gives a resoultion of 0.01 degrees.

I think the best way forward is to try it and see what happens, and look at the contents of the DS18S20 COUNT_REMAIN and COUNT_PER_C registers, with the sensor left in my freezer for an hour or so, with a known accurate thermometer and adjust algorithm accordingly.

many thanks