# Hex to BCD converter assembly routine

Status
Not open for further replies.

#### Haricharan

##### New Member
Friends can anybody help us with a hex to bcd converter in assembly programming for Atmega32. Biggest hex no being 03FF to be converted into decimal no 1024 say digit3,digit2,digit1 and digit0. Thanks in advance

#### Pommie

##### Well-Known Member
Google double dabble for a useful method.

Mike.
Edit, do you want BCD or a string?

#### rjenkinsgb

##### Well-Known Member
It's pretty much a repeated divide-by-ten loop, with the remainder each time being the decimal digits.

This may be of use:

#### Diver300

##### Well-Known Member
You could try this:-

Code:
    mov        #656, w1
mul.uu    w0, w1, w2    ;    this multiplies w0 with w1 and the result is w3:w2
;w3 is now the hundreds

sl        w3, #8, w4      ; store the hundreds for later

cp        w3, #0xA
bra        NZ, no_thousands
mov        #0x1000, w4            ;trap numbers >999 and make the w4 0x1000 instead of 0x0A00
no_thousands:

mov        #100, w1
mul.uu  w1, w3, w2    ;multiply by 100 so that the remainder can be calculated

sub        w0, w2, w0    ;w0 is the remainder, which is the last two digits

;if we multiply by d'6554' the msb is the number divided by 10
mov        #6554, w1
mul.uu    w0, w1, w2    ;now w3 is hex /10
sl        w3, #4, w1
mul.uu  w3, #10, w2    ;multiply by 10 so that the remainder can be calculated

sub        w0, w2, w0    ;w0 is the remainder, which is the last digit
ior        w0, w1, w0
ior        w4, w0, w4        ;combine the results

return

This is for a 16 bit Microchip microcontroller. w0 to w4 are the working registers that are used here.
The start value is in w0 and the result ends up in w4.
The multiply command puts the 32 bit result in the destination register and the one after that, so mull.uu w1, #10, w2 will put the bottom 16 bits of 10*w1 into w2, and the top 16 bits of 10*w1 into w3
It works with any input number up to 0x44A (decimal 1098)

#### Diver300

##### Well-Known Member
I followed the link in rjenkinsgb's post, and I realised that I'm using much the same ideas as RetroDan used in AVR forum.

I've also realised that the Atmega32 is only an 8 bit processor so the 16x16 multiplies in my code won't be any help.

Here is the 8-bit code that I wrote some time ago. The output is two digits in BCD, so if the input is 0x0123, which is 291, the output bytes will be 0x02 and 0x91

It runs straight through with no loops so it is fast. However it takes up much more code space than a looped version.

In this processor, there is only one working register, called w
The multiply command puts the result in prodh and prodl
The trick of multiplying and taking the most significant part of the result in order to divide only works for quite small numbers with 8x8 multiply, so it is only used right at the end in this code.
You can miss out the code before "no_2000" if the input number is less than 0x3FF

Code:
bcdconvert
;This converts hex1:hex0 to bcd. The top half of hex1 must be zero
;the result is in bcd1:bcd0
;The maximum output is 4096

clrf    bcd1

movlw    0x0f
subwf    hex1, w
bnz        comp_4000
movlw    0xa0
subwf    hex0, w
comp_4000
bnc        no_4000
sub_4000
bsf        bcd1, 6
movlw    0xa0
subwf    hex0, f
movlw    0x0f
subwfb    hex1, f

no_4000
movlw    0x07
subwf    hex1, w
bnz        comp_2000
movlw    0xd0
subwf    hex0, w
comp_2000
bnc        no_2000
sub_2000
bsf        bcd1, 5
movlw    0xd0
subwf    hex0, f
movlw    0x07
subwfb    hex1, f

no_2000
movlw    0x03
subwf    hex1, w
bnc        no_800            ;as 800 and 1000 share 3 as the first hex digit
bnz        comp_1000
movlw    0xe8
subwf    hex0, w
comp_1000
bnc        no_1000
sub_1000
bsf        bcd1, 4
movlw    0xe8
subwf    hex0, f
movlw    0x03
subwfb    hex1, f

no_1000
bcd_convert_1000
movlw    0x03
subwf    hex1, w
bnz        comp_800
movlw    0x20
subwf    hex0, w
comp_800
bnc        no_800
sub_800
bsf        bcd1, 3
movlw    0x20
subwf    hex0, f
movlw    0x03
subwfb    hex1, f

no_800
movlw    0x01
subwf    hex1, w
bnz        comp_400
movlw    0x90
subwf    hex0, w
comp_400
bnc        no_400
sub_400
bsf        bcd1, 2
movlw    0x90
subwf    hex0, f
movlw    0x01
subwfb    hex1, f

bcd_convert_400
no_400                    ;the top byte can only be 0 or 1 here
btfsc    hex1, 0
bra        sub_200
bcd_convert_256
movlw    0xc8
subwf    hex0, w
bnc        no_200
sub_200
bsf        bcd1, 1
movlw    0xc8
subwf    hex0, f
movlw    0x00
subwfb    hex1, f
bcd_convert_200
no_200                    ;the top byte can be ignored from now on
movlw    0x64
subwf    hex0, w
bnc        no_100
bsf        bcd1, 0
movlw    0x64
subwf    hex0

no_100
movf    hex0, w
bcd_convert_w
;if we multiply by d'51' and add d'52', and divide by 2, the msb is the number divided by 10
movwf    hex0
mullw    d'51'
movlw    d'52'
movlw    0x00
addwfc    prodh, f    ;this should clear the carry bit
rrcf    prodh, w    ;now w is the input/10
movwf    bcd0
mullw    d'10'
movf    prodl, w
subwf    hex0, f

swapf    bcd0, w
iorwf    hex0, w
movwf    bcd0
return

Last edited:
Status
Not open for further replies.

Replies
3
Views
3K
Replies
5
Views
7K
Replies
2
Views
2K
Replies
1
Views
2K
Replies
0
Views
2K