Jump to content


Photo

Converting binary to decimal (BCD)


  • Please log in to reply
24 replies to this topic

#1 RobG

RobG

    Level 5

  • Members
  • 2,999 posts
  • LocationCary, NC, US


Posted 03 July 2011 - 04:37 AM

EDIT: the final versions of converter are here

Until now, I could get away with wasting clock cycles in my code.
My current project however requires from me writing efficient code and saving every possible clock cycle that I can.
I started to optimize my code with binary to decimal conversion piece.
My usual way of doing conversion, modulus + division, is the easiest but at the same time most clock cycle consuming method.
I found few suggestions on the net, like using C's div function, which returns structure with quotient and remainder eliminating the need for modulus operation.
Another way of converting I found is to use shifts and additions, much faster, but there is still room for improvement.

I figured to get better results, I will need to use some hardware feature, but the value line does not come with MPY module. There's one instruction that can help speed up decimal conversion, not available in C directly, but available through intrinsic function or asm. I decided to give it a try and the results are very positive.

I created 5 different functions to convert 10 bit(ADC's resolution) binary into an array of decimal numbers.
The range is 0-999 and there's no logic to handle overflow (10 bits range is 0-1023,) I didn't want to complicate this for testing purposes.

Here are the results (clock cycles) for the numbers 9, 99, and 999:

1. Modulus+divide ----- 346 - 657 - 973
2. C's div ------------ 293 - 575 - 886
3. Shift+add ---------- 248 - 274 - 327
4. S+a with my mods --- 139 - 233 - 234
5. My converter ------- 133 - 141 - 162
6. My conv with cond -- 98 -- 134 - 193


Shift and add becomes slow when binary > 9. It is also limited, adding 4th digit or increasing the number of binary bits would affect the performance. This is true for modulus+divide method as well, but updating it for higher bit number is pretty easy.

The thing about my converter is that it produces BCD integer which then is converted into an array. If you don't need an array, you can save another 41 cycles! Expanding it to 12 or 16 bits would have little effect on performance in comparison with other methods. Using conditionals speeds up conversion of small numbers by about 25%, but it slows down conversion of large numbers by about 20% (10 bit conversion.) And there is still room for improvement, it can be re-written in asm.

#include "msp430g2231.h"
#include 

void modAndDiv(unsigned int n);
void modAndDivAlt(unsigned int n);
void versionOfHackersDelight(unsigned int n);
unsigned int decimalAdd(unsigned int n);
unsigned int decimalAddAlt(unsigned int n);

unsigned char decimalResults[3] = {0,0,0};

void main(void) {
WDTCTL = WDTPW + WDTHOLD;

unsigned int result; //BCD

result = decimalAdd(999); //121
decimalResults[2] = result & 0x000F;//8
decimalResults[1] = (result & 0x00F0)>>4;//24
decimalResults[0] = (result & 0x0F00)>>8;//9
//total 162

result = decimalAdd(99);//100
decimalResults[2] = result & 0x000F;//8
decimalResults[1] = (result & 0x00F0)>>4;//24
decimalResults[0] = (result & 0x0F00)>>8;//9
//total 141

result = decimalAdd(9);//92
decimalResults[2] = result & 0x000F;//8
decimalResults[1] = (result & 0x00F0)>>4;//24
decimalResults[0] = (result & 0x0F00)>>8;//9
//total 133

result = decimalAddAlt(999); //152
decimalResults[2] = result & 0x000F;//8
decimalResults[1] = (result & 0x00F0)>>4;//24
decimalResults[0] = (result & 0x0F00)>>8;//9
//total 193

result = decimalAddAlt(99);//93
decimalResults[2] = result & 0x000F;//8
decimalResults[1] = (result & 0x00F0)>>4;//24
decimalResults[0] = (result & 0x0F00)>>8;//9
//total 134

result = decimalAddAlt(9);//57
decimalResults[2] = result & 0x000F;//8
decimalResults[1] = (result & 0x00F0)>>4;//24
decimalResults[0] = (result & 0x0F00)>>8;//9
//total 98

modAndDiv(999);
//total 973
modAndDiv(99);
//total 657
modAndDiv(9);
//total 346

modAndDivAlt(999);
//total 886
modAndDivAlt(99);
//total 575
modAndDivAlt(9);
//total 293

versionOfHackersDelight(999);
//total 234 (original 327)
versionOfHackersDelight(99);
//total 233 (original 274)
versionOfHackersDelight(9);
//total 139 (original 248)
}

unsigned int decimalAdd(unsigned int n) {
unsigned int result = 0;
result = _bcd_add_short(result, (n & 0x0007));
if(n & 0x0008)
result = _bcd_add_short(result, 0x0008);
if(n & 0x0010)
result = _bcd_add_short(result, 0x0016);
if(n & 0x0020)
result = _bcd_add_short(result, 0x0032);
if(n & 0x0040)
result = _bcd_add_short(result, 0x0064);
if(n & 0x0080)
result = _bcd_add_short(result, 0x0128);
if(n & 0x0100)
result = _bcd_add_short(result, 0x0256);
if(n & 0x0200)
result = _bcd_add_short(result, 0x0512);
return result;
}

void modAndDiv(unsigned int n) {
decimalResults[0] = 0;
decimalResults[1] = 0;
decimalResults[2] = 0;
unsigned char charIndex = 2;
while(n > 0) {
decimalResults[charIndex] = n % 10;
n /= 10;
charIndex--;
}
}

void modAndDivAlt(unsigned int n) {
decimalResults[0] = 0;
decimalResults[1] = 0;
decimalResults[2] = 0;
unsigned char charIndex = 2;
div_t d;
while(n > 0) {
d = div(n,10);
decimalResults[charIndex] = d.rem;
n= d.quot;
charIndex--;
}
}

void versionOfHackersDelight(unsigned int n) {
static const unsigned int rem[12] = {
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1
};
unsigned int q1, q2, q3, q, r;
decimalResults[0] = 0;
decimalResults[1] = 0;
decimalResults[2] = 0;

q1 = (n >> 1) + (n >> 2);
q1 += q1 >> 4;
q1 += q1 >> 8;
q2 = q1 >> 3;
r = n - ((q2 << 3) + q2 + q2); // originally r = n - q2 * 10;
q = q2 + (r > 9);
decimalResults[2] = rem[r];

if(n<10) // added this condition to exit when n<10, following calculations are just a waste
return;

q3 = (q >> 1) + (q >> 2);
q3 += q3 >> 4;
q3 = q3 >> 3;
r = q - ((q3 << 3) + q3 + q3); // originally r = q - q3 * 10;
decimalResults[0] = q3 + (r > 9);
decimalResults[1] = rem[r];
}

unsigned int decimalAddAlt(unsigned int n) {
unsigned int result = 0;
result = _bcd_add_short(result, (n & 0x0007));
if(n & 0x0008) {
result = _bcd_add_short(result, 0x0008);
if(n<16)
return result;
}
if(n & 0x0010) {
result = _bcd_add_short(result, 0x0016);
if(n<32)
return result;
}
if(n & 0x0020) {
result = _bcd_add_short(result, 0x0032);
if(n<64)
return result;
}
if(n & 0x0040) {
result = _bcd_add_short(result, 0x0064);
if(n<128)
return result;
}
if(n & 0x0080) {
result = _bcd_add_short(result, 0x0128);
if(n<256)
return result;
}
if(n & 0x0100) {
result = _bcd_add_short(result, 0x0256);
if(n<512)
return result;
}
if(n & 0x0200)
result = _bcd_add_short(result, 0x0512);

return result;
}



Here's the actual binary to BCD converter, both versions:

result = convertToBinary(binary);
result = convertToBinaryAlt(binary);
decimalResults[3] = result & 0x000F;
decimalResults[2] = (result & 0x00F0)>>4;
decimalResults[1] = (result & 0x0F00)>>8;
decimalResults[0] = (result & 0xF000)>>12;


unsigned int convertToBinary(unsigned int n) {
unsigned int result = 0;
result = _bcd_add_short(result, (n & 0x0007));
if(n & 0x0008)
result = _bcd_add_short(result, 0x0008);
if(n & 0x0010)
result = _bcd_add_short(result, 0x0016);
if(n & 0x0020)
result = _bcd_add_short(result, 0x0032);
if(n & 0x0040)
result = _bcd_add_short(result, 0x0064);
if(n & 0x0080)
result = _bcd_add_short(result, 0x0128);
if(n & 0x0100)
result = _bcd_add_short(result, 0x0256);
if(n & 0x0200)
result = _bcd_add_short(result, 0x0512);
return result;
}

//alternate version with conditionals
unsigned int convertToBinaryAlt(unsigned int n) {
unsigned int result = 0;
result = _bcd_add_short(result, (n & 0x0007));
if(n & 0x0008) {
result = _bcd_add_short(result, 0x0008);
if(n<16)
return result;
}
if(n & 0x0010) {
result = _bcd_add_short(result, 0x0016);
if(n<32)
return result;
}
if(n & 0x0020) {
result = _bcd_add_short(result, 0x0032);
if(n<64)
return result;
}
if(n & 0x0040) {
result = _bcd_add_short(result, 0x0064);
if(n<128)
return result;
}
if(n & 0x0080) {
result = _bcd_add_short(result, 0x0128);
if(n<256)
return result;
}
if(n & 0x0100) {
result = _bcd_add_short(result, 0x0256);
if(n<512)
return result;
}
if(n & 0x0200)
result = _bcd_add_short(result, 0x0512);

return result;
}


#2 nobody

nobody

    Level 1

  • Members
  • 94 posts

Posted 03 July 2011 - 05:10 AM

If you have enough free flash, try using conversion tables (fully or partially). This is the fastest method.

#3 oPossum

oPossum

    Poke me with a Stick

  • Members
  • 904 posts
  • LocationMichigan, USA


Posted 03 July 2011 - 05:16 AM


;

; Convert 16 bit binary to 24 bit packed BCD

; C prototype: unsigned long bin2bcd(unsigned x)

;

        clr     R13

        clr     R14

        swpb    R12

        tst.b   R12

        jz      lsb

        swpb    R12

        rla     R12

        dadd    R14, R14

        rla     R12

        dadd    R14, R14

        rla     R12

        dadd    R14, R14

        rla     R12

        dadd    R14, R14

        rla     R12

        dadd    R14, R14

        rla     R12

        dadd    R14, R14

        rla     R12

        dadd    R14, R14

        rla     R12

        dadd    R14, R14

lsb

        rla     R12

        dadd    R14, R14

        rla     R12

        dadd    R14, R14

        rla     R12

        dadd    R14, R14

        rla     R12

        dadd    R14, R14

        rla     R12

        dadd    R14, R14

        rla     R12

        dadd    R14, R14

        dadd    R13, R13

        rla     R12

        dadd    R14, R14

        dadd    R13, R13

        rla     R12

        dadd    R14, R14

        dadd    R13, R13

        mov     R14, R12

        ret


  • RobG likes this
Think in assembly, write in C. Sent from a bunker in an undisclosed location deep beneath a mountain.

#4 RobG

RobG

    Level 5

  • Members
  • 2,999 posts
  • LocationCary, NC, US


Posted 03 July 2011 - 12:00 PM

This is very nice oPossum, so we are now down to 85, 85, and 102 clock cycles (44 conversion + 41 array, 44 + 41, 61 + 41.)

#5 oPossum

oPossum

    Poke me with a Stick

  • Members
  • 904 posts
  • LocationMichigan, USA


Posted 03 July 2011 - 01:45 PM

Test case and commented code for binary to packed BCD and binary to unpacked BCD

This could be tweaked for 3 or 4 digits if you really need maximum speed and compactness.

#include "msp430g2211.h"

unsigned long bin2pbcd(unsigned bin);  // Binary to packed BCD
void bin2bcd(unsigned bin, char * bcd); // Binary to unpacked BCD

int main(void)
{
    unsigned long pbcd;
    char bcd[5];

    WDTCTL = WDTPW + WDTHOLD;             // Stop watchdog timer
    
    pbcd = bin2pbcd(0);                 // 43 cycles
    pbcd = bin2pbcd(1);                 // 43 cycles
    pbcd = bin2pbcd(9);                 // 44 cycles
    pbcd = bin2pbcd(99);                // 44 cycles
    pbcd = bin2pbcd(999);               // 61 cycles
    pbcd = bin2pbcd(9999);              // 61 cycles    
    pbcd = bin2pbcd(65535);             // 60 cycles
    
    bin2bcd(0, bcd);                    // 77 cycles
    bin2bcd(1, bcd);                    // 77 cycles
    bin2bcd(9, bcd);                    // 78 cycles
    bin2bcd(99, bcd);                   // 78 cycles
    bin2bcd(999, bcd);                  // 95 cycles
    bin2bcd(9999, bcd);                 // 95 cycles
    bin2bcd(12345, bcd);                // 95 cycles
    bin2bcd(54321, bcd);                // 95 cycles
    bin2bcd(65535, bcd);                // 94 cycles
}
; bin2bcd.asm

           .cdecls C, LIST, "msp430g2211.h"  ; Include device header file

            .text
            .global bin2pbcd
            .global bin2bcd

;
; Convert 16 bit binary to 20 bit packed BCD
; C prototype: unsigned long bin2pbcd(unsigned bin)
;
bin2pbcd
        clr     R13                     ; Clear BCD result
        clr     R14                     ;
        swpb    R12                     ; Swap upper/lower byte
        tst.b   R12                     ; Check if upper byte is zero
        jz      lsb                     ; Yes, skip upper byte
        swpb    R12                     ; Sway upper/lower bytes back
        rla     R12                     ; Test msb of binary
        dadd    R14, R14                ; Multiply BCD by 2 and add binary bit
        rla     R12                     ; Test bit 14 of binary
        dadd    R14, R14                ; Multiply BCD by 2 and add binary bit
        rla     R12                     ; Test bit 13 of binary
        dadd    R14, R14                ; Multiply BCD by 2 and add binary bit
        rla     R12                     ; Test bit 12 of binary
        dadd    R14, R14                ; Multiply BCD by 2 and add binary bit
        rla     R12                     ; Test bit 11 of binary
        dadd    R14, R14                ; Multiply BCD by 2 and add binary bit
        rla     R12                     ; Test bit 10 of binary
        dadd    R14, R14                ; Multiply BCD by 2 and add binary bit
        rla     R12                     ; Test bit 9 of binary
        dadd    R14, R14                ; Multiply BCD by 2 and add binary bit
        rla     R12                     ; Test bit 8 of binary
        dadd    R14, R14                ; Multiply BCD by 2 and add binary bit
lsb
        rla     R12                     ; Test bit 7 of binary
        dadd    R14, R14                ; Multiply BCD by 2 and add binary bit
        rla     R12                     ; Test bit 6 of binary
        dadd    R14, R14                ; Multiply BCD by 2 and add binary bit
        rla     R12                     ; Test bit 5 of binary
        dadd    R14, R14                ; Multiply BCD by 2 and add binary bit
        rla     R12                     ; Test bit 4 of binary
        dadd    R14, R14                ; Multiply BCD by 2 and add binary bit
        rla     R12                     ; Test bit 3 of binary
        dadd    R14, R14                ; Multiply BCD by 2 and add binary bit
        rla     R12                     ; Test bit 2 of binary
        dadd    R14, R14                ; Multiply BCD by 2 and add binary bit
        dadd    R13, R13                ;
        rla     R12                     ; Test bit 1 of binary
        dadd    R14, R14                ; Multiply BCD by 2 and add binary bit
        dadd    R13, R13                ;
        rla     R12                     ; Test bit 0 of binary
        dadd    R14, R14                ; Multiply BCD by 2 and add binary bit
        dadd    R13, R13                ;
        mov     R14, R12                ; Move LSW in to proper register
        ret                             ; Return

; Convert 16 bit binary to 5 characters of BCD
; C prototype: void bin2bcd(unsigned bin, char * bcd)
;
bin2bcd
        mov     R13, R15                ; Save BCD pointer
        call    #bin2pbcd               ; Convert to packed BCD
        mov     R12, R14                ; Copy digits 2 -> 5
        and     #0x0F0F, R12            ; Mask digits 3 & 5
        mov.b   R12, 4(R15)             ; Move digit 5 to bcd[4]
        swpb    R12                     ; Swap digits 3 & 5
        mov.b   R12, 2(R15)             ; Move digit 3 to bcd[2]
        rra     R14                     ; Shift digits 2 & 4 to lower nibble
        rra     R14                     ;
        rra     R14                     ;
        rra     R14                     ;
        and     #0x0F0F, R14            ; Mask digits 2 & 4
        mov.b   R14, 3(R15)             ; Move digit 4 to bcd[3]
        swpb    R14                     ; Swap digits 2 & 4
        mov.b   R14, 1(R15)             ; Move digit 2 to bcd[1]
        mov.b   R13, 0(R15)             ; Move digit 1 to bcd[0]
        ret                             ; Return

  • bluehash and gwdeveloper like this
Think in assembly, write in C. Sent from a bunker in an undisclosed location deep beneath a mountain.

#6 Mac

Mac

    Level 2

  • Members
  • 245 posts
  • LocationMichigan, USA

Posted 03 July 2011 - 10:45 PM

oPossum,

This is good stuff. Please keep it coming.

Is there a repository of assembly code snippets like this somewhere? You know, like the PIC code repository at PICLIST, but for MSP430?

Cheerful regards, Mike

#7 bluehash

bluehash

    Site Admin

  • Administrators
  • 6,429 posts

Posted 04 July 2011 - 02:05 AM

hmm.. the code vault was meant for that. This way you get support and code, both together.

43oh - MSP430, TivaC, ARM-Sitara and C2000 Discussion, News, Projects and Hacks

 

 


#8 Mac

Mac

    Level 2

  • Members
  • 245 posts
  • LocationMichigan, USA

Posted 04 July 2011 - 03:37 AM

hmm.. the code vault was meant for that. This way you get support and code, both together.


The oldest post in "the code vault" seems to be from August 2010. Is that when TI came out with the MSP430?

#9 RobG

RobG

    Level 5

  • Members
  • 2,999 posts
  • LocationCary, NC, US


Posted 04 July 2011 - 04:01 AM

Now I am thinking I have approached this all wrong.
I wanted to stick with C and that's why I searched for C examples, and that's why I came up with my C routine.
Instead, I should have abandoned C all together or at least for the parts that are inefficient and use asm.

Quick search on Google and I found what I was looking for (I knew this was done already, just couldn't find it.)

slaa151
msp430x11x1_ca_07.s43
and many more, like thermometer code examples

;------------------------------------------------------------------------------
bin2bcd;     Subroutine for converting 16 bit binary to BCD
;              Input: R12 is 16 bit binary
;            Working: R15 is used and not saved
;             Output: R14|R13 5 digit BCD
;------------------------------------------------------------------------------
             mov #16,R15
             clr R14
             clr R13
L$1          rla R12
             dadd R13,R13
             dadd R14,R14
             dec R15
             jnz L$1
             ret

Since loops are used, this is not the most efficient code but it's not that bad, and it is very close in efficiency to my C routine.
That said, those who do not want to use asm, use my routine, it's the fastest I know of written in C.

@Mac and bluehash, the reason for this thread in Code Vault is just that, share the code :)

#10 Mac

Mac

    Level 2

  • Members
  • 245 posts
  • LocationMichigan, USA

Posted 04 July 2011 - 11:59 AM

... @Mac and bluehash, the reason for this thread in Code Vault is just that, share the code :)


The emphasis (in code vault) seems to be C and there's nothing here more than a year old. I'm looking for assembly language examples like the program listing you found which was dated February 2005. Thanks for posting, btw...

You should recognize oPossum's code as an "unrolled" and optimized version of the loop routine you posted. Just for fun, I rolled it back up into a loop to characterize a four digit (0..9999) version yesterday;

;
;  bin2bcd, 16 bit binary to 4 digit packed bcd (0..9999)
;
        clr.w   R14             ; 8 words, 83 cycles
        mov.w   #1, R13         ;                      (1)
xlp     rla.w   R12             ;                      (1)
        dadd.w  R14, R14        ;                      (1)
        rla.w   R13             ;                      (1)
        jnz     xlp             ;                      (2)
        mov.w   R14, R12        ; return pbcd in R12   (2)

Cheerful regards, Mike McLaren, K8LH
  • oPossum likes this

#11 bluehash

bluehash

    Site Admin

  • Administrators
  • 6,429 posts

Posted 04 July 2011 - 12:17 PM

hmm.. the code vault was meant for that. This way you get support and code, both together.


The oldest post in "the code vault" seems to be from August 2010. Is that when TI came out with the MSP430?


Yes. But TI came out with the MSP430 much earlier. 43oh was created when the Launchpad was released as there were alot of questions floating on the web unanswered.
The only places where you will find code for the MSP430 arch is the TI web site or here. The TI site is a very good repository of code, but strewed all across the site and do not come up in searches.

You are free to post anything interesting you find on the TI site, here.

43oh - MSP430, TivaC, ARM-Sitara and C2000 Discussion, News, Projects and Hacks

 

 


#12 RobG

RobG

    Level 5

  • Members
  • 2,999 posts
  • LocationCary, NC, US


Posted 04 July 2011 - 01:04 PM

... @Mac and bluehash, the reason for this thread in Code Vault is just that, share the code :)

The emphasis (in code vault) seems to be C and there's nothing here more than a year old. I'm looking for assembly language examples like the program listing you found which was dated February 2005. Thanks for posting, btw...

Well, here's our chance to start one :)

#13 Mac

Mac

    Level 2

  • Members
  • 245 posts
  • LocationMichigan, USA

Posted 04 July 2011 - 01:27 PM

Just found a document from 2000, MSP430 Family Mixed-Signal Microcontroller Application Reports (slaa024.pdf), which seems to have a lot of the basic stuff I'm lookin' for (including that 16-bit to 5-digit binary-to-bcd routine). Yippee!

Regards, Mike
  • hvontres and zeke like this

#14 RobG

RobG

    Level 5

  • Members
  • 2,999 posts
  • LocationCary, NC, US


Posted 04 July 2011 - 02:22 PM

Yeah, I came across that one too, it's not only code but also hardware design gold mine. Didn't have time to process that one yet, 1000+ pages of good stuff, like converters, power meters, ADC, PWM, triacs, you name it.
I think the link to that document belongs in it's own post.
I guess some things are timeless.

#15 zeke

zeke

    Level 5

  • Members
  • 1,666 posts
  • LocationCalgary, Canada

Posted 04 July 2011 - 05:42 PM

I noticed something interesting in that document.

The author keeps saying that the example circuit is for a MSP430C3xx series device.

I looked into that and discovered that their input voltage can range between 2.7 and 5.5 Volts.

Therefore, the example hardware circuits will need to change to adapt to the lower voltages of the newer devices.

"Life is 10% of what happens to me and 90% of how I react to it" - Charles R. Swindoll

Electrons -> randomelectrons.com
Photons -> ninemicron.com


#16 RobG

RobG

    Level 5

  • Members
  • 2,999 posts
  • LocationCary, NC, US


Posted 05 July 2011 - 03:46 AM

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;
}

  • timotet, xpg and oPossum like this

#17 RobG

RobG

    Level 5

  • Members
  • 2,999 posts
  • LocationCary, NC, US


Posted 07 July 2011 - 08:34 PM

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

  • bluehash and hvontres like this

#18 hvontres

hvontres

    Advanced Member

  • Members
  • PipPipPip
  • 34 posts

Posted 19 July 2011 - 04:18 AM

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;
    }

  • RobG likes this

#19 nuetron

nuetron

    Level 3

  • Members
  • 382 posts
  • LocationThe Wood Between the Worlds

Posted 19 July 2011 - 09:56 PM

Hey y'all, did you see this?

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.
I usually use IAR EW Kickstart 5.20.
Because my first laptop's motherboard failed, my second laptop's harddrive died,
and tending to our IT business, I haven't had much time to spend on microcontrollers...

#20 timotet

timotet

    Level 2

  • Members
  • 172 posts

Posted 28 July 2011 - 10:42 PM

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/... ... 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




0 user(s) are reading this topic

0 members, 0 guests, 0 anonymous users