Ok, so I am working with a PIC microprocessor, in C. It's a 16F, so it can't hold integers larger than 32bits (unsigned int32 is the largest datasize available)
好的,所以我在C中使用PIC微处理器。它是一个16F,因此它不能保存大于32位的整数(unsigned int32是可用的最大数据量)
From a reader, I receive a 5 byte ID code. To transmit it, I have to encoded to BCD, digit by digit. I can't sprint it to a string, as it is larger that the data size, and can't process it. I can't divide it because no operation is defined for it.
从阅读器,我收到一个5字节的ID代码。为了传输它,我必须逐位编码为BCD。我无法将其打印到字符串,因为它比数据大小大,并且无法处理它。我无法分割它,因为没有为它定义操作。
I can't figure out any solution possible, does anyone have dealt with this before?
我无法找出任何解决方案,有没有人以前处理过这个问题?
EDIT:
I receive the number in a series of 5 bytes: "FF-FF-FF-FF-FF". I need to convert it to decimal "0123456789012" (13 digits, length of 256^5 in decimal) to send it through RS232. The second function (Take the ASCII, and send it) I already have it working, but I need the string representation of the full number before I can do anything with it.
我收到一系列5个字节的数字:“FF-FF-FF-FF-FF”。我需要将其转换为十进制“0123456789012”(13位数,长度为256 ^ 5十进制),以通过RS232发送。第二个功能(采用ASCII,并发送它)我已经有它工作,但我需要完整数字的字符串表示,然后我可以用它做任何事情。
5 个解决方案
#1
Assuming you have 32 bit arithmetic: 2**24 = 16777216, so taking x as the most significant 2 bytes and y as the least significant 3:
假设您有32位算术:2 ** 24 = 16777216,所以将x视为最重要的2字节,将y视为最不重要的3:
(16777216 * x + y) / 1000
= (16777000 * x + 216 * x + y) / 1000
= 16777 * x + (216 * x + y) / 1000
The first term can be calculated in 32 bits without overflow (since x < 2**16
). The second term can also be calculated without overflow (since x < 2**16
and y < 2**24
).
第一项可以32位计算而不会溢出(因为x <2 ** 16)。第二项也可以在没有溢出的情况下计算(因为x <2 ** 16且y <2 ** 24)。
This is basically long division in base 2**24
of a 2-digit value, but with terms pre-calculated knowing that the divisor is 1000. One thousand is chosen because it's the least power of 10 greater than 2**8
.
这基本上是2位数值的基数2 ** 24中的长除法,但是在知道除数为1000的情况下预先计算的项。选择了1000,因为它是10的最小幂大于2 ** 8。
So, first compute the lowest three digits, use the fact that (2**32) % 1000 == 296
. So this time we'll take x as the highest byte and y as the low 4 bytes
所以,首先计算最低的三位数,使用(2 ** 32)%1000 == 296的事实。所以这次我们将x作为最高字节,y作为低4字节
((2**32) * x + y) % 1000 = ((2**32) * x) % 1000 + y % 1000 (modulo 1000)
= (296 * x) % 1000 + y % 1000 (modulo 1000)
((2**32) * x + y) % 1000 = ((296 * x) % 1000 + y % 1000) % 1000
Then divide the original number by 1000 using the formula above. Then you're safely into 32 bit territory and can churn out the remaining digits using the normal loop.
然后使用上面的公式将原始数字除以1000。然后你可以安全地进入32位区域,并可以使用正常循环生成剩余的数字。
Btw, I'd check the results if I were you: I haven't tested this and it's possible I've made an error somewhere. It should be easy to compare against the results of bcd conversions done using the usual means in a 64-bit integer on a PC.
顺便说一句,如果我是你,我会检查结果:我没有测试过这个,我可能在某个地方犯了错误。应该很容易与使用PC上64位整数的常用方法完成的bcd转换结果进行比较。
#2
What I would do, is implement addition and multiplication for numbers coded as a string (sort of BigNum). That way, you can sprintf the most significant byte of your ID to a string "A", multiply it with the string "4294967296" (256^4) giving you string "B", sprintf the 4 least significant bytes of your ID in another string "C", and finally adding "B" and "C".
我要做的是对编码为字符串的数字(一种BigNum)实现加法和乘法。这样,您可以将ID的最重要字节sprintf为字符串“A”,将其与字符串“4294967296”(256 ^ 4)相乘,为您提供字符串“B”,sprintf为您ID中的4个最低字节另一个字符串“C”,最后添加“B”和“C”。
It's not very sexy, especially on a micro-controller, but it works :)
它不是很性感,特别是在微控制器上,但它的工作原理:)
#3
The PIC16F does not have a hardware multiply or divide unit, so unless you are multiplying or dividing by a power of 2, it is taxing to the processor. Here is a routine that does a BCD on a 32 bit number and doesn't require division or multiplication. You could adapt this to a 5 byte number by doing it in chunks.
PIC16F没有硬件乘法或除法单元,因此,除非您乘以或除以2的幂,否则它对处理器造成负担。这是一个在32位数字上执行BCD且不需要除法或乘法的例程。您可以通过以块为单位将其调整为5字节数。
void BCD32(int32u numIn) { int8u digit = 0;
void BCD32(int32u numIn){int8u digit = 0;
while (numIn >= 1000000000)
{
numIn -= 1000000000;
digit++;
}
debug[0] = digit + 48;
digit = 0;
while (numIn >= 100000000)
{
numIn -= 100000000;
digit++;
}
debug[1] = digit + 48;
digit = 0;
while (numIn >= 10000000)
{
numIn -= 10000000;
digit++;
}
debug[2] = digit + 48;
digit = 0;
while (numIn >= 1000000)
{
numIn -= 1000000;
digit++;
}
debug[3] = digit + 48;
digit = 0;
while (numIn >= 100000)
{
numIn -= 100000;
digit++;
}
debug[4] = digit + 48;
digit = 0;
while (numIn >= 10000)
{
numIn -= 10000;
digit++;
}
debug[5] = digit + 48;
digit = 0;
while (numIn >= 1000)
{
numIn -= 1000;
digit++;
}
debug[6] = digit + 48;
digit = 0;
while (numIn >= 100)
{
numIn -= 100;
digit++;
}
debug[7] = digit + 48;
digit = 0;
while (numIn >= 10)
{
numIn -= 10;
digit++;
}
debug[8] = digit + 48;
digit = 0;
while (numIn >= 1)
{
numIn -= 1;
digit++;
}
debug[9] = digit + 48;
debug[10] = CARRIAGE_RETURN;
debug[11] = NEW_LINE_FEED;
SendUart(12);
}
#4
You can always "sprintf" it to a string manually yourself. go over the data byte after byte and convert it to a numerical string by appending individual characters.
您可以自己手动将其“sprintf”为字符串。遍历字节后的数据字节,并通过附加单个字符将其转换为数字字符串。
#5
The core of this problem I would say is one of "long division" to convert to decimal. Not entirely unlike long division you learned in grade school, though with binary numbers, long division is much simpler. But its still a lot of work.
我要说的这个问题的核心是转换为十进制的“长除法”之一。与你在小学阶段学到的长分并不完全不同,尽管使用二进制数,长分割更简单。但它仍然需要做很多工作。
try:
http://mathforum.org/library/drmath/view/55951.html
You will have to implement your own multi-byte subtraction and shift routines.
您必须实现自己的多字节减法和移位例程。
#1
Assuming you have 32 bit arithmetic: 2**24 = 16777216, so taking x as the most significant 2 bytes and y as the least significant 3:
假设您有32位算术:2 ** 24 = 16777216,所以将x视为最重要的2字节,将y视为最不重要的3:
(16777216 * x + y) / 1000
= (16777000 * x + 216 * x + y) / 1000
= 16777 * x + (216 * x + y) / 1000
The first term can be calculated in 32 bits without overflow (since x < 2**16
). The second term can also be calculated without overflow (since x < 2**16
and y < 2**24
).
第一项可以32位计算而不会溢出(因为x <2 ** 16)。第二项也可以在没有溢出的情况下计算(因为x <2 ** 16且y <2 ** 24)。
This is basically long division in base 2**24
of a 2-digit value, but with terms pre-calculated knowing that the divisor is 1000. One thousand is chosen because it's the least power of 10 greater than 2**8
.
这基本上是2位数值的基数2 ** 24中的长除法,但是在知道除数为1000的情况下预先计算的项。选择了1000,因为它是10的最小幂大于2 ** 8。
So, first compute the lowest three digits, use the fact that (2**32) % 1000 == 296
. So this time we'll take x as the highest byte and y as the low 4 bytes
所以,首先计算最低的三位数,使用(2 ** 32)%1000 == 296的事实。所以这次我们将x作为最高字节,y作为低4字节
((2**32) * x + y) % 1000 = ((2**32) * x) % 1000 + y % 1000 (modulo 1000)
= (296 * x) % 1000 + y % 1000 (modulo 1000)
((2**32) * x + y) % 1000 = ((296 * x) % 1000 + y % 1000) % 1000
Then divide the original number by 1000 using the formula above. Then you're safely into 32 bit territory and can churn out the remaining digits using the normal loop.
然后使用上面的公式将原始数字除以1000。然后你可以安全地进入32位区域,并可以使用正常循环生成剩余的数字。
Btw, I'd check the results if I were you: I haven't tested this and it's possible I've made an error somewhere. It should be easy to compare against the results of bcd conversions done using the usual means in a 64-bit integer on a PC.
顺便说一句,如果我是你,我会检查结果:我没有测试过这个,我可能在某个地方犯了错误。应该很容易与使用PC上64位整数的常用方法完成的bcd转换结果进行比较。
#2
What I would do, is implement addition and multiplication for numbers coded as a string (sort of BigNum). That way, you can sprintf the most significant byte of your ID to a string "A", multiply it with the string "4294967296" (256^4) giving you string "B", sprintf the 4 least significant bytes of your ID in another string "C", and finally adding "B" and "C".
我要做的是对编码为字符串的数字(一种BigNum)实现加法和乘法。这样,您可以将ID的最重要字节sprintf为字符串“A”,将其与字符串“4294967296”(256 ^ 4)相乘,为您提供字符串“B”,sprintf为您ID中的4个最低字节另一个字符串“C”,最后添加“B”和“C”。
It's not very sexy, especially on a micro-controller, but it works :)
它不是很性感,特别是在微控制器上,但它的工作原理:)
#3
The PIC16F does not have a hardware multiply or divide unit, so unless you are multiplying or dividing by a power of 2, it is taxing to the processor. Here is a routine that does a BCD on a 32 bit number and doesn't require division or multiplication. You could adapt this to a 5 byte number by doing it in chunks.
PIC16F没有硬件乘法或除法单元,因此,除非您乘以或除以2的幂,否则它对处理器造成负担。这是一个在32位数字上执行BCD且不需要除法或乘法的例程。您可以通过以块为单位将其调整为5字节数。
void BCD32(int32u numIn) { int8u digit = 0;
void BCD32(int32u numIn){int8u digit = 0;
while (numIn >= 1000000000)
{
numIn -= 1000000000;
digit++;
}
debug[0] = digit + 48;
digit = 0;
while (numIn >= 100000000)
{
numIn -= 100000000;
digit++;
}
debug[1] = digit + 48;
digit = 0;
while (numIn >= 10000000)
{
numIn -= 10000000;
digit++;
}
debug[2] = digit + 48;
digit = 0;
while (numIn >= 1000000)
{
numIn -= 1000000;
digit++;
}
debug[3] = digit + 48;
digit = 0;
while (numIn >= 100000)
{
numIn -= 100000;
digit++;
}
debug[4] = digit + 48;
digit = 0;
while (numIn >= 10000)
{
numIn -= 10000;
digit++;
}
debug[5] = digit + 48;
digit = 0;
while (numIn >= 1000)
{
numIn -= 1000;
digit++;
}
debug[6] = digit + 48;
digit = 0;
while (numIn >= 100)
{
numIn -= 100;
digit++;
}
debug[7] = digit + 48;
digit = 0;
while (numIn >= 10)
{
numIn -= 10;
digit++;
}
debug[8] = digit + 48;
digit = 0;
while (numIn >= 1)
{
numIn -= 1;
digit++;
}
debug[9] = digit + 48;
debug[10] = CARRIAGE_RETURN;
debug[11] = NEW_LINE_FEED;
SendUart(12);
}
#4
You can always "sprintf" it to a string manually yourself. go over the data byte after byte and convert it to a numerical string by appending individual characters.
您可以自己手动将其“sprintf”为字符串。遍历字节后的数据字节,并通过附加单个字符将其转换为数字字符串。
#5
The core of this problem I would say is one of "long division" to convert to decimal. Not entirely unlike long division you learned in grade school, though with binary numbers, long division is much simpler. But its still a lot of work.
我要说的这个问题的核心是转换为十进制的“长除法”之一。与你在小学阶段学到的长分并不完全不同,尽管使用二进制数,长分割更简单。但它仍然需要做很多工作。
try:
http://mathforum.org/library/drmath/view/55951.html
You will have to implement your own multi-byte subtraction and shift routines.
您必须实现自己的多字节减法和移位例程。