what is wrong with interrupt assembly program? (pic18f4520)

Discussion in 'Embedded Systems and Microcontrollers' started by thar07, Sep 28, 2015.

  1. thar07

    Thread Starter Member

    Jan 3, 2015
    71
    0
    i wrote this to turn on a Led connected to portd,0 when portb,0 it pushed but this does not work. why is that ?



     
  2. JohnInTX

    Moderator

    Jun 26, 2012
    2,347
    1,029
    If your interrupts were working, you would have a hard time seeing the LED flash since as soon as you exit the interrupt routine you are back in h: which turns it right back on.

    But your interrupts aren't working. You are confusing the interrupt enable INT0IE (INTCON,4) with the flag that says that the interrupt has occurred INToIF(INTCON,1) . You need to enable the interrupt then check INToIF in the interrupt routine and clear it when you process the interrupt.

    You really need to STOP declaring your own lower case names for SFRs that have already been defined in P18F4520.inc. Your code should use the pre-defined names only and in the correct upper case. Things like intcon,4 are confusing and won't tell you what's going on like INTCON,INT0IE will. Both of those reference the same bit but the latter (correct) one tells you what's happening and it should be apparent that you are accessing the wrong bit in INTCON from looking at the source.

    Good luck.
     
    thar07 and ErnieM like this.
  3. MaxHeadRoom

    Expert

    Jul 18, 2013
    10,555
    2,375
    The OP must be reading the Pic programming books the likes of written by David Benson, although usefull, D.B. insists on declaring in lower case the appropriate registers used in the program without the use of the .INC file.:(
    Max.
     
    JohnInTX likes this.
  4. JohnInTX

    Moderator

    Jun 26, 2012
    2,347
    1,029
    Sounds like Mr. Benson should be avoided at all costs if the price of useful programming ideas is a big bag of bad habits. Thanks for the tip.
     
  5. dannyf

    Well-Known Member

    Sep 13, 2015
    1,825
    364
    Code (Text):
    1. porta equ 0xf80 ;port and tris adress
    I would use the standard macros defined in the .inc/.h file. If you insist on using your own macros, define your macros to the standard macros.

    I would also seriously think about using assembly as the language for programming. It is much easier to code in a high level language like C.
     
  6. thar07

    Thread Starter Member

    Jan 3, 2015
    71
    0
    OK, I rewrite the program with correct sfr names but it still did not work. why is that?
    here is the new code


    Code (Text):
    1.  
    2.  
    3. #include <p18F4520.inc>
    4.     CONFIG OSC=HS , WDT=OFF , LVP=OFF , PBADEN=OFF
    5.  
    6.  
    7. porta    equ 0xf80   ;port and tris adress
    8. trisa    equ 0xf92
    9. portb    equ 0xf81
    10. trisb    equ 0xf93
    11. portc    equ 0xf82
    12. trisc    equ 0xf94
    13. trisd    equ 0xf95
    14. portd    equ 0xf83
    15. intcon  equ 0xff2
    16.  
    17. ;************************************************************
    18.    ORG 0H
    19.    GOTO MAIN
    20. ;***************************INTRRUPT
    21.    ORG 0008H
    22.    BTFSS INTCON, INT0IF        ;int0ie check
    23.    RETFIE            ;no, go to main
    24.    GOTO INT0ISR            ;yes goto into isr0
    25.  
    26. ;****************************************************MAIN PROG
    27.    ORG 00100H
    28. MAIN: BCF TRISD,0         ;output
    29.       BSF TRISB, INT0        ;into = input
    30.  
    31.       BSF INTCON, INT0IE    ;enable int0 interrupt
    32.       BSF INTCON, GIE        ;globle int enable
    33.  
    34. H:    BSF PORTD,0
    35.       NOP
    36.       NOP
    37.       NOP
    38.       NOP
    39.       BCF PORTD,0
    40.       BRA H
    41.  
    42. ;****************************************************ISR
    43. INT0ISR
    44.       ORG 200H
    45.  
    46.       BCF portd,0
    47.       BCF INTCON, INT0IF    ;clear int0 flag
    48.       RETFIE            ;return from isr
    49.  
    50.       end
    51.  
    52.  
     
    Last edited: Sep 29, 2015
  7. JohnInTX

    Moderator

    Jun 26, 2012
    2,347
    1,029
    You don't have to make EVERYTHING upper case - just use the pre-defined names in the .inc file which happen to be upper case (and MPASM is case-sensitive). So your labels, etc. can be mixed case and opcodes lower case if you prefer.

    Your problem remains the same as before. From post #2:
    . Remember that the interrupt ENABLE turns the interrupt on and off. The interrupt FLAG is set by some event and cleared by the program when that event is serviced. Your interrupt code should clear the flag by bcf INTCON,INT0IF.

    Your input won't work because you haven't initialized ADCON1. This was covered in your other thread on this here.
     
    thar07 likes this.
  8. thar07

    Thread Starter Member

    Jan 3, 2015
    71
    0
    OK, I edited the program to turn off the led when an interrupt is detected, not to on and off. The program still did not identify the interrupt.( I'm simulating this with Protues )

    when I turned off the PBADEN the program(previous thred) was detected the input from portb. Do i have to turn it on the PBADEN to get the inturrupts ?


    here is the program.

    Code (Text):
    1.  
    2.  
    3. #include <p18F4520.inc>
    4.     CONFIG OSC=HS , WDT=OFF , LVP=OFF , PBADEN=OFF
    5.  
    6.  
    7. porta    equ 0xf80   ;port and tris adress
    8. trisa    equ 0xf92
    9. portb    equ 0xf81
    10. trisb    equ 0xf93
    11. portc    equ 0xf82
    12. trisc    equ 0xf94
    13. trisd    equ 0xf95
    14. portd    equ 0xf83
    15. intcon  equ 0xff2
    16.  
    17. ;************************************************************
    18.    ORG 0H
    19.    GOTO MAIN
    20. ;***************************INTRRUPT
    21.    ORG 0008H
    22.    BTFSS INTCON, INT0IF        ;int0ie check
    23.    RETFIE            ;no, go to main
    24.    GOTO INT0ISR            ;yes goto into isr0
    25.  
    26. ;****************************************************MAIN PROG
    27.    ORG 00100H
    28. MAIN: BCF TRISD,0         ;output
    29.       BSF TRISB, INT0        ;into = input
    30.    
    31.       BSF INTCON, GIE        ;globle int enable
    32.       BSF INTCON, INT0IE    ;enable int0 interrupt
    33.    
    34.    
    35. H:    BSF PORTD,0
    36.  
    37.       BRA H
    38.  
    39. ;****************************************************ISR
    40. INT0ISR
    41.       ORG 200H
    42.    
    43.       BCF portd,0
    44.       BCF INTCON, INT0IF    ;clear int0 flag
    45.       RETFIE            ;return from isr
    46.  
    47.       end
    48.  
    49.  
    50.  
     
  9. JohnInTX

    Moderator

    Jun 26, 2012
    2,347
    1,029
    WIth PBADEN=OFF, PORTB is digital at power up so you don't need to worry about ADCON1 for PORTB.
    How do you know you are not getting the interrupt? The LED will flash faster than you can see it unless you are single stepping the code - are you?

    I might try something like this for a test. Turns on the LED once then if the interrupt happens, it turns it off, verifying the interrupt.
    Keep in mind that INT0 will interrupt on the falling edge of RB0 - change that in INTCON2 if you need to.

    Code (Microchip Assembler):
    1. #include <p18F4520.inc>
    2.     CONFIG OSC=HS , WDT=OFF , LVP=OFF , PBADEN=OFF
    3.  
    4. ;************************************************************
    5.    ORG 0H
    6.    goto Main
    7.  
    8. ;***************************INTRRUPT
    9.    ORG 0008H
    10.    btfss INTCON,INT0IF  ;INT0?
    11.    retfie                ;no, return to main
    12.  
    13.    goto INT0ISR        ;yes goto into isr0
    14. ;****************************************************MAIN PROG
    15.    ORG 00100H
    16. Main:
    17.     BCF TRISD,0         ;output
    18.     BSF TRISB, INT0        ;into = input
    19.  
    20.     BSF PORTD,0        ; just ONCE for now
    21.  
    22.     BSF INTCON, INT0IE    ;enable int0 interrupt
    23.  
    24.     bcf INTCON,INT0IF    ; clear the flag then..
    25.  
    26.     BSF INTCON, GIE        ;global int enable
    27.  
    28. H:
    29.     nop            ; let interrupt happen
    30.     nop            ; iff LED turns OFF, its working
    31.     BRA H
    32. ;****************************************************ISR
    33. INT0ISR:
    34.       ORG 200H
    35.  
    36.       BCF PORTD,0
    37.       BCF INTCON, INT0IF    ;clear int0 flag
    38.       RETFIE            ;return from isr
    39.       END
     
    thar07 likes this.
  10. thar07

    Thread Starter Member

    Jan 3, 2015
    71
    0
    When simulating in protues, step by step, the instruction which is being executing is highlighted and it did not go to ISR so that i thought it was not getting the interrupt. But I was wrong.
    Now i have a idea about how it works. Thank you very much for your help.

    By the way can we put the ISR in the Interrupt vector table's location, 0008h ? Without using 200h for that.
     
  11. JohnInTX

    Moderator

    Jun 26, 2012
    2,347
    1,029
    You're welcome. If you are using the non-priority interrupt mode (default), there is only one interrupt vector at 0008h and yes, you can put the whole routine right there. Just keep in mind that if you change to the priority mode, you'll have the second vector at 0018h and you would then have to jump around that. As it is, its OK. You also don't need to ORG the main routine at anything. Just put it after the interrupt routine and the assembler will locate it for you. Like this:
    Code (Microchip Assembler):
    1. #include <p18F4520.inc>
    2.     CONFIG OSC=HS , WDT=OFF , LVP=OFF , PBADEN=OFF
    3. ;************************************************************
    4.    ORG 0H
    5.    goto Main        ; jump past fixed location of ISR
    6. ;********************** INTERRUPT ROUTINE *****************
    7.    ORG 0008H
    8.  
    9.    btfss INTCON,INT0IF  ;INT0?
    10.    bra    IRQexit         ;no, exit the ISR at a single point
    11.  
    12.    BCF PORTD,0
    13.    BCF INTCON, INT0IF    ;clear int0 flag
    14.  
    15. IRQexit:
    16.    RETFIE                ;return from isr
    17. ; **************************MAIN PROG*******************
    18. ; This will be located right after the IRQ routine...
    19. Main:
    20.     BCF TRISD,0         ;output
    21.     BSF TRISB, INT0        ;into = input
    22.     BSF PORTD,0        ; just ONCE for now
    23.     BSF INTCON, INT0IE    ;enable int0 interrupt
    24.     bcf INTCON,INT0IF    ; clear the flag then..
    25.     BSF INTCON, GIE        ;global int enable
    26. H:
    27.     nop            ; let interrupt happen
    28.     nop            ; iff LED turns OFF, its working
    29.     bra H
    30.  
    31.     END
    Note the changes. Also note that in the ISR, everything goes to a single exit point. You don't have any context saving in the ISR which normally is required (but not here since none of the instructions change W, STATUS, BSR etc). Eventually you'll have to do that. You can use the fast return stack on the 4520 if you do this:
    Code (Microchip Assembler):
    1. ;********************** INTERRUPT ROUTINE *****************
    2.    ORG 0008H
    3.    call    fixIRQ,FAST    ; 'FAST' call to re-push W,STATUS,BSR
    4.  
    5. fixIRQ:
    6.    pop            ; pop the stack to restore to original value
    7.    btfss INTCON,INT0IF  ;INT0?
    8.    bra    IRQexit         ;no, exit the ISR at a single point
    9.  
    10.    BCF PORTD,0
    11.    BCF INTCON, INT0IF    ;clear int0 flag
    12.  
    13. IRQexit:
    14.    RETFIE FAST           ;return from isr, restore W,STATUS,BSR
    The dummy call is to ensure that W,STATUS,BSR got properly saved - its a bug in the chip - see the errata for the 4520. Note that anything else you use in the ISR will have to be saved before you use it then restored just before exiting the ISR. That's why I used the single exit point. That's where you would restore any saved context.

    Actually, you don't need interrupts to do something like making an LED follow an input but presumably you are getting your feet wet so carry on!

    EDIT: This would be a good time to point out that on an 18Fxxxx PIC, you always want to do single bit outputs (bcf/bsf) on the LATx registers, not on PORTx. This is also true for any read-modify-write operation that operates on IO. Use as ANDWF LATx,F not ANDWF PORTx,F
    For consistancy, always do inputs on PORTx, outputs to LATx.
    Microchip also recommends (as do I) that you don't use single bit operations on the TRIS registers either. Figure out what the whole 8 bits will be and do something like this for each port:

    Code (Microchip Assembler):
    1. movlw 0bxxxxxxxx
    2. movwf TRISB
     
    Last edited: Sep 29, 2015
    thar07 likes this.
  12. thar07

    Thread Starter Member

    Jan 3, 2015
    71
    0
    OK, I finally wrote the program I want. Thank very much for helping.
     
  13. dannyf

    Well-Known Member

    Sep 13, 2015
    1,825
    364
    nice. I'm sure the next person will find your post quite helpful.
     
Loading...