PDA

View Full Version : Interrupts Revisited



Rob Martin
- 4th August 2005, 18:14
Hi All
I'm away on holiday programming by torch light in the middle of a forest (seriously) and only have web access via a mobile phone. I've tried finding my answers in the archieves but with no joy so forgive me for asking a question which has probably been asked elsewhere.


I'm using a 16f877 20MHz with all the RB ports held high using external resisitors.
I have a tri coloured LED connected to RC0 & RC1 and Ground.

My problem is the Interrupt routine below works fine and turns the LED on and off.However when the interrupt occurs I need to call another routine. As soon as I add any other command into the routine it appears to permanently call the routine! and screws everything else up although the LED's still work OK.

I happy that the RB pins are not changing state so why is my interrupt routine running! am I not clearing a flag somewhere?
or am I missing something very obvious?
I've made sure I have no other references to the RB pins in my code and the ISR can not be executed by the code running into it as it is at the end of my code.
if I remove the "ON INTERRUPt" line the rest of my code functions normally and the LEDs stop working.

Rob
(desperate of Hampshire)


'Interrupts stuff********************************************* *
TRISB = %11111111 ' Set PORTB to all input
INTCON.3 = 1 ' Enable the RB port change interrupt
OPTION_REG = $7f ' Enable PORTB pull-ups
'TRISC = %00000011 ' Set PORTB.0-2 (LEDs) to output, 3-7 to input

sw1 VAR PORTB.6
sw2 VAR PORTB.4
'SW3 VAR PORTB.7
' Define the pins that are connected to LEDs
led1 VAR PORTC.0
led2 VAR PORTC.1
ON INTERRUPT GOTO ISR




****BIG SNIP************
RETURN
DISABLE
:ISR

IF sw1 = 1 Then
high LED1

else
low led1
endif

IF sw2 = 1 Then
HIGH led2
else
low led2
endif

IF sw3 = 1 Then
HIGH led1
HIGH led2
else
low led1
low led2
endif

TempwData var WORD
Tempwdata = wData 'stores the current wdata pointer

************HERE the problem happens********************
if (sw1 = 1) then
wData = 7*256 + 0 : GOSUB Send
wData = $1F00 + $62 : GOSUB Send
else
wData = 7*256 + 0 : GOSUB Send
wData = $1000 + $0b : GOSUB Send 'b
endif
wdata = TempWData 'Restores the original wdata pointer

INTCON.1 = 0 ' Clear interrupt flag xxxxx
resume
ENABLE

mister_e
- 4th August 2005, 20:12
i'm not 100% sure but close to be. Please someone shoot me if i'm not correct.

You can't use a gosub in a ISR
You can't use var definition elsewhere than at the begining... There's no local variable in PBP.
:ISR should be ISR:


without checking in the datasheet, this is the firsts thing that spring to mind.

Bruce
- 4th August 2005, 21:03
If you jump to or call a sub-routine outside the ISR DISABLE / RESUME, ENABLE block, PBP will shoot you straight back to the beginning of your ISR once the 1st BASIC instruction outside this protected area completes execution.

yettie
- 5th August 2005, 01:22
rob,

i think he had the same problem in using the ON INTERRUPT method. maybe you would want to consider the ASM interrupts. Its a lot more easier than microcode interrupt. just for an idea.

DEFINE INTHAND IntHandler
...(define your variables)

;-------------
Initialize:
TRISB = $FF
INTCON = %11001000 ;(enable portb change interrupt)
OPTION_REG = $7F ;(pulls ups enable)
... (then your main routines)

;------------------
@_IntHandler ;Interrupt Service Routine
INTCON.3 = 0 ; disable portb change interrupt while in this routine
;(reset all necessary variables and call your extra routines)
INTCON.3 = 1 ; reenable portb change interrupt
@retfie


Well I hope this one will give you some ideas. ON INTERRUPT is hard to implement with so much latency compared asm interrupt. As another advatage, you saved some words since ON INTERRUPTS have so many overheads inserted per each of your line since it polls interrupt flags. ok?

regards,
Paul

yettie
- 5th August 2005, 01:44
in addition to this, save all your status, W and other registers if necessary when the program is interrupted. just reload it later. in your case i don't think you will to save your last state when interrupted, or just correct me if im wrong.

regards,
yettie

Rob Martin
- 5th August 2005, 10:53
The routine I call outside of the ISR has DISABLE & ENABLE either side of it.
It was my understanding that I can call this other routine and that it will complete the routine then jump back to the ISR.

This part appears to work fine. My problem is/was that even when an interrupt hasn't occured my code inside the ISR seems to the execute?
(it seems to execute the "ELSE" statments)

Can someone confirm I have the correct flags bits set and clear for the "on change" interrupt.

Lastly having local VARS, I have compiled like this before and never had a problem. Does the compiler just pick the VAR out at compilation time regardless of where they are?
Again with the ON INTERRUPT call does this need to be anywhere specific? it seems to my no difference where I put it.

Rob

Bruce
- 5th August 2005, 15:48
Try adding this to the end of your ISR before returning;

Dummy = PORTB ' read port into Dummy var to end missmatch condition
INTCON.0 = 0 ' clear RB interrupt flag bit

Clearing INTCON.1 clears RB0/INT External Interrupt Flag bit. Not RB interrupt on change.

Rob Martin
- 5th August 2005, 18:31
Bruce

Let me take one step back.
Here is the code I used originally to test my PCB
You said I was clearing the RB0 flag which I agree with but unless I clear this the program doesn't work!!
If I use the INTCON.0 = 0 the code doesn't work but using INTCON.1=0 makes the program work.
I'm very confused and going round in circles as what I would expect to work doesn't. Do I need to enable the Global interrupt GIE INTCON.7=1 before exiting the ISR?

I've reread the 16f877 data sheet and what I'm doing shouldn't work, but it does.

Rob



***************************************

DEFINE LOADER_USED 1 'Boot Loader
'Define inputs held low by external resistors
sw1 VAR PORTB.6
sw2 VAR PORTB.4
SW3 VAR PORTB.0
' Define the pins that are connected to LEDs
led1 VAR PORTC.0
led2 VAR PORTC.1

INTCON.3 = 1 ' Enable the RB port change interrupt
OPTION_REG = $7f ' Enable PORTB pull-ups
TRISC = %00000011 ' Set PORTB.0-2 (LEDs) to output, 3-7 to input
on interrupt goto ISR

main: ' main program begins here


' Check any button pressed to toggle on LED


NAP 7 ' Go to sleep. When the watchdog is
' disabled, NAP won't wake up until
' an interrupt occurs.

GoTo main ' Do it again upon waking
DISABLE
:ISR
IF sw1 = 1 Then
high LED1
else
low led1
endif

IF sw2 = 1 Then
HIGH led2
else
low led2
endif

IF sw3 = 1 Then
HIGH led1
HIGH led2
else
low led1
low led2
endif
'***HERE*************
'INTCON.0 = 0 ' Clear the RB port change flag bit( this doesn't)
INTCON.1 = 0 ' Clear interrupt flag (this works)

RESUME
ENABLE

Bruce
- 5th August 2005, 19:38
INTCON.3 = 1 turns ON RB Port Change Interrupt Enable bit. This means any change on RB7, 6, 5 or 4 will generate the interrupt.

There are a few things to watch out for when using this.

1. Set the upper 4-bits up as inputs. TRISB = %11110000 (assumes only top 4 are used as inputs) change as required. And make sure these inputs are not floating by using internal or external pull-ups - or external pull-downs depending on your switch open/close logic.

2. Do a "read" of the port before turning ON RB int change. Dummy = PORTB.
Just take a snap-shot of portb inputs before turning the option on.

3. INTCON.3 = 1 Now any change from the last value read on RB7,6,5 or 4 will cause the interrupt flag bit INTCON.0 to be set (RBIF: RB Port Change Interrupt Flag bit)

Now, before exiting your ISR, you need to read portb again, then clear the flag bit associated with RB int change.

Dummy = portb ' end missmatch
INTCON.0 = 0 ' clear interrupt flag bit before re-enabling interrupts
RESUME
ENABLE

Some other things to consider.

You're testing upper portb pins in your ISR. This actually reads the port, and will end the missmatch, BUT, your program is going to run much faster than than anyone can operate a push-button switch, and you will have switch bounce.

What can happen is you enable RB int on change, someone releases the switch, and you have the interrupt "missmatch" condition all over again.

You might want to include some code that recognizes the keypress, and then waits for the user to release the key before reading the port, and re-enabling the interrupt on change. You can turn ON the LED immediately, but wait for the key to be released before reading the port & re-enabling int on change.

Also, you're turning ON internal pull-ups, and you're testing input pins for logic 1 with IF SW1 = 1 THEN do something.

What logic level does a switch press apply to your switch inputs?

Do I need to enable the Global interrupt GIE INTCON.7=1 before exiting the ISR?
Definitely not. Exiting the interrupt with RESUME, ENABLE handles everything for you. Using ON INTERRUPT you never need to mess with GIE unless you want to totally disable interrupts. In that case write INTCON = $80 like shown in your manual.

crematory
- 5th August 2005, 21:25
Hello

Good answer bruce, really good one :)

Any way, to solve your problem, here is what you have to do, as it worked for me:

1. Read portb.
2. Clear the GIE and portb on change IE bit.
3. Pause for, say 100 to 150 ms, to ensure that the user has releasd the button.
4. Do what you want to do. Use the first value you read for portb.
5. Now set RB on change IE bit.
6. Then read portb again, to clear any "may be" pending interrupts, don't try to read portb before enabling RB IE bit, as this is certainly will not be sufficent.
7. Resume will enable GIE bit.

I wish I had that code, I formatted the C partition, and forgot to move some files, that was one of them :(

Bruce
- 5th August 2005, 22:02
Download AN552 (Implementing Wake-up on Key Stroke) from Microchip, and ye will see the light....;o}

Rob Martin
- 6th August 2005, 16:44
The inputs are from brake, left and right indicators etc. so the inputs can be very short pulses if someone touches the brake for a fraction of a second hence why I was using the on change interrupts to catch all the inputs.
The inputs are all held low by resistors (not high as i put before).

I'll try the answer that bruce & Co have offered and see if i can find the answer to my problems.

Thanks for the support guys it's kept me sane :)


Rob

crematory
- 6th August 2005, 18:57
Hello Rob

Its recommended to have the port pins pulled up, as this will save you long hours of code debuging to find out why your PIC is seeing a brake pushed, while its not indeed.


Regards