what is wrong with interrupt assembly program? (pic18f4520)

Thread Starter

thar07

Joined Jan 3, 2015
71
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 ?



#include <p18F4520.inc>
CONFIG OSC=HS , WDT=OFF , LVP=OFF , PBADEN=OFF


porta equ 0xf80 ;port and tris adress
trisa equ 0xf92
portb equ 0xf81
trisb equ 0xf93
portc equ 0xf82
trisc equ 0xf94
trisd equ 0xf95
portd equ 0xf83
intcon equ 0xff2

;************************************************************
org 0h
goto main
;***************************INTRRUPT
org 0008h
btfss intcon,4 ;int0ie check
retfie ;no, go to main
goto int0isr ;yes goto into isr0

;****************************************************MAIN PROG
org 00100h
main: bcf trisd,0 ;output
bsf trisb,0 ;into = input

bsf intcon,4 ;enable int0 interrupt
bsf intcon,7 ;globle int enable

h: bsf portd,0
bra h

;****************************************************ISR
int0isr:
org 200h

bcf portd,0
bcf intcon,4 ;clear int0 flag
retfie ;return from isr

end
 

JohnInTX

Joined Jun 26, 2012
3,799
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.
 

MaxHeadRoom

Joined Jul 18, 2013
19,008
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

Joined Jun 26, 2012
3,799
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.
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.
 

dannyf

Joined Sep 13, 2015
2,196
Code:
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.
 

Thread Starter

thar07

Joined Jan 3, 2015
71
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.
OK, I rewrite the program with correct sfr names but it still did not work. why is that?
here is the new code


Code:
#include <p18F4520.inc>
    CONFIG OSC=HS , WDT=OFF , LVP=OFF , PBADEN=OFF


porta    equ 0xf80   ;port and tris adress
trisa    equ 0xf92
portb    equ 0xf81
trisb    equ 0xf93
portc    equ 0xf82
trisc    equ 0xf94
trisd    equ 0xf95
portd    equ 0xf83
intcon  equ 0xff2

;************************************************************
   ORG 0H
   GOTO MAIN
;***************************INTRRUPT
   ORG 0008H
   BTFSS INTCON, INT0IF        ;int0ie check
   RETFIE            ;no, go to main
   GOTO INT0ISR            ;yes goto into isr0

;****************************************************MAIN PROG
   ORG 00100H
MAIN: BCF TRISD,0         ;output
      BSF TRISB, INT0        ;into = input
  
      BSF INTCON, INT0IE    ;enable int0 interrupt
      BSF INTCON, GIE        ;globle int enable
  
H:    BSF PORTD,0
      NOP
      NOP
      NOP
      NOP
      BCF PORTD,0
      BRA H

;****************************************************ISR
INT0ISR
      ORG 200H
  
      BCF portd,0
      BCF INTCON, INT0IF    ;clear int0 flag
      RETFIE            ;return from isr

      end
 
Last edited:

JohnInTX

Joined Jun 26, 2012
3,799
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:
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.
. 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.
 

Thread Starter

thar07

Joined Jan 3, 2015
71
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:
#include <p18F4520.inc>
    CONFIG OSC=HS , WDT=OFF , LVP=OFF , PBADEN=OFF
 
 
porta    equ 0xf80   ;port and tris adress
trisa    equ 0xf92
portb    equ 0xf81
trisb    equ 0xf93
portc    equ 0xf82
trisc    equ 0xf94
trisd    equ 0xf95
portd    equ 0xf83
intcon  equ 0xff2

;************************************************************ 
   ORG 0H
   GOTO MAIN
;***************************INTRRUPT
   ORG 0008H
   BTFSS INTCON, INT0IF        ;int0ie check
   RETFIE            ;no, go to main
   GOTO INT0ISR            ;yes goto into isr0

;****************************************************MAIN PROG
   ORG 00100H
MAIN: BCF TRISD,0         ;output
      BSF TRISB, INT0        ;into = input
   
      BSF INTCON, GIE        ;globle int enable
      BSF INTCON, INT0IE    ;enable int0 interrupt
   
   
H:    BSF PORTD,0
  
      BRA H

;****************************************************ISR
INT0ISR
      ORG 200H
   
      BCF portd,0
      BCF INTCON, INT0IF    ;clear int0 flag
      RETFIE            ;return from isr

      end
 

JohnInTX

Joined Jun 26, 2012
3,799
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:
#include <p18F4520.inc>
    CONFIG OSC=HS , WDT=OFF , LVP=OFF , PBADEN=OFF

;************************************************************
   ORG 0H
   goto Main

;***************************INTRRUPT
   ORG 0008H
   btfss INTCON,INT0IF  ;INT0?
   retfie                ;no, return to main

   goto INT0ISR        ;yes goto into isr0
;****************************************************MAIN PROG
   ORG 00100H
Main:
    BCF TRISD,0         ;output
    BSF TRISB, INT0        ;into = input
 
    BSF PORTD,0        ; just ONCE for now

    BSF INTCON, INT0IE    ;enable int0 interrupt

    bcf INTCON,INT0IF    ; clear the flag then..

    BSF INTCON, GIE        ;global int enable
 
H:
    nop            ; let interrupt happen
    nop            ; iff LED turns OFF, its working
    BRA H
;****************************************************ISR
INT0ISR:
      ORG 200H
 
      BCF PORTD,0
      BCF INTCON, INT0IF    ;clear int0 flag
      RETFIE            ;return from isr
      END
 

Thread Starter

thar07

Joined Jan 3, 2015
71
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.
 

JohnInTX

Joined Jun 26, 2012
3,799
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.
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:
#include <p18F4520.inc>
    CONFIG OSC=HS , WDT=OFF , LVP=OFF , PBADEN=OFF
;************************************************************
   ORG 0H
   goto Main        ; jump past fixed location of ISR
;********************** INTERRUPT ROUTINE *****************
   ORG 0008H

   btfss INTCON,INT0IF  ;INT0?
   bra    IRQexit         ;no, exit the ISR at a single point

   BCF PORTD,0
   BCF INTCON, INT0IF    ;clear int0 flag

IRQexit:
   RETFIE                ;return from isr
; **************************MAIN PROG*******************
; This will be located right after the IRQ routine...
Main:
    BCF TRISD,0         ;output
    BSF TRISB, INT0        ;into = input
    BSF PORTD,0        ; just ONCE for now
    BSF INTCON, INT0IE    ;enable int0 interrupt
    bcf INTCON,INT0IF    ; clear the flag then..
    BSF INTCON, GIE        ;global int enable
H:
    nop            ; let interrupt happen
    nop            ; iff LED turns OFF, its working
    bra H

    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:
;********************** INTERRUPT ROUTINE *****************
   ORG 0008H
   call    fixIRQ,FAST    ; 'FAST' call to re-push W,STATUS,BSR

fixIRQ:
   pop            ; pop the stack to restore to original value
   btfss INTCON,INT0IF  ;INT0?
   bra    IRQexit         ;no, exit the ISR at a single point

   BCF PORTD,0
   BCF INTCON, INT0IF    ;clear int0 flag

IRQexit:
   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:
movlw 0bxxxxxxxx
movwf TRISB
 
Last edited:
Top