# what is wrong with interrupt assembly program? (pic18f4520)

#### 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.

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.

#### 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.

#### 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?

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

#### 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:

#### thar07

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

#### dannyf

Joined Sep 13, 2015
2,196
OK, I finally wrote the program I want. Thank very much for helping.
nice. I'm sure the next person will find your post quite helpful.