Convert a 'signed' Word to a Long with minimum manipulation ?


Closed Thread
Results 1 to 8 of 8
  1. #1
    Join Date
    Nov 2008
    Posts
    96

    Default Convert a 'signed' Word to a Long with minimum manipulation ?

    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?)
    ???
    Last edited by mr.sneezy; - 26th May 2010 at 12:58. Reason: Idea ?

  2. #2
    Join Date
    Nov 2005
    Location
    Perth, Australia
    Posts
    429


    Did you find this post helpful? Yes | No

    Default

    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
    "I think fish is nice, but then I think that rain is wet, so who am I to judge?" - Douglas Adams

  3. #3
    Join Date
    May 2004
    Location
    NW France
    Posts
    3,648


    Did you find this post helpful? Yes | No

    Default

    Hi,

    I' d try a first thing ...

    Code:
     
    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
    ************************************************** ***********************
    Why insist on using 32 Bits when you're not even able to deal with the first 8 ones ??? ehhhhhh ...
    ************************************************** ***********************
    IF there is the word "Problem" in your question ...
    certainly the answer is " RTFM " or " RTFDataSheet " !!!
    *****************************************

  4. #4
    Join Date
    Nov 2008
    Posts
    96


    Did you find this post helpful? Yes | No

    Default

    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.
    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

  5. #5
    Join Date
    Nov 2008
    Posts
    96


    Did you find this post helpful? Yes | No

    Default

    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.

    Code:
    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
    Last edited by mr.sneezy; - 27th May 2010 at 12:35.

  6. #6
    Join Date
    Nov 2005
    Location
    Perth, Australia
    Posts
    429


    Did you find this post helpful? Yes | No

    Default

    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)
    Last edited by Kamikaze47; - 27th May 2010 at 14:27.
    "I think fish is nice, but then I think that rain is wet, so who am I to judge?" - Douglas Adams

  7. #7
    Join Date
    Nov 2008
    Posts
    96


    Did you find this post helpful? Yes | No

    Default

    Thanks.
    It sounds like I should just avoid using the Shift type divides then with Longs...
    Martin

  8. #8
    Join Date
    Nov 2005
    Location
    Perth, Australia
    Posts
    429


    Did you find this post helpful? Yes | No

    Default

    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
    "I think fish is nice, but then I think that rain is wet, so who am I to judge?" - Douglas Adams

Members who have read this thread : 0

You do not have permission to view the list of names.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts