十进制到BCD到ASCII

时间:2017-06-08 20:57:10

标签: c ascii bcd

也许这个任务比我在下面写的要复杂一点,但接下来的代码是我对BCD的十进制。任务是输入一个十进制数,将其转换为BCD,然后转换为ASCII,以便它可以显示在微控制器上。据我所知,代码适用于转换为BCD的基本操作,但是在将其转换为ASCII时我会陷入困境。总输出为ASCII,因此可以在LCD上显示递增的值。

到目前为止我的代码:

int dec2bin(int a){              //Decimal to binary function                               
    int bin;                                                    
    int i =1;
    while (a!=0){                                               
    bin+=(a%2)*i;                                           
    i*=10;                                                  
    a/=2;                                                   
    }                                                           
    return bin;
}

unsigned int ConverttoBCD(int val){

    unsigned int unit = 0;
    unsigned int ten = 0;
    unsigned int hundred = 0;

    hundred = (val/100);
    ten = ((val-hundred*100)/10);
    unit = (val-(hundred*100+ten*10));
    uint8_t ret1 = dec2bin(unit);
    uint8_t ret2 = dec2bin((ten)<<4);
    uint8_t ret3 = dec2bin((hundred)<<8);
    return(ret3+ret2+ret1);
}

1 个答案:

答案 0 :(得分:1)

转换为BCD以获得数字的ASCII表示的想法实际上是“正确的”。给定BCD,您只需要为每个数字添加'0'以获取相应的ASCII值。

但是你的代码有几个问题。最重要的一点是,您尝试在8位类型中填充向左移位8位的值。这永远不会有效,那些8位将为零,想一想!然后我绝对了解你的dec2bin()函数应该做什么。

因此,我将为您提供一个可能的正确解决方案。关键的想法是为每个BCD数字使用char。当然,BCD数字只需要4位而char至少有8位 - 但无论如何你需要char来表示你的ASCII表示,当你的BCD数字已经在个人{{1}时你需要做的就是为每个人添加char

在此期间:通过划分和乘法转换为BCD是浪费资源。有一个很好的算法Double dabble,只能使用位移和加法转换为BCD。我在以下示例代码中使用它:

'0'

如果您实际知道您的目标平台以及您要转换的整数类型中有多少位,则不需要此#include <stdio.h> #include <string.h> // for determining the number of value bits in an integer type, // see https://stackoverflow.com/a/4589384/2371524 for this nice trick: #define IMAX_BITS(m) ((m) /((m)%0x3fffffffL+1) /0x3fffffffL %0x3fffffffL *30 \ + (m)%0x3fffffffL /((m)%31+1)/31%31*5 + 4-12/((m)%31+3)) // number of bits in unsigned int: #define UNSIGNEDINT_BITS IMAX_BITS((unsigned)-1) // convert to ASCII using BCD, return the number of digits: int toAscii(char *buf, int bufsize, unsigned val) { // sanity check, a buffer smaller than one digit is pointless if (bufsize < 1) return -1; // initialize output buffer to zero // if you don't have memset, use a loop here memset(buf, 0, bufsize); int scanstart = bufsize - 1; int i; // mask for single bits in value, start at most significant bit unsigned mask = 1U << (UNSIGNEDINT_BITS - 1); while (mask) { // extract single bit int bit = !!(val & mask); for (i = scanstart; i < bufsize; ++i) { // this is the "double dabble" trick -- in each iteration, // add 3 to each element that is greater than 4. This will // generate the correct overflowing bits while shifting for // BCD if (buf[i] > 4) buf[i] += 3; } // if we have filled the output buffer from the right far enough, // we have to scan one position earlier in the next iteration if (buf[scanstart] > 7) --scanstart; // check for overflow of our buffer: if (scanstart < 0) return -1; // now just shift the bits in the BCD digits: for (i = scanstart; i < bufsize - 1; ++i) { buf[i] <<= 1; buf[i] &= 0xf; buf[i] |= (buf[i+1] > 7); } // shift in the new bit from our value: buf[bufsize-1] <<= 1; buf[bufsize-1] &= 0xf; buf[bufsize-1] |= bit; // next bit: mask >>= 1; } // find first non-zero digit: for (i = 0; i < bufsize - 1; ++i) if (buf[i]) break; int digits = bufsize - i; // eliminate leading zero digits // (again, use a loop if you don't have memmove) // (or, if you're converting to a fixed number of digits and *want* // the leading zeros, just skip this step entirely, including the // loop above) memmove(buf, buf + i, digits); // convert to ascii: for (i = 0; i < digits; ++i) buf[i] += '0'; return digits; } int main(void) { // some simple test code: char buf[10]; int digits = toAscii(buf, 10, 471142); for (int i = 0; i < digits; ++i) { putchar(buf[i]); } puts(""); } “魔术宏”。