Jump to content
43oh

Converting binary to decimal (BCD)


Recommended Posts

Those are the final versions, the ones I will be using from now on I guess. The C's ease of use (relative :),), and the speed of asm.

The first one uses only 50 clock cycles, the second one 83, and the third one between 109 and 123.

 

The first one takes up to 12 bit number and returns 4 digit packed BCD.

 

The second one takes up to 12 bit number and a pointer to char array which is then populated with 4 digit BCD result, MSD in the first element.

 

The third one is just like the second, but it maps digits to ASCII characters and blanks leading zeros (returns space instead of 0.)

This one is perfect for use with HD44780 LCD displays.

You feed it binary number (might be output from ADC) and you get an array of chars ready to be sent to the LCD.

For example, number 1234 will be returned as {"0x31",0x32","0x33","0x34"}, then all you need to do is set the address on the display and send elements one by one. Display will look like "1234."

If the number is smaller, 12 for example, leading digits will be blanked {"0x20",0x20","0x31","0x32"} and the display will look like " 12", meaning you don't have to mess around with positioning.

 

First one, binary to packed bcd

unsigned int bcd = binaryToPackedBCD(1234);

unsigned int binaryToPackedBCD(unsigned int n) {
   __asm(" clr		R14");
   __asm(" rla		R12");
   __asm(" rla		R12");
   __asm(" rla		R12");
   __asm(" rla		R12");
   __asm(" rla		R12");
   __asm(" dadd	R14, R14");
   __asm(" rla		R12");
   __asm(" dadd	R14, R14");
   __asm(" rla		R12");
   __asm(" dadd	R14, R14");
   __asm(" rla		R12");
   __asm(" dadd	R14, R14");
   __asm(" rla		R12");
   __asm(" dadd	R14, R14");
   __asm(" rla		R12");
   __asm(" dadd	R14, R14");
   __asm(" rla		R12");
   __asm(" dadd	R14, R14");
   __asm(" rla		R12");
   __asm(" dadd	R14, R14");
   __asm(" rla		R12");
   __asm(" dadd	R14, R14");
   __asm(" rla		R12");
   __asm(" dadd	R14, R14");
   __asm(" rla		R12");
   __asm(" dadd	R14, R14");
   __asm(" rla		R12");
   __asm(" dadd	R14, R14");
   __asm(" mov		R14, R12");
   return n;
}

 

Second one, binary to array (unpacked)

unsigned char bcd[4] = {0,0,0,0};

binaryToUnpackedBCD(1234, bcd);

void binaryToUnpackedBCD(unsigned int n, unsigned char * digits) {
   __asm(" clr		R14");
   __asm(" rla		R12");
   __asm(" rla		R12");
   __asm(" rla		R12");
   __asm(" rla		R12");
   __asm(" rla		R12");
   __asm(" dadd	R14, R14");
   __asm(" rla		R12");
   __asm(" dadd	R14, R14");
   __asm(" rla		R12");
   __asm(" dadd	R14, R14");
   __asm(" rla		R12");
   __asm(" dadd	R14, R14");
   __asm(" rla		R12");
   __asm(" dadd	R14, R14");
   __asm(" rla		R12");
   __asm(" dadd	R14, R14");
   __asm(" rla		R12");
   __asm(" dadd	R14, R14");
   __asm(" rla		R12");
   __asm(" dadd	R14, R14");
   __asm(" rla		R12");
   __asm(" dadd	R14, R14");
   __asm(" rla		R12");
   __asm(" dadd	R14, R14");
   __asm(" rla		R12");
   __asm(" dadd	R14, R14");
   __asm(" rla		R12");
   __asm(" dadd	R14, R14");
   __asm(" mov.b	R14, 3(R13)");
   __asm(" swpb	R14");
   __asm(" mov.b	R14, 1(R13)");
   __asm(" rra		R14");
   __asm(" rra		R14");
   __asm(" rra		R14");
   __asm(" rra		R14");
   __asm(" mov.b	R14, 0(R13)");
   __asm(" swpb	R14");
   __asm(" mov.b	R14, 2(R13)");
   __asm(" and		#0x0F0F, 0(R13)");
   __asm(" and		#0x0F0F, 2(R13)");
   return;
}

 

Third one, binary to ASCII or HD44780

unsigned char chars[4] = {0,0,0,0};

binaryToASCII(780, chars);

void binaryToASCII(unsigned int n, unsigned char * characters) {
   __asm(" clr		R14");
   __asm(" rla		R12");
   __asm(" rla		R12");
   __asm(" rla		R12");
   __asm(" rla		R12");
   __asm(" rla		R12");
   __asm(" dadd	R14, R14");
   __asm(" rla		R12");
   __asm(" dadd	R14, R14");
   __asm(" rla		R12");
   __asm(" dadd	R14, R14");
   __asm(" rla		R12");
   __asm(" dadd	R14, R14");
   __asm(" rla		R12");
   __asm(" dadd	R14, R14");
   __asm(" rla		R12");
   __asm(" dadd	R14, R14");
   __asm(" rla		R12");
   __asm(" dadd	R14, R14");
   __asm(" rla		R12");
   __asm(" dadd	R14, R14");
   __asm(" rla		R12");
   __asm(" dadd	R14, R14");
   __asm(" rla		R12");
   __asm(" dadd	R14, R14");
   __asm(" rla		R12");
   __asm(" dadd	R14, R14");
   __asm(" rla		R12");
   __asm(" dadd	R14, R14");
   __asm(" mov.b	R14, 3(R13)");
   __asm(" swpb	R14");
   __asm(" mov.b	R14, 1(R13)");
   __asm(" rra		R14");
   __asm(" rra		R14");
   __asm(" rra		R14");
   __asm(" rra		R14");
   __asm(" mov.b	R14, 0(R13)");
   __asm(" swpb	R14");
   __asm(" mov.b	R14, 2(R13)");
   __asm(" and		#0x0F0F, 0(R13)");
   __asm(" and		#0x0F0F, 2(R13)");
   __asm(" add.b	#0x30, 3(R13)");
   __asm(" tst.b	0(R13)");
   __asm(" jnz l1");
   __asm(" mov.b	#0x20, 0(R13)");
   __asm(" tst.b	1(R13)");
   __asm(" jnz l2");
   __asm(" mov.b	#0x20, 1(R13)");
   __asm(" tst.b	2(R13)");
   __asm(" jnz l3");
   __asm(" mov.b	#0x20, 2(R13)");
   __asm(" jmp l4");
   __asm("l1:");
   __asm(" add.b	#0x30, 0(R13)");
   __asm("l2:");
   __asm(" add.b	#0x30, 1(R13)");
   __asm("l3:");
   __asm(" add.b	#0x30, 2(R13)");
   __asm("l4:");
   return;
}

Link to post
Share on other sites

To make my last function more usable, I have changed it a little bit and included scale.

This will be useful for example when sending ADC output to display.

The scale can be from 0-4 (anything >4 will be treated as 4.)

 

Here's how the output will look like on the display:

 

     scale 0  scale 1  scale 2  scale 3  scale 4
1234     1234    123.4    12.34    1.234    .1234
567       567     56.7     5.67    0.567    .0567
89         89      8.9     0.89    0.089    .0089
1           1      0.1     0.01    0.001    .0001
0           0      0.0     0.00    0.000    .0000

 


void binaryToASCIIScale(unsigned int n, unsigned char * digits, unsigned int scale);
unsigned char s[5] = {0,0,0,0,0};

binaryToASCIIScale(1234, s, 2);

void binaryToASCIIScale(unsigned int n, unsigned char * digits, unsigned int scale) {
   __asm(" clr		R15");
   __asm(" rla		R12");
   __asm(" rla		R12");
   __asm(" rla		R12");
   __asm(" rla		R12");
   __asm(" rla		R12");
   __asm(" dadd	R15, R15");
   __asm(" rla		R12");
   __asm(" dadd	R15, R15");
   __asm(" rla		R12");
   __asm(" dadd	R15, R15");
   __asm(" rla		R12");
   __asm(" dadd	R15, R15");
   __asm(" rla		R12");
   __asm(" dadd	R15, R15");
   __asm(" rla		R12");
   __asm(" dadd	R15, R15");
   __asm(" rla		R12");
   __asm(" dadd	R15, R15");
   __asm(" rla		R12");
   __asm(" dadd	R15, R15");
   __asm(" rla		R12");
   __asm(" dadd	R15, R15");
   __asm(" rla		R12");
   __asm(" dadd	R15, R15");
   __asm(" rla		R12");
   __asm(" dadd	R15, R15");
   __asm(" rla		R12");
   __asm(" dadd	R15, R15");
   __asm(" mov.b	R15, 3(R13)");
   __asm(" swpb	R15");
   __asm(" mov.b	R15, 1(R13)");
   __asm(" rra		R15");
   __asm(" rra		R15");
   __asm(" rra		R15");
   __asm(" rra		R15");
   __asm(" mov.b	R15, 0(R13)");
   __asm(" swpb	R15");
   __asm(" mov.b	R15, 2(R13)");
   __asm(" and		#0x0F0F, 0(R13)");
   __asm(" and		#0x0F0F, 2(R13)");
   __asm(" add.b	#0x30, 3(R13)");
   __asm(" tst.b	0(R13)");
   __asm(" jnz l10");
   __asm(" cmp	#3, R14");
   __asm(" jge l10");
   __asm(" mov.b	#0x20, 0(R13)");
   __asm(" tst.b	1(R13)");
   __asm(" jnz l20");
   __asm(" cmp	#2, R14");
   __asm(" jge l20");
   __asm(" mov.b	#0x20, 1(R13)");
   __asm(" tst.b	2(R13)");
   __asm(" jnz l30");
   __asm(" cmp	#1, R14");
   __asm(" jge l30");
   __asm(" mov.b	#0x20, 2(R13)");
   __asm(" jmp l40");
   __asm("l10:");
   __asm(" add.b	#0x30, 0(R13)");
   __asm("l20:");
   __asm(" add.b	#0x30, 1(R13)");
   __asm("l30:");
   __asm(" add.b	#0x30, 2(R13)");

   __asm("l40:");
   __asm("	tst	R14");
   __asm(" jz l80");

   __asm(" dec R14");
   __asm(" mov.b	3(R13), 4(R13)");
   __asm("	tst	R14");
   __asm(" jnz l50");
   __asm(" mov.b	#0x2E, 3(R13)");
   __asm(" jmp l90");
   __asm("l50:");

   __asm(" dec R14");
   __asm(" mov.b	2(R13), 3(R13)");
   __asm("	tst	R14");
   __asm(" jnz l60");
   __asm(" mov.b	#0x2E, 2(R13)");
   __asm(" jmp l90");
   __asm("l60:");

   __asm(" dec R14");
   __asm(" mov.b	1(R13), 2(R13)");
   __asm("	tst	R14");
   __asm(" jnz l70");
   __asm(" mov.b	#0x2E, 1(R13)");
   __asm(" jmp l90");
   __asm("l70:");

   __asm(" dec R14");
   __asm(" mov.b	0(R13), 1(R13)");
   __asm(" mov.b	#0x2E, 0(R13)");
   __asm(" jmp l90");

   __asm("l80:");
   __asm(" mov.b	3(R13), 4(R13)");
   __asm(" mov.b	2(R13), 3(R13)");
   __asm(" mov.b	1(R13), 2(R13)");
   __asm(" mov.b	0(R13), 1(R13)");
   __asm(" mov.b	#0x20, 0(R13)");

   __asm("l90:");

   return;
}

 

And asm version of the above:

.global binaryToASCIIScale

binaryToASCIIScale:
clr		R15
rla		R12
rla		R12
rla		R12
rla		R12
rla		R12
dadd	R15, R15
rla		R12
dadd	R15, R15
rla		R12
dadd	R15, R15
rla		R12
dadd	R15, R15
rla		R12
dadd	R15, R15
rla		R12
dadd	R15, R15
rla		R12
dadd	R15, R15
rla		R12
dadd	R15, R15
rla		R12
dadd	R15, R15
rla		R12
dadd	R15, R15
rla		R12
dadd	R15, R15
rla		R12
dadd	R15, R15
mov.b	R15, 3(R13)
swpb	R15
mov.b	R15, 1(R13)
rra		R15
rra		R15
rra		R15
rra		R15
mov.b	R15, 0(R13)
swpb	R15
	mov.b	R15, 2(R13)
and		#0x0F0F, 0(R13)
and		#0x0F0F, 2(R13)
add.b	#0x30, 3(R13)
tst.b	0(R13)
jnz l10
cmp	#3, R14
jge l10
mov.b	#0x20, 0(R13)
tst.b	1(R13)
jnz l20
cmp	#2, R14
jge l20
mov.b	#0x20, 1(R13)
tst.b	2(R13)
jnz l30
cmp	#1, R14
jge l30
mov.b	#0x20, 2(R13)
jmp l40
l10:
add.b	#0x30, 0(R13)
l20:
add.b	#0x30, 1(R13)
l30:
add.b	#0x30, 2(R13
l40:
tst	R14
jz l80
dec R14
mov.b	3(R13), 4(R13)
tst	R14
jnz l50
mov.b	#0x2E, 3(R13)
jmp l90
l50:
dec R14
mov.b	2(R13), 3(R13)
tst	R14
jnz l60
mov.b	#0x2E, 2(R13)
jmp l90
l60:
dec R14
mov.b	1(R13), 2(R13)
tst	R14
jnz l70
mov.b	#0x2E, 1(R13)
jmp l90
l70:
dec R14
mov.b	0(R13), 1(R13)
mov.b	#0x2E, 0(R13)
jmp l90
l80:
mov.b	3(R13), 4(R13)
mov.b	2(R13), 3(R13)
mov.b	1(R13), 2(R13)
mov.b	0(R13), 1(R13)
mov.b	#0x20, 0(R13)
l90:
   ret

Link to post
Share on other sites
  • 2 weeks later...

Here is a version modified for mspgcc. It uses a slightly different calling convention (args are put into R15:R12 from left to right)

I tested this on a MSP430G2231.

 

 

 

To make my last function more usable, I have changed it a little bit and included scale.

This will be useful for example when sending ADC output to display.

The scale can be from 0-4 (anything >4 will be treated as 4.)

 

Here's how the output will look like on the display:

 

     scale 0  scale 1  scale 2  scale 3  scale 4
1234     1234    123.4    12.34    1.234    .1234
567       567     56.7     5.67    0.567    .0567
89         89      8.9     0.89    0.089    .0089
1           1      0.1     0.01    0.001    .0001
0           0      0.0     0.00    0.000    .0000

  void binaryToASCIIScale(unsigned int n, unsigned char * digits, unsigned int scale);
   unsigned char s[5] = {0,0,0,0,0};
   int data=1234;
   int sc=2;

   void main (void){
   binaryToASCIIScale(data, s, sc);
   }

   void binaryToASCIIScale(unsigned int n, unsigned char * digits, unsigned int scale) {
       __asm(" clr      R12");
       __asm(" rla      R15");
       __asm(" rla      R15");
       __asm(" rla      R15");
       __asm(" rla      R15");
       __asm(" rla      R15");
       __asm(" dadd   R12, R12");
       __asm(" rla      R15");
       __asm(" dadd   R12, R12");
       __asm(" rla      R15");
       __asm(" dadd   R12, R12");
       __asm(" rla      R15");
       __asm(" dadd   R12, R12");
       __asm(" rla      R15");
       __asm(" dadd   R12, R12");
       __asm(" rla      R15");
       __asm(" dadd   R12, R12");
       __asm(" rla      R15");
       __asm(" dadd   R12, R12");
       __asm(" rla      R15");
       __asm(" dadd   R12, R12");
       __asm(" rla      R15");
       __asm(" dadd   R12, R12");
       __asm(" rla      R15");
       __asm(" dadd   R12, R12");
       __asm(" rla      R15");
       __asm(" dadd   R12, R12");
       __asm(" rla      R15");
       __asm(" dadd   R12, R12");
       __asm(" mov.b   R12, 3(R14)");
       __asm(" swpb   R12");
       __asm(" mov.b   R12, 1(R14)");
       __asm(" rra      R12");
       __asm(" rra      R12");
       __asm(" rra      R12");
       __asm(" rra      R12");
       __asm(" mov.b   R12, 0(R14)");
       __asm(" swpb   R12");
       __asm(" mov.b   R12, 2(R14)");
       __asm(" and      #0x0F0F, 0(R14)");
       __asm(" and      #0x0F0F, 2(R14)");
       __asm(" add.b   #0x30, 3(R14)");
       __asm(" tst.b   0(R14)");
       __asm(" jnz l10");
       __asm(" cmp   #3, R13");
       __asm(" jge l10");
       __asm(" mov.b   #0x20, 0(R14)");
       __asm(" tst.b   1(R14)");
       __asm(" jnz l20");
       __asm(" cmp   #2, R13");
       __asm(" jge l20");
       __asm(" mov.b   #0x20, 1(R14)");
       __asm(" tst.b   2(R14)");
       __asm(" jnz l30");
       __asm(" cmp   #1, R13");
       __asm(" jge l30");
       __asm(" mov.b   #0x20, 2(R14)");
       __asm(" jmp l40");
       __asm("l10:");
       __asm(" add.b   #0x30, 0(R14)");
       __asm("l20:");
       __asm(" add.b   #0x30, 1(R14)");
       __asm("l30:");
       __asm(" add.b   #0x30, 2(R14)");

       __asm("l40:");
       __asm("   tst   R13");
       __asm(" jz l80");

       __asm(" dec R13");
       __asm(" mov.b   3(R14), 4(R14)");
       __asm("   tst   R13");
       __asm(" jnz l50");
       __asm(" mov.b   #0x2E, 3(R14)");
       __asm(" jmp l90");
       __asm("l50:");

       __asm(" dec R13");
       __asm(" mov.b   2(R14), 3(R14)");
       __asm("   tst   R13");
       __asm(" jnz l60");
       __asm(" mov.b   #0x2E, 2(R14)");
       __asm(" jmp l90");
       __asm("l60:");

       __asm(" dec R13");
       __asm(" mov.b   1(R14), 2(R14)");
       __asm("   tst   R13");
       __asm(" jnz l70");
       __asm(" mov.b   #0x2E, 1(R14)");
       __asm(" jmp l90");
       __asm("l70:");

       __asm(" dec R13");
       __asm(" mov.b   0(R14), 1(R14)");
       __asm(" mov.b   #0x2E, 0(R14)");
       __asm(" jmp l90");

       __asm("l80:");
       __asm(" mov.b   3(R14), 4(R14)");
       __asm(" mov.b   2(R14), 3(R14)");
       __asm(" mov.b   1(R14), 2(R14)");
       __asm(" mov.b   0(R14), 1(R14)");
       __asm(" mov.b   #0x20, 0(R14)");

       __asm("l90:");

       return;
   }

Link to post
Share on other sites

Hey y'all, did you see this?

Ranjit[/url]":1er9xjjb]
void tostr(int i,char *str); //Converts Integers to String, useful routine

void tostr(int i,char *s)	// Convert Interger to String
{
char *p;
p=s;

if(i >= 200)
	p[0]= 2;
else if(i >= 100)
	p[0]= 1;
else
	p[0]= 0;

p[2]=i%10;

i-=p[2];
i/=10;
p[1]=i%10;

       p[3] = 0; // mark end of string
p[2]+=0x30;
p[1]+=0x30;
p[0]+=0x30;
}

'tostr' takes a binary integer (or character) and converts it to a string of chars that get printed on an HD44780.

I modified it to suit my application, now it displays four digits instead of three (the highest number is 9999):

    void PrintStr(char *Text);
       char foo[4];
   void tostr(int i,char *str); //Converts Integers to String, useful routine

// These three are used like this:
   void main (void) {
       tostr(counter,foo);
       sendInstruction(0xC0);
       PrintStr(foo);
   }
a
   void PrintStr(char *Text) {
   char *c;
   c = Text;
   while ((c != 0) && (*c != 0))
   {
       sendData(*c);
       c++;
   }
}
void tostr(int i,char *s) {	// Convert Integer to String
char *p;
p=s;
p[3]=i%10;
i-=p[3];
i/=10;
p[2]=i%10;
i-=p[2];
i/=10;
p[1]=i%10;
i-=p[1];
i/=10;
p[0]=i%10;
i-=p[0];
       p[4] = 0; // mark end of string
p[3]+=0x30;
p[2]+=0x30;
p[1]+=0x30;
p[0]+=0x30;
}

Feel free to ignore me if this isn't relevant.

Link to post
Share on other sites
  • 2 weeks later...

Hey RobG

 

Could you give a small example of how to use the Binary to ASCII code for the noobs like me? :shifty:

 

I am working on a project that uses the TI RTC code.

located here: http://focus.ti.com/general/docs/litabs ... r=slaa290a

 

The output for the clock is in BCD and I have not been able to figure out how to convert it.

I tried just adding 0x30 to the BCD output but that only works up to 9, so I though this may be the answer.

 

this is from the TI info:

"To be easily displayable on an LCD, all variables are encoded in

BCD. All variables, except the year, use one byte."

 

The clock is ticking away if only I could display it correctly.

 

thanks

Link to post
Share on other sites

Here's what you need to do, you have to get digits from nibbles:

int digit = (seconds >> 4) + 0x30;

send(digit);

digit = (seconds & 0x0F) + 0x30;

send(digit);

 

Repeat same for minutes and hours.

Basically, all variables are already BCD encoded meaning nibbles are between 0-9, no binary to BCD is necessary.

Link to post
Share on other sites

Ok thanks for the code!

 

RobG

I tried yours first and the display is not correct. It is not displaying the numbers its displaying symbols.

I think the + 30 is the culprit.

 

opossum

I tried yours second and its working correctly.

the difference is in the + '0'.

 

I understand that the +30 adds to the hex value that the character is supposed to be right? for the LCD

so since the nibble has the proper value do we not need to add the +30.

 

sorry if this is a noob question.

Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...