I'm to stupid right now to solve this problem...
I get a BCD number (every digit is an own 4Bit representation)
For example, what I want:
Output: BCD 0x415
Input: 0x202
What have I tried:
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;
}
But I know that's very wrong this would be 202 in Bit representation and then split into 5 nibbles and then represented as decimal number again
I can solve the problem on paper but I just cant get it in a simple C-Code
You got it the wrong way round. Your code is converting from BCD to binary, just as your question's (original) title says. But the input and output values you provided are correct only if you convert from binary to BCD. In that case, try:
#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;
}
Proof: http://ideone.com/R0reQh
Try the following.
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;
}
Also one may try the following variant (although maybe little inefficient)
/*
Copyright (c) 2016 enthusiasticgeek<[email protected]> 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;
}
The real problem here is confusion of bases and units
The 202 should be HEX which equates to 514 decimal... and therefore the BCD calcs are correct
Binary code decimal will convert the decimal (514) into three nibble sized fields: - 5 = 0101 - 1 = 0001 - 4 = 0100
The bigger problem was that you have the title the wrong way around, and you are converting Uint to BCD, whereas the title asked for BCD to Unint
My 2 cents, I needed similar for a RTC chip which used BCD to encode the time and date info. Came up with the following macros that worked fine for the requirement:
#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))))
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With