6

我现在很愚蠢,无法解决这个问题...

我得到一个 BCD 数字(每个数字都是自己的 4 位表示)

例如,我想要什么:

  • 输入:202(十六进制)== 514(十进制)
  • 输出:BCD 0x415

  • 输入:0x202

  • 位表示:0010 0000 0010 = 514

我尝试了什么:

unsigned int uiValue = 0x202;
unsigned int uiResult = 0;
unsigned int uiMultiplier = 1;
unsigned int uiDigit = 0;


// get the dec bcd value
while ( uiValue > 0 )
{
    uiDigit= uiValue & 0x0F;
    uiValue >>= 4;
    uiResult += uiMultiplier * uiDigit;
    uiMultiplier *= 10;
}

但我知道这是非常错误的,这将是位表示的 202,然后分成 5 个半字节,然后再次表示为十进制数

我可以在纸上解决问题,但我无法用简单的 C 代码解决

4

10 回答 10

14

你弄错了。正如您的问题(原始)标题所说,您的代码正在从BCD 转换为 binary 。但是您提供的输入和输出值只有在您从binary 转换为 BCD时才是正确的。在这种情况下,请尝试:

#include <stdio.h>

int main(void) {

   int binaryInput = 0x202; 
   int bcdResult = 0;
   int shift = 0;

   printf("Binary: 0x%x (dec: %d)\n", binaryInput , binaryInput );

   while (binaryInput > 0) {
      bcdResult |= (binaryInput % 10) << (shift++ << 2);
      binaryInput /= 10;
   }

   printf("BCD: 0x%x (dec: %d)\n", bcdResult , bcdResult );
   return 0;
}

证明:http: //ideone.com/R0reQh

于 2012-11-06T09:16:09.880 回答
2

试试下面的。

unsigned long toPackedBcd (unsigned int val)
{
  unsigned long bcdresult = 0; char i;


  for (i = 0; val; i++)
  {
    ((char*)&bcdresult)[i / 2] |= i & 1 ? (val % 10) << 4 : (val % 10) & 0xf;
    val /= 10;
  }
  return bcdresult;
}

也可以尝试以下变体(尽管可能效率低下)

/*
Copyright (c) 2016 enthusiasticgeek<enthusiasticgeek@gmail.com> Binary to Packed BCD
This code may be used (including commercial products) without warranties of any kind (use at your own risk)
as long as this copyright notice is retained.
Author, under no circumstances, shall not be responsible for any code crashes or bugs.
Exception to copyright code: 'reverse string function' which is taken from http://stackoverflow.com/questions/19853014/reversing-a-string-in-place-in-c-pointers#19853059
Double Dabble Algorithm for unsigned int explanation

255(binary) - base 10 -> 597(packed BCD) - base 16
     H|    T|    U|        (Keep shifting left)
               11111111
             1 1111111
            11 111111  
           111 11111
          1010 11111    <-----added 3 in unit's place (7+3 = 10) 
        1 0101 1111  
        1 1000 1111     <-----added 3 in unit's place (5+3 = 8)
       11 0001 111
      110 0011 11       
     1001 0011 11       <-----added 3 in ten's place (6+3 = 9)
   1 0010 0111 1  
   1 0010 1010 1        <-----added 3 in unit's place (7+3 = 10)
  10 0101 0101  -> binary 597 but bcd 255
  ^    ^    ^  
  |    |    |
  2    5    5   
*/
#include <stdio.h>   
#include <string.h>

//Function Prototypes
unsigned int binaryToPackedBCD (unsigned int binary); 
char * printPackedBCD(unsigned int bcd, char * bcd_string);

// For the following function see http://stackoverflow.com/questions/19853014/reversing-a-string-in-place-in-c-pointers#19853059
void reverse(char *str);

//Function Definitions
unsigned int binaryToPackedBCD (unsigned int binary) {
  const unsigned int TOTAL_BITS = 32;
  /*Place holder for bcd*/
  unsigned int bcd = 0;
  /*counters*/
  unsigned int i,j = 0;
  for (i=0; i<TOTAL_BITS; i++) {
     /*
      Identify the bit to append  to LSB of 8 byte or 32 bit word -
      First bitwise AND mask with 1. 
      Then shift to appropriate (nth shift) place. 
      Then shift the result back to the lsb position. 
     */
      unsigned int binary_bit_to_lsb = (1<<(TOTAL_BITS-1-i)&binary)>>(TOTAL_BITS-1-i);
      /*shift by 1 place and append bit to lsb*/
      bcd = ( bcd<<1 ) | binary_bit_to_lsb;       
      /*printf("=> %u\n",bcd);*/
      /*Don't add 3 for last bit shift i.e. in this case 32nd bit*/
      if( i >= TOTAL_BITS-1) { 
      break;
      }
      /*else continue*/
      /* Now, check every nibble from LSB to MSB and if greater than or equal 5 - add 3 if so */
      for (j=0; j<TOTAL_BITS; j+=4) {
        unsigned int temp = (bcd & (0xf<<j))>>j;
        if(temp >= 0x5) {
        /*printf("[%u,%u], %u, bcd = %u\n",i,j, temp, bcd);*/
        /*Now, add 3 at the appropriate nibble*/
         bcd = bcd  + (3<<j);
        // printf("Now bcd = %u\n", bcd);
        }
      }
  }
  /*printf("The number is %u\n",bcd);*/
  return bcd;
}   

char * printPackedBCD(unsigned int bcd, char * bcd_string) {
  const unsigned int TOTAL_BITS = 32;
  printf("[LSB] =>\n");
   /* Now, check every nibble from LSB to MSB and convert to char* */
  for (unsigned int j=0; j<TOTAL_BITS; j+=4) {
  //for (unsigned int j=TOTAL_BITS-1; j>=4; j-=4) {
      unsigned int temp = (bcd & (0xf<<j))>>j;
      if(temp==0){
    bcd_string[j/4] = '0';      
      } else if(temp==1){
    bcd_string[j/4] = '1';
      } else if(temp==2){
    bcd_string[j/4] = '2';
      } else if(temp==3){
    bcd_string[j/4] = '3';
      } else if(temp==4){
    bcd_string[j/4] = '4';
      } else if(temp==5){
    bcd_string[j/4] = '5';
      } else if(temp==6){
    bcd_string[j/4] = '6';
      } else if(temp==7){
    bcd_string[j/4] = '7';
      } else if(temp==8){
    bcd_string[j/4] = '8';
      } else if(temp==9){
    bcd_string[j/4] = '9';
      } else {
    bcd_string[j/4] = 'X';
      }
      printf ("[%u - nibble] => %c\n", j/4, bcd_string[j/4]);
  }      
  printf("<= [MSB]\n");
  reverse(bcd_string);
  return bcd_string;
}

// For the following function see http://stackoverflow.com/questions/19853014/reversing-a-string-in-place-in-c-pointers#19853059
void reverse(char *str)
{ 
    if (str != 0 && *str != '\0') // Non-null pointer; non-empty string
    {
    char *end = str + strlen(str) - 1; 
    while (str < end)
    {
        char tmp = *str; 
        *str++ = *end; 
        *end-- = tmp;
    } 
    }
}

int main(int argc, char * argv[])
{
  unsigned int number = 255;
  unsigned int bcd = binaryToPackedBCD(number);
  char bcd_string[8];
  printPackedBCD(bcd, bcd_string);
  printf("Binary (Base 10) = %u => Packed BCD (Base 16) = %u\n OR \nPacked BCD String = %s\n", number, bcd, bcd_string);
  return 0;
}
于 2012-12-10T16:28:09.783 回答
1

这里真正的问题是基础和单位的混淆

202 应该是十六进制,等于十进制 514 ......因此 BCD 计算是正确的

二进制代码十进制将十进制 (514) 转换为三个半字节大小的字段: - 5 = 0101 - 1 = 0001 - 4 = 0100

更大的问题是您的标题错误,并且您正在将 Uint 转换为 BCD,而标题要求将 BCD 转换为 Unint

于 2012-11-06T09:13:52.727 回答
1

我的 2 美分,我需要类似的 RTC 芯片,它使用 BCD 来编码时间和日期信息。想出了以下可以很好地满足要求的宏:

#define MACRO_BCD_TO_HEX(x) ((BYTE) ((((x >> 4) & 0x0F) * 10) + (x & 0x0F)))

#define MACRO_HEX_TO_BCD(x) ((BYTE) (((x / 10 ) << 4) | ((x % 10))))

于 2021-07-08T23:00:57.640 回答
0

一个天真的但简单的解决方案:

char buffer[16];
sprintf(buffer, "%d", var);
sscanf(buffer, "%x", &var);
于 2012-11-06T09:17:20.550 回答
0

这是我开发的解决方案,适用于嵌入式系统,例如 Microchip PIC 微控制器:

#include <stdio.h>
void main(){
    unsigned int output = 0;
    unsigned int input;
    signed char a;
    //enter any number from 0 to 9999 here:
    input = 1265;
    for(a = 13; a >= 0; a--){
        if((output & 0xF) >= 5)
            output += 3;
        if(((output & 0xF0) >> 4) >= 5)
            output += (3 << 4);
        if(((output & 0xF00) >> 8) >= 5)
            output += (3 << 8);
        output = (output << 1) | ((input >> a) & 1);
    }
    printf("Input decimal or binary: %d\nOutput BCD: %X\nOutput decimal: %u\n", input, output, output);
}
于 2017-02-17T22:31:53.407 回答
0

这是我的字节转换版本:

//----------------------------------------------
// This function converts n bytes Binary (up to 8, but can be any size)
// value to n bytes BCD value or more.
//----------------------------------------------

void bin2bcdn(void * val, unsigned int8 cnt)
{
    unsigned int8  sz, y, buff[20];         // buff = malloc((cnt+1)*2);
    
    if(cnt > 8) sz = 64;                    // 8x8
    else        sz = cnt * 8 ;              // Size in bits of the data we shift
    
    memset(&buff , 0, sizeof(buff));        // Clears buffer
    memcpy(&buff, val, cnt);                // Copy the data to buffer

    while(sz && !(buff[cnt-1] & 0x80))      // Do not waste time with null bytes,
    {                                       // so search for first significative bit
        rotate_left(&buff, sizeof(buff));   // Rotate until we find some data
        sz--;                               // Done this one
    }
    while(sz--)                             // Anyting left?
    {
        for( y = 0; y < cnt+2; y++)         // Here we fix the nibbles
        {
            if(((buff[cnt+y] + 0x03) & 0x08) != 0) buff[cnt+y] += 0x03;
            if(((buff[cnt+y] + 0x30) & 0x80) != 0) buff[cnt+y] += 0x30;
        }
        rotate_left(&buff, sizeof(buff));   // Rotate the stuff
    }
    memcpy(val, &buff[cnt], cnt);           // Copy the buffer to the data
//  free(buff);       //in case used malloc
}   // :D Done
于 2020-09-17T12:57:16.337 回答
0
long bin2BCD(long binary) { // double dabble: 8 decimal digits in 32 bits BCD
  if (!binary) return 0;
  long bit = 0x4000000; //  99999999 max binary
  while (!(binary & bit)) bit >>= 1;  // skip to MSB

  long bcd = 0;
  long carry = 0;
  while (1) {
    bcd <<= 1;
    bcd += carry; // carry 6s to next BCD digits (10 + 6 = 0x10 = LSB of next BCD digit)
    if (bit & binary) bcd |= 1;
    if (!(bit >>= 1)) return bcd;
    carry = ((bcd + 0x33333333) & 0x88888888) >> 1; // carrys: 8s -> 4s
    carry += carry >> 1; // carrys 6s  
  }
}
于 2020-11-22T14:12:49.110 回答
0

简单的解决方案

#include <stdio.h>

int main(void) {

   int binaryInput = 514 ;      //0x202 
   int bcdResult = 0;
   int digit = 0;
   int i=1;

   printf("Binary: 0x%x (dec: %d)\n", binaryInput , binaryInput );

   while (binaryInput > 0) {
 
      digit = binaryInput %10;          //pick digit
      bcdResult = bcdResult+digit*i;
      i=16*i;
      binaryInput = binaryInput/ 10;
   }
   printf("BCD: 0x%x (dec: %d)\n", bcdResult , bcdResult );
   return 0;
}

二进制:0x202(十进制:514)

BCD:0x514(十进制:1300)

于 2020-11-26T15:23:03.677 回答
0

您还可以尝试以下方法:

在每次迭代中,剩余部分(表示为 nibble )位于其相应的位置。

uint32_t bcd_converter(int num)
{                          
  uint32_t temp=0;              
  int i=0;                 
  while(num>0){            
    temp|=((num%10)<<i);   
    i+=4;                  
    num/=10;               
  }                        
                           
  return temp;             
}                          

于 2022-02-09T13:39:45.713 回答