handling 32-bit numbers
tdodds
Posts: 12
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.
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
www.parallax.com/StoreSearchResults/tabid/768/List/0/SortField/4/ProductID/401/Default.aspx?txtSearch=floating+point
-Phil
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.
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?
www.emesystems.com/BS2math6.htm
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Tracy Allen
www.emesystems.com
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
The PBASIC double precision (32 bit) divide by 10 code is pretty straightforward, but the explanation is a little tricky.
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