N字节无符号二进制 转 十进制BCD码(C调用汇编子程序)

2020-02-01 16:23发布

汇编子程序模块:NBYTE_BCD.asm
  1. ;========================================================================
  2. ; extern void NBYTEBCD(unsigned char idata *pri, unsigned char leni, unsigned char idata *pro, unsigned char leno);
  3. ;
  4. ; N字节无符号二进制  对应  十进制BCD码字节数
  5. ; (N <= 4 )  则 N+1   
  6. ; (N <= 9 )  则 N+2          
  7. ; (N <= 12) 则 N+3
  8. ; ……

  9. $NOMOD51

  10. NAME NBYTE_BCD                                                  ;模块名

  11. ?PR?_NBYTEBCD?NBYTE_BCD  SEGMENT CODE              ;在程序存储区中定义段     
  12. ?DT?_NBYTEBCD?NBYTE_BCD  SEGMENT DATA OVERLAYABLE
  13.         PUBLIC  ?_NBYTEBCD?BYTE
  14.         PUBLIC  _NBYTEBCD                                        ;用PUBLIC 声明函数为公共函数

  15.         RSEG          ?DT?_NBYTEBCD?NBYTE_BCD
  16. ?_NBYTEBCD?BYTE:
  17.             pri?040:   DS   1    ;R7
  18.            leni?041:   DS   1    ;R5
  19.             pro?042:   DS   1    ;R3
  20.            ORG 3
  21.            leno?043:   DS   1
  22.         RSEG    ?PR?_NBYTEBCD?NBYTE_BCD                ;用RSEG 表示函数可被连接器放置在任何地方

  23. ;========================================================================
  24. ;函数:N字节无符号二进制转十进制BCD码
  25. ;输入:*pri         
  26. ;输出:*pro
  27. ;资源:ACC、CY、R0、R1、R3、R4、R5、R7、leno?043
  28. ; ROM:59B(包括调用函数时的形参输入)

  29. _NBYTEBCD:
  30.         ;USING        0
  31.         MOV  A,R7
  32.         ADD  A,R5  
  33.         DEC  A     
  34.         MOV  R7,A
  35.        
  36.         MOV  A,leno?043
  37.         MOV  R4,A
  38.         ADD  A,R3
  39.         DEC  A      
  40.         MOV  R3,A

  41.         MOV  R0,A
  42. NP__0:
  43.          MOV  @R0,#0
  44.         DEC  R0
  45.         DJNZ R4,NP__0
  46.        
  47.         MOV  A,R5       ;转换(R5)字节二进制整数
  48.         RL   A
  49.         RL   A
  50.         RL   A
  51.         MOV  R1,A       ;计数器
  52.      CLR  C
  53. NP__1:       
  54.         MOV  A,R5
  55.         MOV  R4,A       ;循环(R5)次
  56.         MOV  A,R7
  57.         MOV  R0,A
  58. NP__2:
  59.          MOV  A,@R0      ;从高端移出待转换数的1位到CY中
  60.          RLC  A
  61.          MOV  @R0,A
  62.         DEC  R0
  63.         DJNZ R4,NP__2
  64.        
  65.         MOV  A,leno?043
  66.         MOV  R4,A       ;循环(leno)次
  67.         MOV  A,R3
  68.         MOV  R0,A
  69. NP__3:
  70.          MOV  A,@R0      ;BCD码带进位自身相加,相当于乘2
  71.          ADDC A,@R0
  72.          DA   A          ;十进制调整
  73.          MOV  @R0,A
  74.         DEC  R0
  75.         DJNZ R4,NP__3
  76.        
  77.          DJNZ R1,NP__1
  78.        
  79.          RET

  80.         END
复制代码使用方法,将 NBYTE_BCD.asm 添加到工程中,在 main.c 中声明后就可以调用,举例:
  1. unsigned char asc[8] = {0x0A,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA};
  2. unsigned char nz[10];

  3. extern void NBYTEBCD(unsigned char idata *pri, unsigned char leni, unsigned char idata *pro, unsigned char leno);

  4. void main(void)
  5. {
  6.         NBYTEBCD(asc, 8, nz, 10);
  7.        
  8.         while (1)
  9.         {
  10.                
  11.         }
  12. }
复制代码
友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。
该问题目前已经被作者或者管理员关闭, 无法添加新回复
16条回答
downtoearth
1楼-- · 2020-02-02 16:34
想了一会写了这程序,我还是很菜,有什么错误的地方望大家多点指导,口下流情。
  1. #include <STRING.H>
  2. uchar Data[]= {0x0A,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA};
  3. uchar BCD[]={0};
  4. uchar Four_Bit_BCD (uchar Data)
  5. {
  6. uchar Data_Temp ;
  7. switch (Data)
  8.         {
  9.                  case 0 : Data_Temp = 0x00 ; break ;
  10.                  case 1 : Data_Temp = 0x01 ; break ;
  11.                  case 2 : Data_Temp = 0x02 ; break ;
  12.                  case 3 : Data_Temp = 0x03 ; break ;
  13.                  case 4 : Data_Temp = 0x04 ; break ;
  14.                  case 5 : Data_Temp = 0x05 ; break ;
  15.                  case 6 : Data_Temp = 0x06 ; break ;
  16.                  case 7 : Data_Temp = 0x07 ; break ;
  17.                  case 8 : Data_Temp = 0x08 ; break ;
  18.                  case 9 : Data_Temp = 0x09 ; break ;
  19.                  default : break ;
  20.                 }
  21. return Data_Temp ;
  22. }

  23. void Data_Change_BCD(uchar *Data_P,uchar *BCD_P)
  24. {
  25. uchar i ;
  26. uchar Data_Temp_L,Data_Temp_H;
  27. i=strlen(Data_P);
  28. for (; i>0; i--)
  29.       {
  30.            Data_Temp_L = *Data_P  % 10 ;
  31.            Data_Temp_H = *Data_P  / 10 ;
  32.            *BCD_P = Four_Bit_BCD( Data_Temp_H )<<4+Four_Bit_BCD( Data_Temp_L );
  33.            Data_P++;
  34.            BCD_P++ ;
  35.           }
  36. }
复制代码
BXAK
2楼-- · 2020-02-02 18:12
downtoearth 发表于 2012-9-29 14:05
想了一会写了这程序,我还是很菜,有什么错误的地方望大家多点指导,口下流情。 ...

好像不对头,比如:
十六进制0xFF = 十进制255,将 十六进制0xFF 转换成 BCD 结果应该是 0x0225
十六进制0x0FFF FFFF FFFF FFFF = 十进制1,152,921,504,606,846,975,将 十六进制0x0FFF FFFF FFFF FFFF 转换成 BCD 结果应该是 0x01152921504606846975
downtoearth
3楼-- · 2020-02-02 20:50
本帖最后由 downtoearth 于 2012-9-29 14:31 编辑

BCD码不是用4位的二进制数表示1位的十进制数中的0-9吗?那么一个8位二进制数就是只可以表示0-99咯!
那为什么有0xAA的数据的。不明白,跟帖弄个究竟.理解错,我再想想!
BXAK
4楼-- · 2020-02-03 02:21
本帖最后由 BXAK 于 2012-9-29 15:28 编辑
downtoearth 发表于 2012-9-29 14:28
BCD码不是用4位的二进制数表示1位的十进制数中的0-9吗?那么一个8位二进制数就是只可以表示0-99咯!
那为什 ...


1字节(即8位)无符号二进制数:0000 0000 ~ 1111 1111         
对应 十六进制:0x00 ~ 0xFF   
对应    十进制:0 ~ 255

比如想把十六进制数以十进制显示到数码管、液晶屏……时,
如果小于等于4字节时直接用除法和求余提取就可以,如:
unsigned int n = 12345;
十万位 = n/10000;
万位 = n/1000%10;
……
但如果8字节、……的十六进制数时,上面的方法行不通(keil C51支持最大的整形数据是unsigned long,4字节),这就需要把 8字节、……的十六进制数 先转成BCD


之所以弄这个程序是因为想做等精度频率计,需要公式 fx = (fo * nx) / no,其中:
unsigned long code fo = 22118400UL;
unsigned long no,nx;
运算中为了精确没有用浮点float运算,keil C51不支持double。
(fo * nx) 的积是 8字节十六进制,
(fo * nx) / no 的商是 8字节十六进制,余数是 4字节十六进制

downtoearth
5楼-- · 2020-02-03 02:39
 精彩回答 2  元偷偷看……
downtoearth
6楼-- · 2020-02-03 02:52
本帖最后由 downtoearth 于 2012-9-29 16:04 编辑
BXAK 发表于 2012-9-29 15:20
1字节(即8位)无符号二进制数:0000 0000 ~ 1111 1111         
对应 十六进制:0x00 ~ 0xFF   
对应   ...


哦,原来是这样,好复杂呀,不过我在keil51中用过double型数据修饰符,为什么编译器没有报错的。运算正确奇怪!

一周热门 更多>