8051 Assembly Language Timer Question (AT89S52)

Discussion in 'Embedded Systems and Microcontrollers' started by Dseng, Mar 13, 2016.

  1. Dseng

    Thread Starter New Member

    Jan 13, 2016
    20
    2
    I am having a problem with my timer interrupt routine for a project I am working on using an AT89S52. The program below should toggle the bits on ports 1 and 2 each second. It should call the timer interrupt 160 times per second and decrement R2 each time. When R2 reaches zero it should toggle the bits on ports 1 and 2. When I run the program it only calls the timer interrupt once and then gets stuck in the "HERE" loop.

    Everything in my program seems to be OK. What's wrong? Is there something in the way I'm enabling or disabling the interrupt? I don't know where to begin looking. Everything seems correct to me.

    Code (ASM):
    1.  
    2. ORG     0
    3.             JMP    RESET
    4. org    003                  
    5.                         JMP     ISERV        ;NOT USED IN THIS EXAMPLE
    6.  
    7. org 000Bh                  
    8.                        JMP    TCSERV      ;TIMER 0 INTERRUPT SERVICE ROUTINE
    9. ;        
    10. org    0030h                  
    11. ;
    12. RESET:  
    13.                        MOV       P1,#00H         ;MAKE P1 AN OUTPUT PORT
    14.                        MOV        P2,#00H        ;MAKE P2 AN OUTPUT PORT
    15.                        MOV       P3,#0FFH      ;MAKE P3 AN INPUT PORT
    16.      
    17. ;
    18. START:         MOV    R2,#160        ;INITALIZE R2 (NUMBER OF TIMES WE CALL THE TIMER INTERRUPT BEFORE TOGGLING P1 AND P2)
    19.                       MOV    A,#055H       ;INITAL PORT VALUE, HALF THE BITS OF THE PORT ARE ON, HALF ARE OFF.
    20.                       MOV IE,#00000010b  ;SETS TIMER 0 OVERFLOW INTERRUPT BUT DOESN'T ENABLE IT. (THE GATE (IE.7) IS ZERO).
    21.                       CALL    TINIT            ;INITALIZE THE TIMER
    22. HERE:           MOV    P1,A              ;OUTPUT TO PORT 1
    23.                       MOV    P2,A              ;OUTPUT TO PORT 2
    24.                       SJMP    HERE          ;KEEP DOING IT, TOGGLING THE BITS AFTER EACH 160 TIMER INTERRUPTS.
    25.  
    26.  
    27. TINIT:           MOV        TMOD, #01        ;Put Timer 0 into Mode 1, (16 bit timer)
    28.                      MOV        TL0,#0B7H        ;XTAL FREQUENCY = 3.579545MHZ. CLOCK FREQUENCY=XTAL/12=3.579545M/12=298.295K
    29.                      MOV        TH0, #0F8H       ;THE INTERUPT CALLS 160 TIMES/SEC SO IT SHOULD COUNT 298.295417K/30 = 1864 = 0748H
    30.                                                                ;SINCE THE COUNTER COUNTS UP WE WILL NEED TO SUBTRACT 26D7 FROM FFFF. 0748H-                                                                                    ;FFFFH=F8B7H
    31.                     SETB    TR0                       ;THIS SHOULD START THE TIMER
    32.                     SETB    IE.7                       ;PUTS A 1 IN THE GATE BIT OF IE AND SHOULD ENABLE TIMER 0 OVERFLOW.
    33.                     RET
    34. TCSERV: ;
    35.                    CLR        IE.7                       ;DISABLE INTERRUPTS
    36.                    CLR        TR0                      ;STOPS TIMER 0
    37.                    CLR        TF0                      ;RESETS TIMER 0 OVERFLOW FLAG
    38.                    MOV       TMOD, #01H       ;PUTS TIMER 0 INTO MODE 1 (16 bit timer)
    39.                    MOV       TL0,#0B7H          ;RELOAD THE TIMER
    40.                    MOV       TH0,#0F8H      
    41.                    DJNZ      R2,DONE            ;HAS ONE SECOND PASSED?
    42.                   MOV        R2,#160               ;IF YES THEN RESET FOR ANOTHER SECOND AND
    43.                   CPL    A                               ;TOGLE BITS ON OUTPUT PORT
    44. DONE:       SETB    IE.7                        ;TURN THE TIMER INTERRUPT BACK ON
    45.                   SETB    TR0                        ;RESTART THE TIMER
    46.                   RET                                     ;RETURN TO "HERE" LOOP
    47. ISERV:      RET                                     ;THIS DOES NOTHING
    48. END
    49.  
    Moderators note: used code tags for asm
     
    Last edited by a moderator: Mar 13, 2016
  2. Dseng

    Thread Starter New Member

    Jan 13, 2016
    20
    2
    I can't get the program to align properly. Here is a PDF file for it.

    Code (ASM):
    1.  
    2.   ORG   0
    3.    JMP   RESET
    4.  
    5.    ORG   003
    6.    JMP   ISERV     ;NOT USED IN THIS EXAMPLE
    7.    ORG 000Bh
    8.    JMP   TCSERV     ;TIMER 0 INTERRUPT SERVICE ROUTINE
    9.  
    10.    ORG   0030h
    11.  
    12. RESET:
    13.    MOV     P1,#00H     ;MAKE P1 AN OUTPUT PORT
    14.    MOV     P2,#00H     ;MAKE P2 AN OUTPUT PORT
    15.    MOV     P3,#0FFH   ;MAKE P3 AN INPUT PORT
    16.  
    17. START:
    18.    MOV     R2,#160     ;INITALIZE R2 (NUMBER OF TIMES WE CALL THE TIMER INTERRUPT BEFORE TOGGLING P1 AND P2)
    19.    MOV     A,#055H     ;INITAL PORT VALUE, HALF THE BITS OF THE PORT ARE ON, HALF ARE OFF.
    20.    MOV     IE,#00000010b ;SETS TIMER 0 OVERFLOW INTERRUPT BUT DOESN'T ENABLE IT. (THE GATE (IE.7) IS ZERO).
    21.    CALL    TINIT     ;INITALIZE THE TIMER
    22.  
    23. HERE:
    24.    MOV     P1,A     ;OUTPUT TO PORT 1
    25.    MOV     P2,A     ;OUTPUT TO PORT 2
    26.    SJMP   HERE      ;KEEP DOING IT, TOGGLING THE BITS AFTER EACH 160 TIMER INTERRUPTS.
    27. TINIT:
    28.    MOV     TMOD,#01   ;Put Timer 0 into Mode 1, (16 bit timer)
    29.    MOV     TL0,#0B7H   ;XTAL FREQUENCY = 3.579545MHZ. CLOCK FREQUENCY=XTAL/12=3.579545M/12=298.295K
    30.    MOV     TH0,#0F8H   ;THE INTERUPT CALLS 160 TIMES/SEC SO IT SHOULD COUNT 298.295417K/30 = 1864 = 0748H
    31.              ;SINCE THE COUNTER COUNTS UP WE WILL NEED TO SUBTRACT 26D7 FROM FFFF. 0748H-FFFFH=F8B7H
    32.    SETB   TR0       ;THIS SHOULD START THE TIMER
    33.    SETB    IE.7     ;PUTS A 1 IN THE GATE BIT OF IE AND SHOULD ENABLE TIMER 0 OVERFLOW.
    34.    RET
    35.  
    36. TCSERV:
    37.    CLR     IE.7     ;DISABLE INTERRUPTS
    38.    CLR     TR0       ;STOPS TIMER 0
    39.    CLR     TF0       ;RESETS TIMER 0 OVERFLOW FLAG
    40.    MOV     TMOD, #01H   ;PUTS TIMER 0 INTO MODE 1 (16 bit timer)
    41.    MOV     TL0,#0B7H   ;RELOAD THE TIMER
    42.    MOV     TH0,#0F8H
    43.    DJNZ    R2,DONE     ;HAS ONE SECOND PASSED?
    44.  
    45.    MOV     R2,#160     ;IF YES THEN RESET FOR ANOTHER SECOND AND
    46.    CPL     A       ;TOGLE BITS ON OUTPUT PORT
    47.  
    48. DONE:
    49.    SETB   IE.7     ;TURN THE TIMER INTERRUPT BACK ON
    50.    SETB  TR0       ;RESTART THE TIMER
    51.    RET           ;RETURN TO "HERE" LOOP
    52.  
    53. ISERV:  
    54.    RET           ;THIS DOES NOTHING
    55.  
    56.    END
    57.  
    Mod edit: this one's a little better. PDF's are hard to deal with. Sometmes a member will want to load the code on his machine for debugging.
     
    Last edited by a moderator: Mar 13, 2016
  3. Dseng

    Thread Starter New Member

    Jan 13, 2016
    20
    2
    I figured this out. I didn't realize that I needed a RETI instruction as opposed to a RET when returning from an interrupt. Also, I had the timer in mode 2 (8 bit auto reload) instead of mode 1 (16 bit).
     
    cmartinez and JohnInTX like this.
  4. cmartinez

    AAC Fanatic!

    Jan 17, 2007
    3,573
    2,542
    Thanks for posting your solution to your own question... I was going to dig into it until I saw your last post. Your gesture has saved the people in this forum a bit of valuable time.

    I have some experience with 8051 MCU's, so I hope I can be of help to you in the future.
    Welcome to AAC, btw.
     
  5. Dseng

    Thread Starter New Member

    Jan 13, 2016
    20
    2
    Thanks for your response. I will probably be needing more assistance in the future. I stumbled across the answer while looking at an example for a timer interrupt routine.
     
  6. ErnieM

    AAC Fanatic!

    Apr 24, 2011
    7,392
    1,605
    Yes, for assembly you need a "return from interrupt" instead of just a simple "return" instruction.

    If you are using a higher level language consult your compiler manual carefully. When I made the jump from assembly to C on one device I took the asm and wrote C to match which was a mistake because the compiler took care of some steps that needed explicit assembly steps to perform. (I believe it was reenabling the interrupt or some such.) My error lead to occasional stack overflows when a. Quick fast bunch of interrupt occurred.

    No matter... Just read understand and follow what your compiler says to do when and if you upgrade.
     
Loading...