关于HEX转BCD码的一些理解1、网上的用51汇编实现的经典方式1)首先是一个网上的经典的51汇编指令实现16bit转换的例子,具体代码如下:2)此代码的原理和分析过程如下:首先解释此段程序功能:入口参数:R6,R7,存放16位二进制数,R6为高8位。
出口参数:R3,R4,R5,存放转换后的BCD码,R3为高位。
程序思路:把16位二进制数按权展开后再进行BCD码相加。
如下图:注意此处加法是按照BCD码相加(代码中有十进制调整指令DA A)。
具体算法:把16位二进制数的每一位都先移入进位标志C,然后乘以2的n次方,这里n是该位的权值。
(此段程序是用与自身相加的方法实现乘2操作的)。
因为共有16位2进制数,所以需要进行16次循环(程序中用R2保存循环次数)。
这样最高位(即R6的最高位)最先被移出并在第一次循环中做了乘2操作并保存在R3R4R5中以供下次累加,第二次循环时该值被再次乘2并累加,以后每次循环都相当于再次进行乘2并累加,这样最高位一共进行了16次乘2累加,也就是乘以2的16次方。
同理,R6的次高位第二次被移出,所以少循环一次,相当于乘以2的15次方并累加。
举例说明:设R6=00H、R7=10H,则R7中的“1”在第12次循环时被移入C中,在以后的4次循环中实现了乘以2的4次方并进行BCD码累加,具体过程如下:R6R7=0000 0000 0001 0000。
R5=R4=R3=0第1次循环:R6最高位的0被移入C标志位后用ADDC指令与R5进行BCD码相加(如有进位则进到R4和R3中,此处无进位),R5=0第2次循环:0被移出后与R5进行BCD码相加,R5=0第3次循环:0被移出后与R5进行BCD码相加,R5=0... ...第11次循环:0被移出后与R5进行BCD码相加,R5=0第12次循环:1被移出后与R5进行BCD码相加,R5=1第13次循环:0被移出后与R5进行BCD码相加,R5=2第14次循环:0被移出后与R5进行BCD码相加,R5=4第15次循环:0被移出后与R5进行BCD码相加,R5=8第16次循环:R7最低位的0被移出后与R5进行BCD码相加,R5=16所以最终结果就是16(放在R5中)。
3)个人对这个代码的理解:a)这段代码执行效率比较高,但需要DA指令,对于某些单片机不支持DA指令需要自己编写DA指令的实现。
b)51汇编指令很多只能对寄存器A操作。
因此循环的格式是MOV A,R6;RLC A; MOV R6,A;对于能直接对其他寄存器执行循环指令的MCU修改后效率更高。
c)DA指令的实现需要辅助进位标志,若MCU无此标志位,则实现起来比较困难。
2、个人改进后的51汇编实现的方式1)基于很多单片机不带有辅助进位标志且没有DA类指令,下面是个人对这个经典算法的改进具体代码如下:DSEG AT 20H ;KEIL汇编51定义寄存器方法。
地址为20H TMP: DS 1 ;中间缓存寄存器,中间变量HEX_U: DS 1 ;HEX_U/H/L存器,3*8bit=24bit,2^24=16777216HEX_H: DS 1HEX_L: DS 1BCD4: DS 1 ;BCD4/3/2/1出口寄存器,因为入口寄存机;最大为:2^24-1=16777215BCD3: DS 1 ;共需要8位BCD码,因此需要4个寄存器用来存放压;缩BCD码BCD2: DS 1BCD1: DS 1COUNT: DS 1 ;中间变量,用来存放移位次数,本例中移位24次BSEG AT 20H ;KEIL汇编51位定义方式LL BIT 3 ;LL=20H.3=TMP.3LH BIT 7 ;LH=20H.7=TMP.7CSEG AT 0000H ;代码段定义起始位置LJMP R_MIANCSEG AT 0010HR_MIAN:HEX_TO_BCD_Init:MOV A,#24MOV COUNT,A ;循环次数24次MOV A,#0XFFMOV HEX_U,A ;HEX数据入口,此处只作赋值验证,MOV HEX_H,A ;若想写成函数在调用函数时将形参赋值即可MOV HEX_L,AMOV A,#00HMOV BCD4,A ;BCD结果初始化赋值为零MOV BCD3,AMOV BCD2,AMOV BCD1,ASHIFT_LOOP:MOV A,HEX_L ;C<---HEX_U/H/L<--RLC A ;|________________|MOV HEX_L,A ;HEX循环左移MOV A,HEX_HRLC AMOV HEX_H,AMOV A,HEX_URLC AMOV HEX_U,AMOV A,BCD1 ;C<---BCD4/3/2/1<--RLC A ;|________________|MOV BCD1,A ;BCD结果循环左移MOV A,BCD2RLC AMOV BCD2,AMOV A,BCD3RLC AMOV BCD3,AMOV A,BCD4RLC AMOV BCD4,ADEC COUNT ;移位次数减一MOV A,COUNTJNZ DA_BCD_Start ;判断是否全部移位完成SJMP $ ;运行完成停在这儿DA_BCD_Start: ;移位后调整结果为十进制BCD码;*********************************************;调整结果为十进制BCD码原理如下:;假如寄存器A,带C循环左移动相当于:B=A+A+C;我们就是要调整B为BCD码,原理详见微机原理的DAA指令;这里只是简单讲一下调整步骤:; 1、若低4位大于9或辅助标志位=1,则将B=B+0X06; 2、在步骤1基础上,若高4位大于9或进位标志=1,则将B=B+0X60 ; 3、进位C算高位;由于我们的单片机没有这个DA类指令,也没有辅助进位标志位;所以对上述原理进行了改进:B=B+0X06<===>B/2=B/2+0X03;因此我们可以再左移位之前进行:低四位加0XO3,高四位加0X30然后再移位;DAA中条件的判断可以这样做:;1、将B寄存器先加0X03,判断B.3是否为1,为1说明条件满足,否则不满足;2、在1基础B寄存器加0X30,判断B.7是否为1,为1说明条件满足,否则不满足;详细代码如下:;*********************************************DA_BCD1_Low4Bit:MOV A,BCD1 ;BCD1+0X03ADD A,#0X03MOV TMP,AJNB LL,DA_BCD1_High4BitMOV BCD1,A ;条件满足BCD0=BCD1+0X03DA_BCD1_High4Bit:MOV A,BCD1 ;BCD1+0X30ADD A,#0X30MOV TMP,AJNB LH,DA_BCD2_Low4BitMOV BCD1,A ;条件满足BCD1=BCD1+0X30DA_BCD2_Low4Bit: ;BCD2调整MOV A,BCD2ADD A,#0X03 ;此处不带进位加因为不可能产生进位,原因如下:MOV TMP,A ;高3位不可能出现111、101、110,假如上次数据是; 0101XXXX(拿这个举例),该数据会调整为1000XXXX,;;移位后本次数据高3位为000,而不是101;因此不会出现BCD1调整后C=1的情况JNB LL,DA_BCD2_High4BitMOV BCD2,ADA_BCD2_High4Bit:MOV A,BCD2ADD A,#0X30MOV TMP,AJNB LH,DA_BCD3_Low4BitMOV BCD2,ADA_BCD3_Low4Bit: ;BCD3调整MOV A,BCD3ADD A,#0X03MOV TMP,AJNB LL,DA_BCD3_High4BitMOV BCD3,ADA_BCD3_High4Bit:MOV A,BCD3ADD A,#0X30MOV TMP,AJNB LH,DA_BCD4_Low4BitMOV BCD3,ADA_BCD4_Low4Bit: ;BCD4调整MOV A,BCD4ADD A,#0X03MOV TMP,AJNB LL,DA_BCD4_High4BitMOV BCD4,ADA_BCD4_High4Bit:MOV A,BCD4ADD A,#0X30MOV TMP,AJNB LH,DA_BCD_EndMOV BCD4,ADA_BCD_End:LJMP SHIFT_LOOPEND2)该代码原理同1中的经典例子,只不过是对其的做了修改,具体不同的细节部分在代码中有详细的注释说明。
此代码已经在KEIL上验证通过,截图如下:3、关于AD指令的一些说明此指令原理同微机原理中的压缩BCD数加法调整指令DAA相同,附件为DAA指令的一些说明。
BCD数调整指令.doc。