readtemp12 negative values

kevrus

New Member
I think I may be a little stupid, ive read various posts regarding readtemp12 negative temps but I still can't seem to follow how to write the code.

This is what i'm using at present for positive temps to 1 decimal place: (copied from somewhere but I cant remember where, although I do follow it somewhat.)

readtemp12 1,w0
w1=w0*10
w2=w1/16
b0=w2/10
b1=w2//10

Can someone please explain the negative bit (excuse the pun) in simple terms please?
 

BeanieBots

Moderator
For Readtemp12, it is the raw data as per the datasheet.
ref:- http://www.picaxeforum.co.uk/showthread.php?t=8110&page=2

I've not got round to trying myself and the datasheet is a little confusing as the values given are 16-bit but referred to as 12-bit.
eg
+10.125C = $00A2
+0.5C = $0008
0C = $0000
-0.5C = $FFF8
-10.125C = $FF5E
-55C = $FC90

It is described as "sign-extended two's complement".

Maybe somebody can explain to us both what we need to do to get that into 'real' numbers for temperatures below 0C.
 

eclectic

Moderator
Negative maths.

kevrus.. Goto

Homepage
Links
Peter H Anderson
then scroll down to Interface with a DS18B20 ..... 18X

e.
 

kevrus

New Member
Ive read and re-read the P H Anderson code and I still don't get it. Maybe i'll give it a break and come back to it later...
 
Well, in words, you would first check for the sign bit so you no how to handle the number. You have a word variable with a highbyte and a lowbyte. With the highbyte you can use an AND with binary like: NegNum = highbyte AND b'00001000' now test that with an IF for a '1'. If a '1' then you have a negative number, yea.

Now for a two's compliment dealing with a negative number. You 'invert' your word variable and add '1' to that. Or you could take your lowbyte, invert that, and then add '1'. Take your highbyte invert that, then add both the lowbyte and highbyte back together. Almost there, Right shifting the whole works 4 times will give you your new negative whole number.

Hope that helps, maybe someone else can give a more concise explanation.
 

hippy

Technical Support
Staff member
What's confusing is the PICAXE Manual 2 Basic Commands doesn't indicate if the raw 12-bit value is sign extended to 16-bit or not when negative. Either way one of these should do the trick -

- ' For 16-bit sign extended
- ReadTemp12 PIN,temperature
- isNegative = temperature / $8000
- If isNegative = 1 Then
- temperature = -temperature
- End If

- ' For non 16-bit sign extended
- ReadTemp12 PIN,temperature
- isNegative = temperature / $0800
- If isNegative = 1 Then
- temperature = temperature ^ $0FFF + 1
- End If

isNegative can be a bit, byte or word variable, temperature must be a word variable.

isNegative will be set zero if a positive temperature and one if negative and can be used in later processing. After processing, temperature will be the corrected absolute value.
 

hippy

Technical Support
Staff member
If someone lets me know which of the two it is which actually works, I'll do that :)
 

kevrus

New Member
Many thanks for all the replies, things are a bit clearer. Hippy, as soon as I get chance, I will try the code, may be a few days yet though...this forum is superb!
 

tikeda

Member
Here's the decoding for the chip's output:
MS byte:
bit #
15 - Sign
14 - Sign
13 - Sign
12 - Sign
11 - Sign
10 - 2^6
09 - 2^5
08 - 2^4

LS byte:
bit #
07 - 2^3
06 - 2^2
05 - 2^1
04 - 2^0
03 - 2^(-1) <0.5000>
02 - 2^(-2) <0.2500> undefined in 9 bit resolution
01 - 2^(-3) <0.1250> undefined in 10 & 9 bit resolution
00 - 2^(-4) <0.0625> undefined in 11,10 & 9 bit resolution

If the temperature is negative, *all* the sign bits are '1' and the rest of the bits are two's-complement (Sign-extended). Bit 10 will be a '1' as well for a negative number within the device's temperature range. The sign bits are '0' for positive readings.

Here is -55.0 degC (from the product sheet):
1111 1100 1001.0000 (period added to indicate fractional portion)
two's-complement =
0000 0011 0111.0000 = 55.0 decimal (last four bits are fractional)

Another:
1111 1111 0101.1110 = -10.125 degC
0000 0000 1010.0010 = 10.125 (complement)

Prof. Anderson's code takes the two's-complement via:
TReading = TReading ^ $ffff + 1

The rest of his code handles the number shifting necessary to tease apart the whole and fractional components of the decimal temperature.
 
Last edited:

kevrus

New Member
Well i've only just got around to looking at this again, and it seems that Hippys first code seems to work a treat in simulation:

- ' For 16-bit sign extended
- ReadTemp12 PIN,temperature
- isNegative = temperature / $8000
- If isNegative = 1 Then
- temperature = -temperature
- End If

I've still yet to build a project with this...a 2 channel frost protection stat with LCD display is proposed...its on the list of things to build.
Thanks for all the replies, a big help.
 

tikeda

Member
Prof. Anderson uses the following to test for a negative temperature:
Code:
SignBit = TReading / 256 / 128
If SignBit = 0 Then Positive
'He handles negative values here...
Hippy's code also uses a divide to get at the sign bits:
Code:
isNegative = temperature / $8000
If isNegative = 1 Then ...
Consider a simple comparison like this:
Code:
If Word_TempReading > 2047 Then
	'Handle negative values here...*
End If

'or, if working in bytes is more efficient...
If UpperByte_TempReading > 7 Then
	'Handle negative values here...*
End If

'or even...
If bit15 = 1 Then...

*Any number between 2047 and 63487 works with
comparison of the word variable and any value
between 7 and 247 works with comparison of the
most significant byte.
I wonder how much multiplication and division 'costs' in terms of processing time compared to If/Then statements. I guess that depends on whether the Picaxe interpreter is optimized to substitute bit shifting when multiplying & dividing powers of two.
 
Last edited:

hippy

Technical Support
Staff member
@ tikeda : I'm not sure why PHA does the division in two steps. You're right, divisions are quite costly time wise. Unfortunately the PICAXE compiler doesn't convert divisions to shifts, in fact it converts shifts to multiplies and divides :)

The advantage of the "signBit = temperature / $8000" is that it's likely the sign will be needed later on, so may as well create that first. By doing the division it means there's only ever a 0 or 1 result which can be stored in any sized variable; bit, byte or word.

A faster solution would be "signBit = temperature & $8000" where the value would be zero ( positive ) or non-zero ( negative ). The disadvantage there is it would need 'sifnBit' defined as a word variable.

An improvement on that might be "signBit = temperature & $8000 Max 1" which would also returna 0 or 1 result.

If temperature is 'b0' then "signBit = bit15' would be the most efficient.

There are many ways to [delete]buy a peerage and get away with it [/delete] skin a cat :)
 

tikeda

Member
Good info, Hippy.

"...in fact it converts shifts to multiplies and divides" Heh, that's e-v-i-l.

One downside to 'optimization' is that it quickly reduces code readability, creating programs that look like entries in the Obfuscated Perl or C Contests. Maybe that's why PHA used the "/256/128" notation: It may make it easier for him to remember what he was trying to do. Not a bad practice if you've got the code space and no performance liabilities.

I didn't realize you could perform an assignment like: bit0 = %00000001 -- That makes life a lot easier in some situations. In the past I just reserved the lowest memory word to hold temporary values where I could also retain & access the individual bits as named variables (i.e.. bitNN).
 
Last edited:

leftyretro

New Member
Surely you're not serious!
That was my first impression also. I didn't think the underlining PIC microprocesssor had hardware X & / instructions and assumed that the Picaxe math routines would use shifts to perform math. But I haven't studied the Pic data sheets in depth so I certainly could be wrong.

Lefty
 

hippy

Technical Support
Staff member
Surely you're not serious!
Actually I am wrong ... the X1's have native shift instructions, the rest do not. I thought an option had been added to let shifts be specified for the others but it appears not. Must have been a dream I was having :)
 
Top