PDA

View Full Version : Convert a 'signed' Word to a Long with minimum manipulation ?



mr.sneezy
- 26th May 2010, 12:50
To continue my current PBP project it looks like I'll need to convert some 'signed' Words (a 16bit signed value read from consecutive bytes of a BMP085 barometric sensors calibration table).

These 'signed' Words are treated as unsigned in PBP when I've read them from the sensor, but I use the S modifier to display them as -ve values on my LCD display.
That was fine, but now I need to really use the true signed value in math operations, so I need to make the unsigned Word into a signed Long.

So here's my hypothetical.
If my Word var contains say the value -14293 in decimal (when Serout2 with SDEC is used to show it), how would I put that value in to a Long variable as signed hex and retain the proper sign of the value (that PBP Words don't care about) ?

I know that I need to read the Words high bit and see if it's a 1 for a negative, then if so set the high bit of the Long to a 1, then copy the remaining bits into the right bits of the long (I think).

I could do bit manipulation byte by byte I guess, but that sounds real messy. Is there a simpler way to have a 'signed' word and expand it into a Long ?

Thanks,
Martin

PS. Actually I think I just thought of a way, but it there might be something better...

Long = Word << 16 'Force the signed word up to the top 16 bits of a Long
Long = Long >> 16 'Shift the Long value back 16 bits right, but PBP keeps the signed bit (high bit) set as required (would it?)
???

Kamikaze47
- 26th May 2010, 14:11
I believe all you have to do is this:

longvar=wordvar
IF wordvar.15 THEN longvar.HIGHWORD=$FFFF

The second line simply fills in the high word of the long with 1's if the number is negative. This is needed because bit 31 must be 1 to indicate that its negative, and because negative numbers are represented in 2's compliment form, the extra bits must be 1's.

Note: untested

Acetronics2
- 26th May 2010, 14:14
Hi,

I' d try a first thing ...



if Myword.15 then

MyWord = Myword * -1 ' absolute value
MyLong = MyWord * -1 ' the negative number

Else

MyLong = MyWord

Endif


certainly not the smartest ... but simple.

*** IDEA : TO BE CONFIRMED ***
Alain

mr.sneezy
- 27th May 2010, 06:18
I guess I should see which way uses least code space too, but I just tryed to complile the first suggestion and it did that OK. I'll only know if the code runs as expected later today, when I burn a PIC and try it.
I added this to my code.


lAC2 var Long 'Long variables for calibration values actually negative in my sensor
lAC3 var Long
lMB var Long
lMC var Long

'Convert unsigned PBP Word var to signed PBP Long var.

lAC2 = AC2 'copy word to long
if AC2.15 then lAC2.HIGHWORD = $FFFF 'Check for negative, set top 16bits to all 1's if true
lAC3 = AC3 'copy word to long
if AC3.15 then lAC3.HIGHWORD = $FFFF 'Check for negative, set top 16bits to all 1's if true
lMB = MB 'copy word to long
if MB.15 then lMB.HIGHWORD = $FFFF 'Check for negative, set top 16bits to all 1's if true
lMC = MC 'copy word to long
if MC.15 then lMC.HIGHWORD = $FFFF 'Check for negative, set top 16bits to all 1's if true

mr.sneezy
- 27th May 2010, 12:31
Yes. The method above works well. I did not try the other way to see if it's tighter code though, I was happy to just push onwards.

I discovered a issues with the rest of my calculations though, and I'd appreciate a comment from the 'Long literates' among us.

I'll try to explain without a huge dialogue, if it's too vague let me know. Here goes...

OK, this code, all the variables are Longs, except AC5, AC6 and MD which are Words.


X1 = ((lUtemp - AC6) * AC5) >>15 'find X1 - Note I needed the extra () around AC5 to get it to work
X2 = (lMC << 11) / (X1 + MD) 'Find X2
B5 = X1 + X2 'Find B5 from X1 and X2
lCTemp = (B5 + 8) / 16 '>> 4 'Hey presto, lCTemp appears...

Firstly I needed two sets of parenthesis around the X1 calculation, or it gave a bad result with only one around the 'lUTemp -AC6'.
The original C code was like this though ( I changed the 2^15 to the shift right by 15).
X1 = (UT - AC6) * AC5 / 2^15

Second, in the last calculation, I got a bad result whenever the value B5 became negative, until I got rid of the >> 4 and made that a '/ 16'. Then the value of lCTemp worked OK below 0 degC (I used freezer spray). I thought a >> 4 shift was equivalent to a / 16, but here in this syntax it seems not.

Can someone fill me in on why the shifts didn't quite work like a numeric divide here ?
Perhaps something to do with signed math again ?

In the end with the second brackets and a numeric divide the results were good, I'd just like to know why my 'fixes' worked so I don't bugger up the next stage...

Thanks,
Martin

Kamikaze47
- 27th May 2010, 14:08
PBP's shift algorithms dont work on negative numbers. You either have to divide instead, or do something like this:

lCTemp=(B5+8)>>4
IF lCTemp.27 THEN lCTemp=lCTemp&$F0000000

(Untested)

*edit* note that the division will always round down (towards negative infinity) when shifting no matter if the number if positive or negative. e.g. 5/2 = 2, but -5/2 = -3 (only for shifting - not division)

mr.sneezy
- 28th May 2010, 00:39
Thanks.
It sounds like I should just avoid using the Shift type divides then with Longs...
Martin

Kamikaze47
- 29th May 2010, 06:26
Just to correct myself, the code in my last post should have been:

lCTemp=(B5+8)>>4
IF lCTemp.27 THEN lCTemp=lCTemp|$F0000000

I accidentally used an AND instead of an OR