如何将38位字节数组转换为ASCII十进制数

时间:2011-01-17 15:05:15

标签: arrays gcc decimal avr

我正在编写一个程序和AVR ATMEGA88,使用TI TM3705A芯片读取FDX RFID标签,并通过UART将其传输到另一个处理器。该芯片使用15625波特,而另一个处理器将以19200波特率接收数据。

想法是读取输入数据(38位ID号 - 例如00 11 E3 D6 7C),CRC检查它然后将其输出为友好的12位十进制数(000300144252),表示该ID的唯一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没有大中间缓冲区等?内存对这些芯片有点限制。

2 个答案:

答案 0 :(得分:0)

转换为十进制计算成本很高 - 无论是自己动手还是将其委托给库函数(例如sprintf())都不会改变它。这里更复杂的是它是一个相对较大的值:38位,大于32位。

使用sprintf(),使用"%lld"打印long long。如果编译器支持long long类型但sprintf()没有,那么您可以手动执行:

static void
convert_to_decimal(char[] dst, unsigned long long src)
{
    int i;

    for (i = 0; i < 12; i ++) {
        dst[11 - i] = '0' + (int)(src % 10);
        src /= 10;
    }
    dst[12] = 0;
}

此函数在dst[](终止NUL)中写出12-char结果。请注意,这意味着除以10,编译器将转换为包含相对复杂的函数。

如果你的编译器不支持long long类型(或试图进行除法时的扼流圈),那么你必须自己实现这个操作,这需要一些数学知识。最终,this article可能有用 - 或者不是。

答案 1 :(得分:0)

经过大量的搜索和反复试验,我找到了解决方案。

我误解了我看到的错误,托马斯是对的。当添加到我自己的功能中时,该功能对于芯片来说太大了。

明显的选择没有去任何地方,但我会在这里列出它们以帮助其他新手来解决这个问题。

itoa() - 16位且 ultoa() - 实现了32位但是太小了。

sprintf(%d)太小而且WinAVR(AVR-GCC)中未实现 sprintf(%lld)

此代码有效(警告):

void main()
{
    unsigned long long tagid;
    char tagid_str[12];

    tagid = 109876543210ull

    convert_to_decimal(tagid_str, tagid);
}

void convert_to_decimal(char* dst, unsigned long long src) 
{     
    int i;
    for (i = 0; i < 12; i ++) 
    {         
        dst[11 - i] = '0' + (int)(src % 10);
        src /= 10;     
    }     

    dst[12] = 0; 
} 

但请查看统计数据:

程序:7358字节( 89.8%已满) (.text + .data + .bootloader)

数据:256字节( 25.0%已满) (.data + .bss + .noinit)

罪魁祸首是运营商。我无法解释为什么长时间使用它会产生近8k的代码!

这是一个可行的替代方案。我修改它只使用无符号长long (64位),最多12位十进制数,以适应我正在使用的RFID阅读器格式。

void main()
{
    unsigned long long tagid;
    char tagid_str[12];

    tagid = 000000000000ull;
    ulltostr((unsigned long long)tagid, tagid_str);

    tagid = 000000000001ull;
    ulltostr((unsigned long long)tagid, tagid_str);

    tagid = 109876543210ull;
    ulltostr((unsigned long long)tagid, tagid_str);

    tagid = 900000000000ull;
    ulltostr((unsigned long long)tagid, tagid_str);

    tagid = 999999999999ull;
    ulltostr((unsigned long long)tagid, tagid_str);
}

//http://www.avrfreaks.net/index.php?name=PNphpBB2&file=viewtopic&t=31199

void ulltostr(unsigned long long val, char *s ) 
{ 
  char *p; 
  unsigned char d, i; 
  unsigned char zero; 
  unsigned long long test; 
  unsigned long long uval = val; 

  p = s; 

  zero = 1; 

  i = 12; 
  do{ 
    i--;    
    if ( i==0)   test =10; 
    else if ( i==1) test =100; 
    else if ( i==2) test =1000; 
    else if ( i==3) test =10000; 
    else if ( i==4) test =100000; 
    else if ( i==5) test =1000000; 
    else if ( i==6) test =10000000; 
    else if ( i==7) test =100000000; 
    else if ( i==8) test =1000000000; 
    else if ( i==9) test =10000000000; 
    else if ( i==10) test=100000000000; 
    else if ( i==11) test=1000000000000; 
    else if ( i==12) test=10000000000000; 

    for( d = '0'; uval >= test; uval -= test ) 
    { 
      d++; 
      zero = 0; 
    } 
    if( zero == 0 ) 
      *p++ = d ; 
  }while( i ); 

  *p++ = (unsigned char)uval + '0'; 
}

统计数据:

程序:758字节( 9.3%完整) (.text + .data + .bootloader)

数据:0字节( 0.0%完整) (.data + .bss + .noinit)

很多更好:)

我大部分时间都在Douglas Jones,但答案最终来自AVR Freaks