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

发布时间:2023-01-24 09:36:27

*************************************************************************

 ;多位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是带进位减法,故在减法开始前不使用CLRC指令将进位清除,会导致类似的错误,而且更不容易发现。

 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中断子程序采用电平触发方式,如果将CLRIE0指令疏漏,会导致中断重入错误。

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、对于商业摄影师而言,哈苏HD系列可以带来一揽子解决方案,只要有钱,...

  • php学习之简单计算器实现代码

    PHP是一种HTML内嵌式的,用来制作动态网页的服务器端的脚本语言。php学习之简单计算器实现代码,需要的朋友可以参考下,希望对大家有所帮助!代码如下:<html><head><title>PHP实现简单...

  • 胶片与数码时代的作文

    时代的变迁带来的是发达的科技,许多人儿时记忆中的胶片,也默默在这个数码时代中被逐渐淘汰。时间慢慢地流逝,一幅幅照片也被埋藏在了相片册里,取而代之的是便捷的手机,可以随时查看不经意间拍下的照片,尽管科技改变了我们的生活,可永不变的是那些被定格...

  • 《源代码》的观后感

    这个周末我看了电影《源代码》,感觉颇有几分味道,所以就心血来潮写了这一篇观后感。电影《源代码》主要讲述了一位在阿富汗战场死亡以后的美国士兵醒来突然发现自己存在于一个陌生、空洞、寒冷的黑*囚笼当中。经过与外界女警官简单的交流以后,这位士兵获知...

  • 相机单反和数码的区别

    现在相机的款式越来越多,大家知道单反相机和数码相机有什么区别吗?以下是小编精心准备的相机单反和数码的区别,大家可以参考以下内容哦!单反是单镜头反光的简称,现在通常是指可更换镜头的全画幅和aps-c画幅的数码相机(以前还有胶片单反),“单”指...