假若A是16位的二进制数字,转换的数学表达式如下:
A = 2^15+2^14+.....2^1+2^0
在转换的时候,待转换的数是16位(两字节),环路计数器是16次,最大的结果因有65535,所以至少要用2.5字节存结果,取整之后就是3个字节做结果储存。
转换要领如下:结果字节首先清零,
然后待转换字节与结果字节同时向左移,移出待转换字节的最高位,逢1结果翻一翻,见0结果原封不动,环路计数器减1,重复以上过程,直到环路计数器减到零。
注:在逢1结果翻一翻中还是加6修正,51中是有直接指令DA,但精简指令内核的MCU
都没有这条指令,因此处理上就完全不同,可以参考以下代码。看看是用了哪些技巧代替了DA指令。
-----对于单片机汇编算法的初学者,该如何把转换两字节改成转换多字节?-----
以下附上来自AVR stduio 自带的bin2 to BCD 例程。
;****************************************
;* "bin2BCD16" - 16-bit Binary to BCD conversion
;*
;* This subroutine converts a 16-bit number (fbinH:fbinL) to a 5-digit
;* packed BCD number represented by 3 bytes (tBCD2:tBCD1:tBCD0).
;* MSD of the 5-digit number is placed in the lowermost nibble of tBCD2.
;*
;* Number of words :25
;* Number of cycles :751/768 (Min/Max)
;* Low registers used :3 (tBCD0,tBCD1,tBCD2)
;* High registers used :4(fbinL,fbinH,cnt16a,tmp16a)
;* Pointers used :Z
;*
;***************************************************************************
;***** Subroutine Register Variables
.equ AtBCD0 =13 ;address of tBCD0
.equ AtBCD2 =15 ;address of tBCD1
.def tBCD0 =r13 ;BCD value digits 1 and 0
.def tBCD1 =r14 ;BCD value digits 3 and 2
.def tBCD2 =r15 ;BCD value digit 4
.def fbinL =r16 ;binary value Low byte
.def fbinH =r17 ;binary value High byte
.def cnt16a =r18 ;loop counter
.def tmp16a =r19 ;temporary value
;***** Code
bin2BCD16:
ldi cnt16a,16 ;Init loop counter
clr tBCD2 ;clear result (3 bytes)
clr tBCD1
clr tBCD0
clr ZH ;clear ZH (not needed for AT90Sxx0x)
bBCDx_1:lsl fbinL ;shift input value
rol fbinH ;through all bytes
rol tBCD0 ;
rol tBCD1
rol tBCD2
dec cnt16a ;decrement loop counter
brne bBCDx_2 ;if counter not zero
ret ; return
bBCDx_2: ldi r30, AtBCD2+1 ;Z points to result MSB + 1
bBCDx_3:
ld tmp16a,-Z ;get (Z) with pre-decrement
;----------------------------------------------------------------
;For AT90Sxx0x, substitute the above line with:
;
; dec ZL
; ld tmp16a,Z
;
;----------------------------------------------------------------
subi tmp16a,-$03 ;add 0x03
sbrc tmp16a,3 ;if bit 3 not clear
st Z,tmp16a ; store back
ld tmp16a,Z ;get (Z)
subi tmp16a,-$30 ;add 0x30
sbrc tmp16a,7 ;if bit 7 not clear
st Z,tmp16a ; store back
cpi ZL,AtBCD0 ;done all three?
brne bBCDx_3 ;loop again if not
rjmp bBCDx_1 |