单片机实现的多数BCD码加法器源代码

时间:2020-08-29 12:36:35 电子信息工程毕业论文 我要投稿

单片机实现的多数BCD码加法器源代码

*************************************************************************
 ;多位BCD码加法:BCDAN
 ;入口:字节数在R7中,被加数在[R0],加数在[R1]
 ;出口:结果在[R0]
 ;使用寄存器:A,R7,R2,R1,C,R0
 ;*************************************************************************
 BCDAN:   MOV     A,      R7
                  MOV     R2,     A
                  ADD     A,      R0
                 MOV     R0,     A
                 MOV     A,      R2
                 ADD     A,      R1
                 MOV     R1,     A
                 CLR     C    ;指令1
 BCDAN1:         DEC     R0    ;指令2
                 DEC     R1    ;指令3
                 MOV     A,      @R1
                 ADDC    A,      @R0  ;指令6
                 DA      A    ;指令4
                 MOV     @R0,    A  ;指令5
                 DJNZ    R2,     BCDAN1
                 RET
 上述子程序出错的可能发生在子程序设计过程中,也可能发生在子程序调用时。现分别讨论如下:
指令疏漏
 指令1最有可能被疏漏,此指令被疏漏的后果是该子程序的结果时对时错。错误的特征是比正确结果小1。尤其是当编写调试减法程序时,由于51单片机的减法指令只有SUBB是带进位减法,故在减法开始前不使用CLR C指令将进位清除,会导致类似的错误,而且更不容易发现。
 2.位置不妥
 指令2、3最可能出现这种错误。显然程序设计的思想是BCD码的高位在低地址单元,低位在高地址单元,从高到低依次存放。因此相加时必须从低位加起,所以作为被加数、加数的指针R0、R1必须通过程序前的一段指令调整到指向低位,调整的方法是原指针加字节数。但实际上直接加字节数后使得R0、R1指到最低字节的后面一个字节去了,故必须
首先将这1减掉,指向最低字节。从表面上看,指令2、3放在指令5后面似乎也实现了从低字节逐渐向高字节的推进作用,很多开发者一不留神就想当然的这样做了,结果前面的一层作用被疏漏掉了,导致程序错误。
 3.指令不当
 例如指令6由于疏忽写成ADD指令,则结果无法正确。
  4.非法调用
 按照子程序的说明,调用该子程序是非常容易的。但有时由于疏忽,没有按照入口要求送数出现非法调用现象,导致出错。这类错误在调试时会使得开发者一时不知错在子程序还是调用它的程序。例如,在调用前R7必须按字节数目正确置数,如果忘了此步,显然结果是无法正常的。
 
 【例二】7135A/D转换结果读取中断子程序。
 ;*************************************************************************
 ;AD转换结果读取中断程序:(/INT0)
 ;万位引起中断:  其它各位采用查询方式
 ;结果暂存在AD单元中(3字节)
 ;*************************************************************************
 ICL7135:        CLR     IE0  ;因为是电平触发,故必软件清中断标志
                 PUSH    ACC     ;保护现场
                 PUSH    02H     ;R2
                 PUSH    01H     ;R1
                 PUSH    00H
                 PUSH    DPL
                 PUSH    DPH
                 MOV     DPTR,   #I8155_PA ;读8155A口的A/D结果
                 MOVX    A,      @DPTR
                 MOV     R2,     A           ;万位入R2
                 ANL     A,      #0F0H
                 JNZ     ICL7135_0  ;POL,OV,UN各位非0,则说明结果不正常
                 SJMP    ICL7135_1
 ICL7135_0:      LJMP    PRI
 ICL7135_1:      MOV     R1,     #AD         ;结果暂存单元(始地址)
                 MOV     A,      R2
                 ANL     A,      #01H        ;存万位
                 XCHD    A,      @R1
                 MOV     A,      R2
                 ANL     A,      #00H 
                 SWAP    A
                 XCHD    A,      @R1
                 MOV     @R1,    A
 INC     R1
 WD4:            MOVX    A,      @DPTR ;读千位
                 JNB     ACC.7,  WD4
                 SWAP    A
                 MOV     @R1,    A       ;千存入
 WD3:            MOVX    A,      @DPTR   ;读百位
                 JNB     ACC.6,  WD3
                 XCHD    A,      @R1     ;百位存入
                 INC     R1
 WD2:            MOVX    A,      @DPTR   ;读十位
                 JNB     ACC.5,  WD2
                 SWAP    A
                 MOV     @R1,    A
 WD1:            MOVX    A,      @DPTR   ;读个位
                 JNB     ACC.4,  WD1
                 XCHD    A,      @R1
                 SETB    EOC_AD          ;设置转换完成标志
                 MOV     R0,     #AD_L   ;R0指向结果单元首址
                 MOV     R1,     #AD     ;转存结果缓冲区
                 MOV     R2,     #03H
 YL_0:           MOV     A,      @R1
                 MOV     @R0,    A
                 INC     R0
                 INC     R1
                 DJNZ    R2,     YL_0
                 SJMP    PRI
 PRI:            POP     DPH            ;恢复现场
                 POP     DPL
                 POP     00H
                 POP     01H
                 POP     02H
                 POP     ACC
                 RETI     ;中断返回
 引用该子程序主要想讨论以下两个问题:
中断程序的常规错误
 1)现场的.保护与恢复
 该指令通过PUSH压栈指令将程序中用到的寄存器及其它资源保护起来,然后通过出栈指令按照“先进后出”原则在中断返回前依次恢复,避免干扰或破坏其它程序的正常执行。
当然,工作寄存器的保存也可通过寄存器组切换的方式更为便捷地实现。由于中断的不可预测性,因此现场保护显得尤为重要,否则中断返回后无法正常运行被中断程序。这种错误的调试非常困难。
 2)触发方式的正确使用
  51单片机的外中断有两种触发方式:低电平触发和下跳边沿触发。为了设计正确的中断子程序,必须十分清楚地了解两种方式的差异。电平触发方式的中断标志位单片机不会自动清除,而边沿触发方式下该标志位能自动清除。上面的INT0中断子程序采用电平触发方式,如果将CLR IE0指令疏漏,会导致中断重入错误。
2.断点调试方法的应用
由于中断的不可控制特性,因此中断子程序的调试常常通过仿真器的断点功能来实现。一般分两种情形:
看是否正常触发中断
为了查看是否正常触发中断,以排查相关的软硬件系统是否存在错误,可以简单地在中断子程序的第一条指令设置断点,然后联机全速执行。如果能进入断点,则说明触发电路等基本正常,中断初始化程序也基本正常。
看结果是否正常
 也是采用断点法,将断点设置在需要查看的位置。例如设置在PRI标号位置可以查看整个结果,即AD_L开始的3单元中的内容。如果在该处无法进入中断,则说明此前程序隐含错误,断点必须逐渐前移,一旦断点能正常进入,则一般可以断定断点后的程序可能有错误。
 
 【例三】16位定时中断子序。
 ;*************************************************************************
 ;定时器中断2: 16位重装入方式
 ;*************************************************************************
 TO_COUNT  EQU  30H   ;中断计数器
 ;
 INT_T2:         CLR     EA
                 PUSH    PSW
                 PUSH    ACC   ;保护现场,A
                 PUSH    00H         ;R0
                 PUSH    01H         ;R1
                 PUSH    02H         ;R2
                 PUSH    03H         ;R3
                 PUSH    04H         ;R4
                 PUSH    06H         ;R6
                 PUSH    07H         ;R7
                 CLR     0CFH        ;清定时器溢出标志
                 INC     T0_COUNT
                 MOV     A,      T0_COUNT
                 CJNE    A,      #64H,   INT_T2_11 ;判中断100次否?
 ; CLR   T0_COUNT  (语法没错,但此处的地址被认为是位地址)
                 MOV     T0_COUNT,#00H ;清累计单元(以重新开始)
                 MOV     R7,     #02H ;YES,则2字节BCD减法(剩余时间-1)
                 MOV     R1,     #BCDJJ  ;减数为0001
                 MOV     @R1,    #00H
                 INC     R1
                 MOV     @R1,    #01H
                 MOV     R0,     #WTBF
                 MOV     R1,     #BCDJJ
                 LCALL   BCDBN           ;BCD减法
                 MOV     A,      @R0     ;判是否到0?
                 INC     R0
                 ORL     A,      @R0
                 JNZ     INT_T2_1        ;判剩余时间为0?
                 CLR     0CAH            ;关T2
                 CLR     TR0             ;YES,则关定时器T0,T1
                 CLR     TR1
                 CLR     ET0             ;禁止T0,T1溢出中断
                 CLR     ET1
                 CLR     EA              ;关总中断
                 SETB    ISOVER          ;设置工作结束标志
                 CLR     ISEND          
 INT_T2_1:       MOV     R0,     #WTBF   ;将新的剩余时间转换成显示代码送显缓
                 MOV     R1,     #DISPBUF+8
                 MOV     A,      @R0
                 MOV     B,      A       ;第一字节暂存
                 ANL     A,      #0F0H   ;取工作时间的千位
                 SWAP    A
                 MOV     @R1,    A       ;送存显缓
                 INC     R1
                 MOV     A,      B
                 ANL     A,      #0FH    ;百位
                 MOV     @R1,    A       ;送存显缓
                 INC     R0
                 INC     R1
                 MOV     A,      @R0
                 MOV     B,      A
                 ANL     A,      #0F0H   ;十位送存
                 SWAP    A
                 MOV     @R1,    A
                 INC     R1
                 MOV     A,      B
                 ANL     A,      #0FH    ;个位
                 MOV     @R1,    A
                 JB      ISOVER, INT_T2_12
 INT_T2_11:      CLR     ISOVER          ;工作还未结束
 INT_T2_12:      POP     07H             ;恢复现场
                 POP     06H
                 POP     04H
                 POP     03H
                 POP     02H
                 POP     01H
                 POP     00H
                 POP     ACC
                 POP     PSW
                 JB      ISOVER, INT_T2_13
                 SETB    EA
 INT_T2_13:      RETI

【单片机实现的多数BCD码加法器源代码】相关文章:

1.如何阅读php源代码

2.分享jquery uaMatch源代码

3.Sun软件策略放源代码

4.关于Java源代码折行的规则

5.java非对称加密的源代码(rsa)

6.双口RAM实现DSP与单片机高速数据通信的方法

7.Linux内核源代码的阅读和工具介绍

8.Sun目前的软件策略--开放源代码

9.单片机发展历史-单片机知识