Welcome to our site!

Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

  • Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

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
Most Helpful Member
Google double dabble for a useful method.

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

Diver300

Well-Known Member
Most Helpful 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
Most Helpful 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'
    addwf    prodl, f       
    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.

Latest threads

EE World Online Articles

Loading
Top