【求助】c51的60秒计时能用中断写有问题?
字体:
小
中
大 |
打印
发表于: 2008-7-18 19:51 作者: clleady 来源: proteus仿真社区
c51的60秒2个共阳数码管计时程序,我用中断来延时,遇到麻烦,那个加1s,add a,不知道放在中断程序中还是反正不段循环的主程序中,好像都不对,放在中断中如果reti者中断产生的寄存器等信息又通过保护现场复原了。写在主程序里呢,它一直循环,寄存器一直在加1,根本不对?到底写在哪里?是不是我有那些关键点没搞清楚,谢谢高手指教。
最新回复
budhy (2008-7-18 20:00:17)
QUOTE:
还是那一句老话,把仿真图和程序传上来,让大家会更好的帮你。clleady (2008-7-18 20:16:40)
[ 本帖最后由 clleady 于 2008-7-18 21:40 编辑 ]
clleady (2008-7-18 21:40:10)
ajmp start
org 000bh ;定时器0的中断入口地址
ajmp delay
org 10H
start: mov tmod,#00000001B;
setb P2.0;
mov P1,#0xc0;
mov p0,#0xc0;
mov R6,#0;
mov r3,#0;
mov r4,#0;
mov dptr,#table;
mov th0,#0xff ;重置定时常数
mov tl0,#0xcf;
setb ea;
setb et0;
setb tr0;
loop:
nop
lcall loop;
delay:
PUSH ACC
PUSH PSW
inc R1 ;软计数器加1
mov a,R1 ;计数器值送入a
cjne a,#2,over ;未计到100则返回继续计数
mov R1,#0 ;计到100后软计数器清零(到1s)
mov a,R6
inc R6;
CJNE a,#59,next;
mov R6,0;
next:mov b,#10;
div ab;
MOV DPTR,#TABLE ;
MOVC A,@A+DPTR;
mov P0,a;
mov a,b;
mov dptr,#table;
MOVC A,@A+DPTR;
mov P1,a;
over: mov th0,#0xff ;重置定时常数
mov tl0,#0xcf
POP PSW
POP ACC
reti;
table: db 0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0xbf ;段码表
; 0 1 2 3 4 5 6 7 8 9 - 对应内容
end
我用了keil的单步循环,数值都调小了来做测试,原来问题处在,循环3次后的reti自动跳到start去了,而不是跳到delay。这是为什么呢?我还是不知道。
budhy (2008-7-18 23:58:23)
CODE:
TH EQU 0x3C ; -50000 = 0x3CB0
TL EQU 0xB0
ORG 0000H
AJMP START
ORG 000BH ;定时器0的中断入口地址
AJMP DELAY
ORG 10h
START:
MOV TMOD,#00000001b
SETB P2.0
MOV P1,#0XC0
MOV P0,#0XC0
MOV R1,#20
MOV R6,#0
MOV DPTR,#TABLE
MOV TH0,#TH ;重置定时常数
MOV TL0,#TL
SETB EA
SETB ET0
SETB TR0
LOOP:
NOP
LCALL LOOP
DELAY:
DJNZ R1,OVER
MOV R1,#20
INC R6
MOV A,R6
CJNE A,#60,NEXT
MOV R6,0
NEXT:
MOV B,#10
DIV AB
MOV DPTR,#TABLE
MOVC A,@A+DPTR
MOV P0,A
MOV A,B
MOV DPTR,#TABLE
MOVC A,@A+DPTR
MOV P1,A
OVER:
MOV TH0,#TH ;重置定时常数
MOV TL0,#TL
RETI
table:
db 0xc0, 0xf9, 0xa4, 0xb0, 0x99, 0x92, 0x82, 0xf8, 0x80, 0x90, 0xbf ;段码表
; 0 1 2 3 4 5 6 7 8 9 - 对应内容
end
hgjinwei (2008-7-19 00:26:56)
NOP
LCALL LOOP
这条指令将会导致堆栈拼命地增长, 然后所有数据都给改了!
hgjinwei (2008-7-19 00:43:52)
以下是改后代码:
org 0000h
ajmp start
org 000bh ;定时器0的中断入口地址
ajmp delay
org 10H
start: mov tmod,#00000001B;
setb P2.0;
mov P1,#0xc0;
mov p0,#0xc0;
mov R6,#0;
mov r3,#0;
mov r4,#0;
mov dptr,#table;
mov th0,#0xdc ;重置定时常数
mov tl0,#0x00;
mov TMOD,0x01;
setb ea;
setb et0;
setb tr0;
loop:
sjmp $
; nop
; lcall loop;
delay:
PUSH ACC
PUSH PSW
djnz r1,over
mov R1,#100 ;计到100后软计数器清零(到1s)
mov a,R6
inc R6;
CJNE a,#59,next;
mov R6,0;
next:mov b,#10;
div ab;
MOV DPTR,#TABLE ;
MOVC A,@A+DPTR;
mov P0,a;
mov a,b;
mov dptr,#table;
MOVC A,@A+DPTR;
mov P1,a;
over: mov th0,#0xdc ;重置定时常数
mov tl0,#0x00
POP PSW
POP ACC
reti;
table: db 0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0xbf ;段码表
; 0 1 2 3 4 5 6 7 8 9 - 对应内容
end
hgjinwei (2008-7-19 00:47:21)
clleady (2008-7-19 11:05:01)
clleady (2008-7-19 11:10:42)

这是我改后成功运行的程序,除了计时不是很精确的1s外,其他都ok。就把本来的nop改成了sjmp $,我会牢记这个教训的,花了我2天,不是高手帮忙我到现在还不知道。5.JPG
org 0000h
ajmp start
org 000bh ;定时器0的中断入口地址
ajmp delay
org 10H
start: mov tmod,#00000001B;
setb P2.0;
mov P1,#0xc0;
mov p0,#0xc0;
mov R6,#0;
mov r3,#0;
mov r4,#0;
mov dptr,#table;
mov th0,#0xff ;重置定时常数
mov tl0,#0xB0;
setb ea;
setb et0;
setb tr0;
loop:
sjmp $;
lcall loop;
delay:
PUSH ACC
PUSH PSW
inc R1 ;软计数器加1
mov a,R1 ;计数器值送入a
cjne a,#20,over ;未计到20则返回继续计数
mov R1,#0 ;计到100后软计数器清零(到1s)
mov a,R6
inc R6;
CJNE a,#59,next;
mov R6,0;
next:mov b,#10;
div ab;
MOV DPTR,#TABLE ;
MOVC A,@A+DPTR;
mov P0,a;
mov a,b;
mov dptr,#table;
MOVC A,@A+DPTR;
mov P1,a;
over: mov th0,#0x3C ;重置定时常数
mov tl0,#0xB0
POP PSW
POP ACC
reti;
table: db 0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0xbf ;段码表
; 0 1 2 3 4 5 6 7 8 9 - 对应内容
end
[ 本帖最后由 clleady 于 2008-7-19 11:12 编辑 ]
hgjinwei (2008-7-19 15:32:50)
程序问题不是出现在"NOP"上,而是出现在"LCALL"上,你将"LCALL"改成"JMP",中间随便你加多少个"NOP"(前提是在跳转范围内),都是没问题的.
"CALL"指令执行结果是*SP = PC,;SP++.
而与之对应的指令"RET"执行结果为: PC = *SP ;SP- -;
所以只有"CALL"指令而没有"RET"指令时,SP就回不断地增加(每遇上一个CALL加一次). 当SP加到内存不够时就会溢出.然后重 0x00开始继续增加.这样你的整个内存空间所存储的数据都会被替换为CALL指令执行时的PC地址.
所以你的程序不会象你想象一样执行.
77531113 (2008-7-22 22:58:44)