【求助】c51的60秒计时能用中断写有问题?


c51的60秒2个共阳数码管计时程序,我用中断来延时,遇到麻烦,那个加1s,add a,不知道放在中断程序中还是反正不段循环的主程序中,好像都不对,放在中断中如果reti者中断产生的寄存器等信息又通过保护现场复原了。写在主程序里呢,它一直循环,寄存器一直在加1,根本不对?到底写在哪里?是不是我有那些关键点没搞清楚,谢谢高手指教。

我也来说两句 查看全部回复

最新回复

  • budhy (2008-7-18 20:00:17)

    QUOTE:

    原帖由 clleady 于 2008-7-18 19:51 发表
    c51的60秒2个共阳数码管计时程序,我用中断来延时,遇到麻烦,那个加1s,add a,不知道放在中断程序中还是反正不段循环的主程序中,好像都不对,放在中断中如果reti者中断产生的寄存器等信息又通过保护现场复原了。写在主程序里呢, ...
    还是那一句老话,把仿真图和程序传上来,让大家会更好的帮你。
  • clleady (2008-7-18 20:16:40)

    我还是参考了一下其他程序,但是现在程序还是有问题。

    [ 本帖最后由 clleady 于 2008-7-18 21:40 编辑 ]
  • clleady (2008-7-18 21:40:10)

    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,#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)

    LOOP:
            NOP
            LCALL        LOOP

    这条指令将会导致堆栈拼命地增长, 然后所有数据都给改了!
  • hgjinwei (2008-7-19 00:43:52)

    动态停机只要用 SJMP $ 就行了.
    以下是改后代码:
    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)

    还有,T0 定时应尽早重装初值, 这样可以减少一些定时误差.
  • clleady (2008-7-19 11:05:01)

    谢谢您们的帮助,你们的程序我都试过了,5楼的和我的差不多哦,没反应的,谢谢六楼的大侠,原来我的问题就出在nop上面,肯能是nop把我后面的程序都删除了,深深的说声谢谢了~
  • clleady (2008-7-19 11:10:42)


    5.JPG

    这是我改后成功运行的程序,除了计时不是很精确的1s外,其他都ok。就把本来的nop改成了sjmp $,我会牢记这个教训的,花了我2天,不是高手帮忙我到现在还不知道。
    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)

    我还是参考了一下其他程序,但是现在程序还是有问题。