单片机实现的多数BCD码加法器源代码_电子信息工程毕业论文范文
发布时间:
2015-03-16
来源:
人大经济论坛
单片机实现的多数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_COUNTEQU30H;中断计数器
;
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