Hex2BCD再讨论——由自写printf引出的另类Hex2BCD算法

2020-01-27 11:38发布

转自大虾网 http://www.daxia.com/list_1683.shtml

有一个矛盾总是在困扰我们---那就是计算机喜欢2进制(16进制)而人类已经习惯了10进制
传统的HEX--BCD通常都按二进制定义按权展开,再付以10进制调整来实现,速度太慢,效率低
我的思路是这样的2的12次方=4096=4100-4=1000H及每一个1000H可以看着"4100"如果有误
差可以从余数中扣除,如双字节数最多扣除16*4=64个,如果有余数,够扣就扣,不够扣从4100
个中次高位减一当100已经够了!如果你问16是怎么来得我告诉65536/4096=16下面是程序
DPTR中是待转换的双字节16进制数,转换的数据保存在34H33H32H31H30H五个连续单元中34H
为高,同样的道理把100=60H+4    4096/96最多商42   4*42=168  
16=4096/256 64和128因为都是单字节所以运算非常简单,经过仿真对比其运行速度比传统
方式快12倍!!!!!!!
       HEXBCD:MOV A,DPH   ;16进制高位送A
              ANL A,#0F0H  ;屏蔽A低四位
              XRL DPH,A    ;屏蔽DPH高四位
              SWAP A       ;A除以16 ( 注意这技巧)
              MOV 32H,A    ;把A个100放百位单元
              RL A  
              RL A         ;两次RL A相当于乘以4,这个4表示4A个千,也表示要扣除4A
             ;A*4096=A*(4000+100)-4A=4A*1000+A*100-4A
              XCH A,DPL
              SUBB A,DPL
              XCH A,DPH
              SUBB A,#00H  ;以上四条指令完成4A的扣除,结果高位在A,低位在DPH
              JNC   "够扣"
              DEC 32H ;不够扣32H减一当百
              MOV A,#101 ;本来是100这里用101是考虑C=1这样就节省一条指令CLR C
              SUBB A,DPL  
              ADD A,DPH  ;A肯定小于64为什么?所以高位不计算了!
              MOV B,#10
              DIV AB  
              MOV 31H,A
              MOV 30H,B
这是个简易的printf,一次只能带一个参数,printf代码在下面。
============================================================
这里是main.c
============================================================
#define _X
#include<myprintf.c> //mypr换成printf时,将此项注释掉

//mypr换成printf时,包含下面三项
//#include<regx52.h>        //mypr换成printf时,包外含这三项,将上面一项注释掉
//#include<inituart.c>
//#include<stdio.h>  
main()
{
        unsigned int k=0x1234;
        InitUart();
        while(1)               
        {         
                mypr("Hello World! K is %x",k);//定义_U时%x换成%u,用printf时用%u和%x各一次
        }                          
}
void uart(void) interrupt 4 using 0
{
}
#define _X  Program Size: data=15.0 xdata=0 code=256
#define _U  Program Size: data=27.0 xdata=0 code=716
printf ...一样
%x Program Size: data=32.1 xdata=0 code=1131
%u Program Size: data=32.1 xdata=0 code=1131

============================================================
下面是myprintf.c
============================================================
#include<regx52.h>
#ifndef     BaudRate
     #define BaudRate 57600L
#endif
#ifndef     OSC
     #define OSC      22118400L     //11.0592M
#endif
#include<inituarts.c>


#ifndef _X
     #ifndef _U
             #define _X
             #define _U
     #endif
#endif

unsigned char code hex2ascii[]={0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x41,0x42,0x43,0x44,0x45,0x46};


//putchar
void prc(unsigned char c)
{
     while(!TI)
             ;
     TI=0;
     SBUF=c;            
}

//xu=1 或2 说明包含输出%u功能
#ifdef _U                    
     void Hex2BCD(unsigned char *p,unsigned int t)
     {
             unsigned char i=0;   
             unsigned char s;
             if(t<10000) goto ca0;
             if(t>=40000) {i =4;t-=40000;}   //如果t<=9999,则这部分可不用。   
             if(t>=20000) {i+=2;t-=20000;}   
             if(t>=10000) {i++; t-=10000;}   
                  *p++=i+48;        //LCDascii               
            
             i=0;   
             ca0:
             if(t>=8000) {i =8;t-=8000;goto ca1;}   
             else
                  if(t>=4000) {i=4;t-=4000;}
                  else ;
            
             if(t>=2000) {i+=2;t-=2000;}   
             ca1:
             if(t>=1000) {i++; t-=1000;}   
             *p++=i+48;   
             i=0;   
             if(t>=800) {i =8;t-=800;goto cb1;}   
             else
                  if(t>=400) {i=4;t-=400;}   
                  else ;   
             if(t>=200) {i+=2;t-=200;}
             cb1:   
             s=(unsigned char)t;  
             if(s>=100) {i++; s-=100;}   
             *p++=i+48;   
             i=0;   
             if(s>=80) {i=8;s-=80;goto cc1;}  
             else
                  if(s>=40) {i=4;s-=40;}   
                  else ;   
             if(s>=20) {i+=2;s-=20;}  
             cc1:  
             if(s>=10) {i++; s-=10;}   
             *p++=i+48;   
             *p++=s+48;
             *p='';  
     }
#endif

//miniprintf
void mypr(unsigned char code *p,unsigned int ap)
{
     unsigned char* apbufp;
#ifdef _U
     unsigned char apbuf[6];
#endif

     for( ;(*p) != '';++p)
     {
             if(*p!='%')                                 
             {
                  prc(*p);
                  continue;
             }
             p++;

#ifdef _X
             if(*p=='x')
             {
                  
                  prc('0');
                  prc('x');
                  apbufp=(unsigned char *)(&ap);       //指向ap的高位,简化除法。(只用高位)
                  while(ap)
                  {
                          if(ap&0xf000)        //说明ap>0x1000
                               prc(hex2ascii[(unsigned char)(*apbufp>>4)]);   //提取高位,然后除8 ,如0x1234提出0x12,0x12>>4=0x01
                          else
                               prc('0');
                          ap<<=4;               //向高位移4位,0x1234变成0x2340变成0x3400变成0x4000变成0x0000
                  }
             }
             continue;
#endif

#ifdef _U
             if(*p=='u')
             {
                  Hex2BCD(apbuf,ap);                //变成BCD数组
                  apbufp=apbuf;
                  while(*apbufp)
                  {     
                          prc(*apbufp);
                          apbufp++;
                  }
             }
#endif            
             continue;
     }                            
}
友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。
该问题目前已经被作者或者管理员关闭, 无法添加新回复
22条回答
shamork
1楼-- · 2020-01-28 06:45
 精彩回答 2  元偷偷看……
shamork
2楼-- · 2020-01-28 08:26
5楼的思路不是问题,关键是如何整理出来,让我们这些习惯了C的人们能够方便的用上。
cowboy
3楼-- · 2020-01-28 13:36
经过仿真对比其运行速度比传统方式快12倍!!!!!!!  
===============================================
快12倍表示有多快?能在100us内完成吗?(以标准12T的51运行于12MHz来算)
shamork
4楼-- · 2020-01-28 17:18
新思路:人类算法 51适用
万位 千位 百位 十位 个位
              2   5   6
+         2   5   6
------------------------------
             12    30     36
+      10    25    30
  4    10    12
------------------------------
  4    20    49    60     36
+                 3  <-36->6
------------------------------
  4    20    49    63     6
+            6<-63->3
------------------------------  
  4    20    55     3     6
+       5<-55->5
------------------------------
  4    25     5     3     6  
+ 2<-25->5
------------------------------
  6     5     5     3     6  

----------------------------------------------------------------------------
我不会汇编,所以只能写个类汇编出来了。等高手来改写优化。这个用在12MHz S51上,123周期(仅计算,没测)
WW EQU 30H;万位
QW EQU 31H;千位
BW EQU 32H;百位
SW EQU 33H;十位
GW EQU 34H;个位

MOV DPH,#FFH
MOV DPL,#FFH

;将DPH(ff)变成2.5.6
MOV A ,DPH
MOV B ,#100
DIV AB
MOV R0,A
MOV A,B;余数放A继续/10
MOV B,#10
DIV AB
MOV R1,A
MOV R2,B
;将DPL(ff)变成2.5.6
MOV A,DPL
MOV B,#100
DIV AB
MOV R3,A
MOV A,B
MOV B,#10
DIV AB
MOV R4,A
MOV R5,B

;开乘了256*6--6*6
MOV A,R5
MOV B,R2
MUL AB
MOV GW,A
;5*6
MOV A,R5
MOV B,R1;
MUL AB
MOV SW,A
;2*6
MOV A,R5
MOV B,R0
MUL AB
MOV BW,A
;256*5--6*5
MOV A,R4
MOV B,R2
MUL AB
ADD SW,A
;5*5
MOV A,R4
MOV B,R1
MUL AB
ADD BW,A
;2*5
MOV A,R4
MOV B,R0
MUL AB
MOV QW,A
;256*2---6*2
MOV A,R3
MOV B,R2
MUL AB
ADD BW,A
;5*2
MOV A,R3
MOV B,R1
MUL AB
ADD QW,A
;2*2
MOV A,R3
MOV B,R0
MUL AB
MOV WW,A
;开始合并--36/10=3(+QW) 余6(GW)
MOV A,GW
MOV B,#10
DIV AB
ADD SW,A
MOV GW,B
;sw
MOV A,SW
MOV B,#10
DIV AB
ADD BW,A
MOV SW,B
;bw
MOV A,BW
MOV B,#10
DIV AB
ADD QW,A
MOV BW,B
;qw ww
MOV A,QW
MOV B,#10
DIV AB
ADD WW,A
MOV QW,B
cowboy
5楼-- · 2020-01-28 19:17
思路错了。0xabcd != 0xab * 0xcd
shamork
6楼-- · 2020-01-28 19:56
 精彩回答 2  元偷偷看……

一周热门 更多>