Shop OBEX P1 Docs P2 Docs Learn Events
handling 32-bit numbers — Parallax Forums

handling 32-bit numbers

tdoddstdodds Posts: 12
edited 2010-05-18 17:22 in BASIC Stamp
Hi,
I have a project where I am gathering and reporting data from several ModBus devices using RS485.·I have the·hardware working just fine for single 16-bit words, but these·devices report some of their values in 32-bit signed-integer or 32-bit floating-point. Is there an existing routine to convert these numbers into a decimal string that I can adopt? It has to handle really large numbers·(a single one in the 31st position has to report as ASCII 1,073,741,824 !) and it also has to·use the sign bit. If not, maybe there is a general methodology to handle 32-bit numbers in microcontrollers that I can use as a basis to create a program.
Thanks for the help.

Comments

  • Mike GreenMike Green Posts: 23,101
    edited 2010-05-17 03:57
    It's very easy to do arithmetic a byte at a time, much like you would do decimal arithmetic by hand on paper. For example, if you have your 32 bit number in two byte arrays called Num1 and Num2, you could add them with:

    Carry = 0
    for i = 0 to 3
    Num1[noparse][[/noparse] i ] = Num1[noparse][[/noparse] i ] + Num2[noparse][[/noparse] i ] + Carry
    Carry = Num1[noparse][[/noparse] i ] >> 8
    Num1[noparse][[/noparse] i ] = Num1[noparse][[/noparse] i ] & $FF
    next i

    Subtraction would work similarly. Multiplication and division would be a byte at a time just like you'd do it by hand in decimal except you'd use bytes instead of decimal digits.

    Division (and remaindering) by a small number like 10 would be easy.
  • tdoddstdodds Posts: 12
    edited 2010-05-17 04:27
    Thanks Phil,

    I looked at that chip and it is definitely a solution, but it's really overkill - that coprocessor has a jillion math functions solved really fast, but I don't need that kind of performance. Also another $20 bucks per circuit board is·a steep price, but I guess I can go for it if I can't find a software solution.

    Thanks Mike,

    From your reply I can see logically how I could do·binary math using the carry bit. ·I need to convert the 32-bit binary number into a 10-byte ASCII string. For example, can you see a way to transmit ASCII 1073741824 if·only the 7th bit of the·most significant byte is set to 1?
  • Mike GreenMike Green Posts: 23,101
    edited 2010-05-17 04:46
    Like I said, you can easily do division by 10 to get a quotient and remainder. If you take a multi-byte value like $80000000 and do this repeatedly, you'll get a series of decimal values that, right to left, are the digits of 1073741824. If you add "0" to each value, you get the ASCII string "4","2","8","1","4","7","3","7","0","1". Reverse the order and you get what you want.
  • Tracy AllenTracy Allen Posts: 6,662
    edited 2010-05-17 15:55
    Examples of kicking out decimal digits of a 32 bit signed number at,
    www.emesystems.com/BS2math6.htm

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Tracy Allen
    www.emesystems.com
  • tdoddstdodds Posts: 12
    edited 2010-05-18 00:44
    Thanks so much Tracy. I ported the divide-by-ten subroutine from your document to my SX28 board and it works perfectly. There does not appear to be a straightforward explanation of how it works though. Do you have same? If not, perhaps I can glean the logic from your text. Below is my SX code:

    DEVICE sx28,oscxt2, turbo,stackx,optionx,BOR26
    FREQ 8_000_000
    ArrayByte VAR byte (12)
    send VAR byte
    TmpB1 VAR Byte
    temp VAR Byte
    RM VAR Byte
    TmpW1 VAR Word
    WX VAR Word
    WY VAR Word
    TX_BYTE SUB 1,2 'transmit byte
    Bin32DEC SUB 1,4 'Create ASCII string from double word

    Start:
    Bin32DEC 0,0,0,128 'ENTER 32 BIT NUMBER -Param1 (leftmost) is least significant byte
    For J = 0 to 9
    ArrayByte(J) = ArrayByte(J) + 48
    Tx_Byte ArrayByte(J)
    Next
    Pause 2000
    Goto Start

    TX_BYTE:
    SEROUT Send, N9600, __PARAM1 ' send the byte
    return
    Bin32DEC:
    WX = __WPARAM34 'Most significant word
    WY = __WPARAM12 'Least significant word
    for I = 9 to 0 Step -1
    TmpW1 = WX//10 'high remainder
    temp = TmpW1_LSB
    WX = WX/10 'high word quotient
    TmpW1 = WY//10 'remainder calc
    TMPB1 = TmpW1_LSB
    RM = temp * 6
    RM = RM//10
    RM = RM + TmpB1
    WY = WY/10 'Low word quotient
    TmpW1 = RM/10 'WY = (WY/10)+(RM/10)+(temp*6553)+(Temp*6/10)
    WY = TmpW1 + WY
    TmpW1 = temp*6553
    WY = WY + TmpW1
    TmpB1 = Temp*6
    TmpB1 = TmpB1/10
    WY = WY + TmpB1
    RM = RM//10 'final remainder
    Arraybyte(I) = RM
    next
    return
  • Tracy AllenTracy Allen Posts: 6,662
    edited 2010-05-18 17:22
    Glad it worked!

    The PBASIC double precision (32 bit) divide by 10 code is pretty straightforward, but the explanation is a little tricky.
    ' calculate z/10, were z=z1:z0, two words, positive number.  
    q1=z1/10
    q0=z1//10
    rm=q0*6//10+(z0//10)
    q0=(q0*6553)+(q0*6/10)+(z0/10)+(rm/10)
    rm=rm//10
    



    The 32 bit number in "base 65536" is
    . z1 * 65536 + z0
    Dividing that by 10 is in general going to give another double precision value, and a remainder from 0 to 9.
    . q1 * 65536 + q0 integer quotient rm remainder.
    The program approaches the division one term at a time, dividing z1 * 65536 by 10 to get the first quotient, q1, and a first remainder. The first remainder then contributes to the lower quotient q0 and to the final remainder rm. It requires some thought. What is the first remainder from
    . rm1=z1*65536//10?
    (The program above reuses the variables rm and q0 for two different purposes) PBASIC can't solve for rm1 directly, but we can rewrite it as
    . rm1= z1 * (65530 + 6) // 10
    . = z1 * 65530 // 10 + z1 * 6 // 10 using arithmetic, // distributes over addition.
    The factor of 10 in the first term makes it drop out. The remainder with the factor of 10 in 65530 is identically zero. So we are left with
    . rm1 = z1 * 6 // 10
    but in general PBSIC might not be able to deal with that either, if z1 happens to be large, specifically larger than 65526/6. So we rewrite that as,
    . rm1 = (z1 // 10) * 6 // 10 basic property of modulus, distributes over multiplication, no overflow.

    The rest of the derivation is similar. Collect terms for the remainder and lower quotient, divide, compute the final remainder. The unfamilar part is probably the modular arithmetic, which is not covered much in schools.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Tracy Allen
    www.emesystems.com
Sign In or Register to comment.