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
;..........
+
DECIMAL CHALLENGE (Steve Teal - Nov '00)
Peter Hemsley’s excellent solution to the age-old and often messy problem of converting binary information into human perceivable decimal inspired me to develop my own solution.
A multiply by two with carry is performed on each digit, nested inside a bit counter, each bit determining the state of the carry for the first multiply. This routine takes 1,957 instruction cycles to execute which is a slight improvement on Peter’s, which uses 3,086. Both routines maintain a constant execution time. It will be just as easy to change the number of bits converted.
The commands "movlw -10, addwf INDF, W"’ are for the PICs that lack any subtract instructions, the 16c5x for example, "movlw 10, subwf INDF, W’’ works just the same.
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
;.............
+
BCD CHALLENGE ACCEPTED (Harry West - Dec '00)
I was very intrigued by the Binary to BCD conversion routine given in Sept '00, as I had always seen this done by some method involving division by ten.
After a lot of thought, I managed to come up with what I think is an improved version. The procedure used to do the conversion is: "Start with a Partial Result (PR) of zero. For each bit in the binary, starting at the left hand end, multiply the PR by two and add the bit."
By doing this arithmetic in decimal, the PR at the end has the converted value which holds the digits as binary coded decimal (BCD) in the lower four bits of each of a succession of bytes, bits 4 to 7 are zeroes (Unpacked BCD). You could also, with a different program, use Packed BCD with two digits in a byte, one in each nibble.
Throughout the process, decimal adjustment (DecAdj) of the PR is necessary to maintain its BCD nature, so that 0 to 9 are unchanged but a result in the range 10 to 15, which is stored as hex 0A to 0F, is converted to 0 to 5 with a 1 carry ready to go in the next BCD, i.e. 0A to 0F become 10 to 15 hex.
The actual process is to add six to the unadjusted result. If this causes a 1 in the fifth bit (bit 4) then the changed pattern is used, otherwise the original unadjusted pattern is retained. For Unpacked BCD the state of bit 4 can be used as the test.
The algorithm in Sept '00 uses "Add 3" before the "times 2" shift. This is best when Packed BCD is converted since for the "top" nibble there is no bit corresponding to bit 4. By "Adding 3" before the shift instead of "Add 6" after, the same effect is obtained using bit 7. However, in this case the carry into the decimal cannot be done until after the shift, hence the two passes through the digits for each bit.
The following is a version using one pass, for Unpacked BCD. I have used the locations BIN0 to BIN2 to hold the three bytes of binary, with the most significant (m.s.) byte in BIN2. The PR goes in the eight bytes DIGIT0 to DIGIT7, with the m.s. digit in DIGIT7. BINCNT and DECCNT hold counts for the two nested loops.
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 ;..........+
SHORTER BCD CONVERSION (Michael McLoughlin - April '01)
I have modified Steve Teal’s code, which required 1957 cycles, so that it completes in 1242 cycles!
Steve’s code doubles his Travelling Total (TT), but this only grows slowly and initially only one digit is needed to handle it. Yet the subroutine always doubles the whole of TT, so almost half the RLF multiplications do 2 × 0 + 0 = 0, and are superfluous. By studying the worst case (all 24 bits = 1) it soon appears that we only need to involve a new decimal digit for every three binary digits. The 08 in Steve’s listing could be called cycles, to start at 01 and increment after every three bits. Another counter (octcnt) ensures the repetition of that whole procedure just eight times.
In the following listing the commands to delete are shown "remmed out" with a semicolon, and the new lines are notated as such.
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:
| file: /techref/microchip/math/radix/b2bu-24b9d-xx.htm, 15KB, , updated: 2007/3/15 09:35, local time: 2008/8/28 11:24,
owner: JMN-EFP-786,
38.103.63.61:LOG IN
|
| ©2008 These pages are served without commercial sponsorship. (No popup ads, etc...).Bandwidth abuse increases hosting cost forcing sponsorship or shutdown. This server aggressively defends against automated copying for any reason including offline viewing, duplication, etc... Please respect this requirement and DO NOT RIP THIS SITE. Questions? Please DO link to this page! Digg it! <A HREF="http://piclist.com/techref/microchip/math/radix/b2bu-24b9d-xx.htm"> 24bit to BCD unpacked 8 digits (several versions) in as little as 25 inst or as few as 1242 cycles by Peter Hemsley, Steve Teal, Harry West, and Michael McLoughlin</A> |
| Did you find what you needed? |
|
o List host: MIT, Site host massmind.org, Top posters @20080828 Apptech, Jinx, Xiaofan Chen, olin piclist, Alan B. Pearce, Vitaliy, William \Chops\ Westfield, Tamas Rudnai, Cedric Chang, David VanHorn, * Page Editors: James Newton, David Cary, and YOU! * Roman Black of Black Robotics donates from sales of Linistep stepper controller kits. * Ashley Roll of Digital Nemesis donates from sales of RCL-1 RS232 to TTL converters. * Monthly Subscribers: Shultz Electronics, Timothy Weber, on-going support is MOST appreciated! * Contributors: Richard Seriani, Sr. |
|
.