BETTER BIN-DEC CONVERSION (Peter Hemsley - Sept '00)
This binary to decimal routine is neat and fast and 24-bit but easily modified to 16 or 32-bit. Execution time is constant and so can be used where timing is critical.
I got the idea from the way some processors execute a decimal adjust instruction in hardware, so did a bit of simple arithmetic and some lateral thinking. This version is my generic one, no real need for the subroutines unless they are called from elsewhere. In the 16-bit version I expanded the two inner loops, the resulting code is hardly any bigger, executes faster, uses only one loop counter and does not use the FSR. Great for the smaller PICs.
BINDEC: CALL CLRDIG MOVLW 24 MOVWF COUNTER1 GOTO SHIFT1 ADJBCD: MOVLW DIGIT1 MOVWF FSR MOVLW 7 MOVWF COUNTER2 MOVLW 3 ADJLOOP: ADDWF INDF,F BTFSS INDF,3 SUBWF INDF,F INCF FSR,F DECFSZ COUNTER2,F GOTO ADJLOOP SHIFT1: CALL SLCNT SLDEC: MOVLW DIGIT1 MOVWF FSR MOVLW 8 MOVWF COUNTER2 SLDLOOP: RLF INDF,F BTFSC INDF,4 BSF STATUS,C BCF INDF,4 INCF FSR,F DECFSZ COUNTER2,F GOTO SLDLOOP DECFSZ COUNTER1,F GOTO ADJBCD RETURN SLCNT: RLF COUNT0,F RLF COUNT1,F RLF COUNT2,F RETURN CLRDIG: CLRF DIGIT1 CLRF DIGIT2 CLRF DIGIT3 CLRF DIGIT4 CLRF DIGIT5 CLRF DIGIT6 CLRF DIGIT7 CLRF DIGIT8 RETURN ;..........
BIN2DEC clrf DEC0 ; Clear decimal output buffer clrf DEC1 clrf DEC2 clrf DEC3 clrf DEC4 clrf DEC5 clrf DEC6 clrf DEC7 ; NB. BINn and FSR are trashed after this routine movlw 24 ; Initiate bit loop movwf BIT_COUNTER BITLOOP rlf BIN0, F ; Every iteration of this loop will copy the next rlf BIN1, F ; bit of the bin value, starting with the MSB, rlf BIN2, F ; to the carry flag movlw DEC0 movwf FSR ; Initiate DECn pointer and counter movlw 8 movwf DEC_COUNTER ; The following is executed 8 times per bit DECLOOP rlf INDF, F ; Multiply DECn by two with carry, DECn * 2 + C movlw -10 ; See note above - test for DECn > 9 addwf INDF, W ; W = DECn -10, if W = positive or zero, C = 1 btfsc STATUS, C ; DECn has overflowed (>>9) if carry is set movwf INDF ; If carry is set DECn = DECn - 10 incf FSR, F ; Carry is CARRIED over to next multiply decfsz DEC-COUNTER, F goto DECLOOP ; Multiply next DECn decfsz BIT-COUNTER, F goto BITLOOP ; Do next bit retlw 0 ; Could be RETURN on most PICs ;.............
BINDEC: CALL CLRDIG ; Clear decimal digits MOVLW 24 ; Decimal count MOVWF BINCNT BITLP: RLF BIN0,F ; Shift binary left RLF BIN1,F RLF BIN2,F MOVLW DIGIT0 MOVWF FSR MOVLW 8 ; Count for the decimal digits MOVWF DECCNT MOVLW 6 ; The Working Register holds 6 throughout. For each bit the inner loop is repeated 8 times, with shift in of the next bit, "times 2" and DecAdj of each digit ADJLP: RLF INDF,F ; 2*digit, then shift in "next bit’’ for DIGIT0 or else the carry from the previous digit ADDWF INDF,F ; Add 6, clears Cf and gives 1 in bit 4 if the BTFSS INDF,4 ; addition is needed; zero if not, when SUBWF INDF,F ; we subtract it again. Sets Cf BSF STATUS,C ; Cf could be 0 or 1, so make it 1 as default BTFSS INDF,4 ; Bit 4 is the carry to the next digit BCF STATUS,C ; Reset Cf to zero if bit 4 is clear BCF INDF,4 ; For BCD clear bit 4 in case it’s one INCF FSR,F ; Go to next digit, (Cf not affected) DECFSZ DECCNT,F ; End of inner loop. check digit count and GOTO ADJLP ; round again if it’s not zero DECFSZ BINCNT,F ; End of outer loop, one pass through digits, GOTO BITLP ; check bit count and repeat if necessary. RETURN ;..........
bin2dec: clrf dec0 clrf dec1 cIrf dec2 cIrf dec3 cIrf dec4 cIrf dec5 cirf dec6 cIrf dec7 ; movlw 18 ; deleted clrf cycles ; new movlw 08 ; new movwf octcnt ; new ctloop: ; new incf cycles ; new movlw 03 ; new movwf bitcnt bitloop: rlf bin0 rlf bin1 rlf bin3 movlw dec0 movwf FSR ; movlw 08 ; deleted movfw cycles ; new movwf deccnt decloop: rlf INDF movlw 0xF6 addwf INDF,0 btfsc STATUS,0 movwf INDF incf FSR decfsz deccnt goto decloop decfsz bitcnt goto bitloop decfsz octcnt ; new goto octloop ; new return ;............ ;From Peter Hemsley 15July01 ;Binary to decimal ;Convert 24 bit binary (count0,1,2) to decimal digits 1 to 8 ;Revised version. My thanks to all who contributed to the bin to dec ;discussion in EPE. processor 16f84 include p16f84.inc radix dec ;Ram equates count0 equ 0x0C ;lsb count1 equ 0x0D count2 equ 0x0E ;msb digit1 equ 0x11 ;lsd digit2 equ 0x12 digit3 equ 0x13 digit4 equ 0x14 digit5 equ 0x15 digit6 equ 0x16 digit7 equ 0x17 digit8 equ 0x18 ;msd bitcnt equ 0x19 digcnt equ 0x1A org 0 ;test code for MPLAB simulator movlw 0xFF movwf count2 movlw 0xFF movwf count1 movlw 0xFF movwf count0 call bin2dec brk1 return bin2dec call clrdig movlw 24 ;24 bits to do movwf bitcnt bitlp rlf count0 ;Shift msb into carry rlf count1 rlf count2 movlw digit1 movwf fsr ;Pointer to digits movlw 8 ;8 digits to do movwf digcnt adjlp rlf indf ;Shift digit 1 bit left movlw -10 addwf indf,w ;Check and adjust for decimal overflow skpnc movwf indf incf fsr ;Next digit decfsz digcnt goto adjlp decfsz bitcnt ;Next bit goto bitlp return clrdig: clrf digit1 clrf digit2 clrf digit3 clrf digit4 clrf digit5 clrf digit6 clrf digit7 clrf digit8 return end
See also:
Questions:
I modify the code of Peter Hemsley 15July01 for pic18f452. replace 'skpnc' with 'btfsc STATUS ,C'; fsr with fsr0L; indf with indf0; and other miodifications. It works only for 'digital1'( digital1 is correct). I don't know what is the problem. Could anybody can help me out?Dominic Dumont of BVL Controls Ltd replies: I tried it to, doesnt work for me either. Tried 3 Versions, none of them works...
Following is my modified codes:
;----------------------------------------------------------------------
;====================================================================
;==== 24 bit to 8 digits BCD BY Peter Hemsley ====================
;====================================================================
;---------------- initialize ------------------
; movlw 0xFF
; movwf count2
; movlw 0xFF
; movwf count1
; movlw 0xFF
; movwf count0
Peter_24bit_BCD
movlw .9
movwf count2
movlw .6
movwf count1
movlw .5
movwf count0
; call bin2dec
;;brk1 return
clrf digit1
clrf digit2
clrf digit3
clrf digit4
clrf digit5
clrf digit6
clrf digit7
clrf digit8
;bin2dec call clrdig
movlw .24 ;24 bits to do
movwf bitcnt
clrf FSR0H
;bitlp rlf count0 ;Shift msb into carry
; rlf count1
; rlf count2
bitlp rlcf count0 ;Shift msb into carry
rlcf count1
rlcf count2
movlw digit1
; movwf fsr ;Pointer to digits
movwf FSR0L ;Pointer to digits
movlw .8 ;8 digits to do
movwf digcnt
;adjlp rlf indf ;Shift digit 1 bit left
adjlp rlcf INDF0 ;Shift digit 1 bit left
;movlw -10
; addwf indf,w ;Check and adjust for decimal overflow
; skpnc
; movwf indf
movlw -d'10'
addwf INDF0,w ;Check and adjust for decimal overflow
btfsc STATUS,C,0
movwf INDF0
; incf fsr ;Next digit
; decfsz digcnt
; goto adjlp
; decfsz bitcnt ;Next bit
; goto bitlp
; return
incf FSR0L ;Next digit
decfsz digcnt
; goto adjlp
bra adjlp
decfsz bitcnt ;Next bit
; goto bitlp
bra bitlp
; return
Comments: