From Binary To BCD…And Back Again (Part 2)

In the previous post I described the algorithm for converting a binary number to binary-coded-decimal (BCD). In this post I’ll describe an algorithm for doing the reverse; converting a BCD number to binary.

The algorithm is based on repeated division and is best explained by example. Begin with a decimal number and divide by 2. The remainder becomes the high order bit in the binary number, the quotient carries forward. Repeat the process for the required number of bits. The table below shows an example for the decimal number 204.

Quotient Remainder Binary Number
204
102 0 0
51 0 00
25 1 100
12 1 1100
6 0 01100
3 0 001100
1 1 1001100
0 1 11001100

For a BCD number start at the most significant digit (MSD). Shift right to divide by two, moving the least-significant bit (LSB) into the carry. Since the remainder after dividing by 2 is the LSB, add 10 to the next significant digit if the carry is set and repeat. Limiting ourselves to number in the range from 0 – 255 (8 bits), in PIC assembly language with 8-bit registers this would look like:

; Load the registers
        movlw   d'2             ; load BCD digit 2
        movwf   DEC2_REGISTER   ;
        movlw   d'0             ; load BCD digit 1
        movwf   DEC1_REGISTER   ;
        movsw   d'4             ; load BCD digit 0
        movwf   DEC0_REGISTER   ;
        clrf    BIN_REGISTER    ; clear the binary register
        movlw   d'8             ; load the counter
        movwf   COUNTER         ;

; Perform the division
DIVIDE
DIGIT2
        bcf     status, c       ; clear the carry
        rrf     DEC2_REGISTER,1 ; rotate digit to the right, putting LSB into carry
        btfss   status, c       ; skip if there is a remainder
        goto    DIGIT1          ; jump to the next digit
        movf    DEC1_REGISTER,0 ; get the next digit
        addlw   d'10            ; add 10
        movwf   DEC1_REGISTER   ; move it back

DIGIT1
        bcf     status, c       ; clear the carry
        rrf     DEC1_REGISTER,1 ; rotate digit to the right, putting LSB into carry
        btfss   status, c       ; skip if there is a remainder
        goto    DIGIT0          ; jump to the next digit
        movwf   DEC0_REGISTER,0 ; get the next digit
        addlw   d'10            ; add 10
        movwf   DEC0_REGISTER   ; move it back

DIGIT0
        bcf     status, c       ; clear the carry
        rrf     DEC0_REGISTER,1 ; rotate the digit to the right, putting LSB into carry

; Update the counter.
BINARY
        rrf     BIN_REGISTER,1  ; rotate remainder into the binary register

        decfsz  COUNTER, 1      ; decrement the counter
        goto    DIVIDE          ; back to the top of the loop
        ...

Note that as written, this will not work with 4-bit BCD numbers because adding 10 to a digit could potentially move it outside the range of 0 – 15. However, like the Binary to BCD algorithm, there is an optimization to be performed that will allow it work with 4-digit BCD.

Instead of checking the carry flag and adding 10 before shifting the next digit, perform all the shifts up front. As mentioned previously, the remainder of division by 2 is simply the register’s least-significant bit (LSB), which, after the shift, becomes the MSB of the next digit’s register. After performing the shifts, check each register’s MSB. If it’s set there was a carry. Clear the MSB and add 5 (because we’ve already done the division via the shift, it’s 5 instead of 10). The code becomes:

; Load the registers
        movlw   d'2             ; load decimal digit 2
        movwf   DEC2_REGISTER   ;
        movlw   d'0             ; load decimal digit 1
        movwf   DEC1_REGISTER   ;
        movsw   d'4             ; load decimal digit 0
        movwf   DEC2_REGISTER   ;
        clrf    BIN_REGISTER    ; clear the binary register
        movlw   d'8             ; load the counter
        movwf   COUNTER         ;

; Perform the division
; Shift the registers
DIVIDE
        bcf     status,c        ; clear the carry
        rrf     DEC2_REGISTER,1 ; rotate digit to the right
        rrf     DEC1_REGISTER,1 ; rotate digit to the right
        rrf     DEC0_REGISTER,1 ; rotate digit to the right
        rrf     BIN_REGISTER,1  ; rotate binary number to the right

; Clear the MSB and add 5 if MSB is set.
; You don't have to check digit 2 because it will always have
; been zero shifted into its MSB.
DIGIT1
        movwf   DEC1_REGISTER,0 ; move digit to the acc
        btfss   DEC1_REGISTER,7 ; skip if MSB is set
        goto    DIGIT0          ; jump to the next digit
        andlw   h'7f            ; clear the MSB
        addlw   d'5             ; add 5
        movwf   DEC1_REGISTER   ; move the digit back
DIGIT0
        movwf   DEC0_REGISTER,0 ; move digit to the acc
        btfss   DEC0_REGISTER,7 ; skip if MSB is set
        goto    BINARY
        andlw   h'7f            ; clear the MSB
        addlw   d'5             ; add 5
        movwf   DEC0_REGISTER   ; move the digit back

; Update the counter.
BINARY
        decfsz  COUNTER, 1      ; decrement the counter
        goto    DIVIDE          ; back to the top of the loop
        ...

As written this code is for 8 bit registers. However, the algorithm is compatible with 4-bit BCD since the value in any of the 4-bit registers will always be in the range from 0 – 15.

If you think about it, this algorithm nicely complements the binary-to-BCD algorithm. For binary-to-BCD you subtract 5 before setting a register’s MSB. For this case, you clear the MSB and add 5. Makes it easy to remember too.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.

rtl-sdr.com

A blog about RTL-SDR (RTL2832) and cheap software defined radio

DuWayne's Place

Computers, Electronics, and Amateur Radio from KC3XM

QRP HomeBuilder - QRPHB -

Computers, Electronics, and Amateur Radio from KC3XM

Open Emitter

Computers, Electronics, and Amateur Radio from KC3XM

Ripples in the Ether

Emanations from Amateur Radio Station NT7S

m0xpd's 'Shack Nasties'

Computers, Electronics, and Amateur Radio from KC3XM

%d bloggers like this: