如何将 38 位字节数组转换为 ASCII 十进制
我正在编写一个例程和一个 AVR ATMEGA88,以使用 TI TM3705A 芯片读取 FDX RFID 标签,并通过 UART 将其传输到另一个处理器。该芯片使用 15625 波特率,而另一个处理器将以 19200 波特率接收数据。
这个想法是读取传入的数据(38 位 ID 号 - 例如 00 11 E3 D6 7C),对其进行 CRC 校验,然后将其输出为友好的 12 位十进制数 (000300144252),代表标签的唯一 ID。
到目前为止,我在数组中有这个 38 位数字:
我感兴趣的实际数字位于元素 2:6 中。 2 个 MSB 的编号。 6 应被忽略,因为它们是下一个数据块的开始。
i Dec Hex Bin
0 80 50 01010000
1 126 7E 01111110
2 124 7C 01111100
3 214 D6 11010110
4 227 E3 11100011
5 17 11 00010001
6 192 C0 11000000
7 237 ED 11101101
8 0 00 00000000
9 128 80 10000000
10 97 61 01100001
11 103 67 01100111
12 126 7E 01111110
13 0 00 00000000
14 0 00 00000000
我正在寻找一种有效的方法来将数组中的字节输出为十进制“000300144252”。
我尝试将其打包成 long long 类型,然后使用 sprintf %d 但它似乎因 temp = data << 而窒息。例如32。我不知道 sprintf 是否能处理这个大小的数字。我承认我已经被 C# 和其他懒惰语言宠坏了:)
有没有一种方法可以“随时”转换为十进制 - 换句话说,从最高有效数字 (6) 读取并在UART上输出十进制ASCII数字,然后5,4,3,2没有大的中间缓冲区等?这些芯片的内存有点受限。
I am writing a routine and an AVR ATMEGA88 to read FDX RFID tags using the TI TM3705A chip and transmit that over UART to another processor. This chip uses 15625 baud while the other processor will receive the data at 19200 baud.
The idea is to read the incoming data (38 bits of ID number - e.g. 00 11 E3 D6 7C), CRC check it and then output it as a friendly 12 digit decimal number (000300144252) that represents the unique ID of the tag.
So far I have this 38 bit number in an array:
The actual number I'm interested in sits in elements 2:6. The 2 MSB's of no. 6 should be ignored because they are the start of the next block of data.
i Dec Hex Bin
0 80 50 01010000
1 126 7E 01111110
2 124 7C 01111100
3 214 D6 11010110
4 227 E3 11100011
5 17 11 00010001
6 192 C0 11000000
7 237 ED 11101101
8 0 00 00000000
9 128 80 10000000
10 97 61 01100001
11 103 67 01100111
12 126 7E 01111110
13 0 00 00000000
14 0 00 00000000
I'm looking for an efficient way to output the bytes in the array as decimal "000300144252".
I've tried packing it into a long long type and then use sprintf %d but it seems to choke on temp = data << 32 for example. I don't know if sprintf will even handle that size number yet. I'll admit I've gotten really spoiled with C# and other lazy languages for this kind of stuff :)
Is there a way to convert to decimal "as you go" - in other words, read from the most significant digit (6) and output the decimal ASCII digits on the UART, then 5,4,3,2 without large intermediate buffers and the like? Memory is a little constrained on these chips.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
转换为十进制的计算量很大 - 无论您自己执行还是将其委托给库函数(例如
sprintf()
)都不会改变它。这里更复杂的是它是一个相对较大的值:38 位,比 32 位大。通过
sprintf()
,使用"%lld"
打印long long
。如果编译器支持long long
类型,但sprintf()
不支持,那么您可以手动完成:此函数在
中写出 12 个字符的结果dst[]
(以 NUL 结尾)。请注意,这意味着除以 10,编译器会将其转换为包含相对复杂的函数。如果您的编译器不支持 long long 类型(或在尝试进行除法时遇到困难),那么您将必须自己实现该操作,这将需要一些数学知识。最终,本文可能有用,也可能没有用。
Conversion to decimal is computationally expensive -- whether you do it yourself or delegate it to a library function such as
sprintf()
does not change it. What makes it more complex here is that it is a relatively large value: 38 bits, that's bigger than 32 bits.With
sprintf()
, use"%lld"
to print along long
. If the compiler supports thelong long
type butsprintf()
does not, then you can do it by hand:This function writes out the 12-char result in
dst[]
(with a terminating NUL). Note that this implies a division by 10, which the compiler will translate into the inclusion of a relatively complex function.If your compiler does not support the
long long
type (or chokes on trying to make a division) then you will have to implement that operation yourself, which will require a bit of mathematical knowledge. Ultimately, this article may be useful -- or not.经过大量的搜索和反复试验,我找到了解决方案。
我误解了我看到的错误,托马斯是对的。当添加到我自己的功能中时,该功能对于芯片来说太大了。
显而易见的选择并没有什么用处,但我将在这里列出它们,以帮助其他菜鸟遇到这个问题时。
itoa() - 16 位和 ultoa() - 32 位已实现,但太小。
sprintf(%d) 太小,并且 sprintf(%lld) 未在 WinAVR (AVR-GCC) 中实现。
此代码有效(有警告):
但是看看统计数据:
程序:7358 字节(89.8% 已满)
(.text + .data + .bootloader)
数据:256 字节(25.0% 已满)
(.data + .bss + .noinit)
罪魁祸首是 % 运算符。我无法解释为什么将它与 long long 一起使用会生成近 8k 的代码!
这是一个可行的替代方案。我将其修改为仅使用 unsigned long long(64 位),最多 12 位十进制数字,以适合我正在使用的 RFID 读取器格式。
统计数据:
程序:758 字节(9.3% 已满)
(.text + .data + .bootloader)
数据:0 字节(0.0% 已满)
(.data + .bss + .noinit)
好多了 :)
我大部分时间都花在 Douglas Jones,但答案最终来自 AVR 怪胎。
After a lot of searching and trial and error, I found a solution.
I misinterpreted the error I was seeing and Thomas is right. The function was too big for the chip when added to my own functions.
The obvious choices didn't go anywhere, but I'll list them here to help other noobs when they hit this problem.
itoa() - 16 bit and ultoa() - 32 bit are implemented but too small.
sprintf(%d) is too small and sprintf(%lld) is not implemented in WinAVR (AVR-GCC).
This code works (with caveat):
But look at the stats:
Program: 7358 bytes (89.8% Full)
(.text + .data + .bootloader)
Data: 256 bytes (25.0% Full)
(.data + .bss + .noinit)
The culprit is the % operator. I can't explain why using it with a long long generates almost 8k of code!
Here is a working alternative. I modified it to only use unsigned long long (64 bits) up to 12 decimal digits to fit the RFID reader format I'm using.
And the stats:
Program: 758 bytes (9.3% Full)
(.text + .data + .bootloader)
Data: 0 bytes (0.0% Full)
(.data + .bss + .noinit)
Much better :)
I spent most of my time with Douglas Jones, but the answer finally came from AVR Freaks.