PDA

View Full Version : Interrupt usage



Russ Kincaid
- 9th April 2008, 03:03
I am a neophyte and don't understand why my code is not working. The statement: on interrupt goto wait is said to be bad syntax but I don't believe it, something else is wrong. My program:
REM device = 12F675
CMCON = 7 ' SETS DIGITAL MODE
ANSEL = 0 ' GPIO.0 TO GPIO.3 SET AS DIGITAL
OPTION_REG = 0 ' WEAK PULLUPS ENABLED
TRISIO = %00000100 ' GPIO.2 SET AS INPUT
IOC = %00000100 ' INTERRUPT ENABLED ON GPIO.2
INTCON = %10010000 ' INTERRUPT ENABLED
N VAR BYTE ' VARIABLE N DEFINED
' ************************************************** ***********
START:
ON INTERRUPT GOTO WAIT
HIGH GPIO.0
FOR N=1 TO 13
NAP 6
NEXT N
LOW GPIO.0

WAIT:
DISABLE INTERRUPT
SLEEP
ON INTERRUPT GOTO START
ENABLE INTERRUPT 'do i need to clear the interrupt bit first?
END

mister_e
- 9th April 2008, 03:40
i see quite a few mistake here
there's no Goto Start after your LED blink
Disable INTERRUPT is not placed at the right place
you can't have more than 1 ON INTERRUPT GOTO
the first ON INTERRUPT is not a the right place
not sure about the NAP loop... to me PAUSEUS would be a better option
not sure about SLEEP in the ISR
yes you MUST clear INT flag
There's no RESUME at the end of your ISR
WAIT is a reserved word and can't be used for labels

but the rest is OK ;)

Something like bellow should work

@ __CONFIG _INTRC_OSC_NOCLKOUT & _WDT_ON & _PWRTE_ON & _MCLRE_OFF & _BODEN_ON

CMCON = 7 ' SETS DIGITAL MODE
ANSEL = 0 ' GPIO.0 TO GPIO.3 SET AS DIGITAL

OPTION_REG = 0 ' WEAK PULLUPS ENABLED
' GP2/INT on falling edge

TRISIO = %00000100 ' GPIO.2 SET AS INPUT

GPIO = 0

N VAR BYTE ' VARIABLE N DEFINED

ON INTERRUPT GOTO WAIT_int
INTCON = %10010000 ' INTERRUPT ENABLED

' ************************************************** ***********
START:
TOGGLE GPIO.0
FOR N=0 TO 250
pauseus 1000
NEXT
GOTO START

DISABLE
WAIT_INT:
TOGGLE GPIO.1
INTCON.1=0 ' Clear GP2/INT flag
RESUME
ENABLE

END

Russ Kincaid
- 9th April 2008, 15:20
Thanks for the info. Since I can't have more than one interrupt goto, I will have to re-think my program. I would like to have the program wake from sleep on interrupt. Could I use "on interruupt goto start"? I want it to end up in sleep mode, do I need a resume statement?
My program is:
Turn LED on
Wait 15 minutes
Turn LED off
Go to sleep
Optionally, I would like to turn the LED off in less than 15 minutes, using the interrupt; but that does not seem possible. I guess I will have to have two buttons: a start (interrupt) button and stop (goto sleep) button.
This program compiles OK, what do you think?


REM device = 12F675
CMCON = 7 ' SETS DIGITAL MODE
ANSEL = 0 ' GPIO.0 TO GPIO.3 SET AS DIGITAL
OPTION_REG = 0 ' WEAK PULLUPS ENABLED
TRISIO = %00001100 ' GPIO.2 AND GPIO.3 SET AS INPUT
IOC = %00000100 ' INTERRUPT ENABLED ON GPIO.2
N VAR WORD ' VARIABLE N DEFINED
ON INTERRUPT GOTO START
INTCON = %10010000 ' INTERRUPT ENABLED
' ************************************************** ***********
START:

HIGH GPIO.0
FOR N=1 TO 900
IF GPIO.3=0 THEN SLEEPNOW
PAUSE 1000
NEXT N
SLEEPNOW:
LOW GPIO.0
SLEEP 65535 ' DOES IT EVENTUALLY WAKE UP? (I DON'T WANT IT TO)

END

mister_e
- 9th April 2008, 15:24
What else the pic will need to do? There's some case you don't even need any ON INTERRUPT.

@ SLEEP will send the PIC in sleep mode untill there's a interrupt type who can wake up the PIC. It should be listed in your datasheet, somewhere at the end.

Brian J Walsh
- 20th April 2008, 00:14
My understanding is, that although there are many sources of interrupts possible within the PIC's hardware, there is only one resulting interrupt condition. Either the processor has been interrupted or it has not. This leads me to believe that this interrupt condition has to be dealt with by a single interrupt handling routine which tells the interrupted processor what to do.

The interrupt routine, or interrupt handler, in its execution could, of course, determine the source of the interrupt by investigating the various interrupt flags and take specific action appropriate to the source, but there is only one routine and the point in the program (the label) where it is located is stated in the 'ON INTERRUPT GOTO' statement. Having more than one 'ON INTERRUPT GOTO', each with a different label, doesn't make sense to me, as that would mean that the interrupted processor could go to more than one routine to resolve the interrupt. How would it know which to go to ?

The flexibility allowed by MELabs by not predetermining the label in the command just means that you can call your interrupt handler what you like. It doesn't mean that there can be more than one and that they are differentiated by having different labels.

OK.. now to the question! The 'ON INTERRUPT' statement reference on MELabs PIC BASIC Pro support website, clearly states before giving the syntax example, that "More than one ON INTERRUPT may be used in a program"... Is this a typo or have I got it completely wrong?

Brian Walsh

Darrel Taylor
- 20th April 2008, 00:58
Hi Brian,

It's NOT a typo. You can use all available interrupts simultaneously.

On any interrupt, the program flow will be directed to the single interrupt handler. Then it's up to you to determine which one fired.

Each interrupt source has 2 bit's associated with it. An Enable bit (*IE), and an Interrupt Flag (*IF). You need to look in the datasheet to find where those bit's are.

Then in the interrupt handler, check BOTH the enable bit and the interrupt flag to determine if a particular interrupt has triggered.

For example, to have the RB Port change and Timer1 interrupts, it might look something like this...


RBIE VAR INTCON.3
RBIF VAR INTCON.0
TMR1IE VAR PIE1.0
TMR1IF VAR PIR1.0
TMR1ON VAR T1CON.0

OldBits VAR BYTE
NewBits VAR BYTE


OldBits = PORTB ; End the mismatch
RBIF = 0 ; clear the flag
RBIE = 1 ; enable PORTB change interrupts

TMR1IF = 0 ; clear TMR1 interrupt flag
TMR1IE = 1 ; enable Timer1 interrupts
TMR1ON = 1 ; Start the Timer

ON INTERRUPT GOTO INTHandler

Main:
PAUSEUS 20
GOTO Main

DISABLE
INTHandler:
IF RBIE and RBIF THEN
NewBits = PORTB ; end the mismatch
RBIF = 0 ; clear the flag
; handle RB port change interrupt here
OldBits = NewBits
ENDIF

IF TMR1IE and TMR1IF THEN
TMR1IF = 0 ; clear the flag
; handle Timer1 interrupt here
ENDIF
RESUME
ENABLE

hth,

Brian J Walsh
- 20th April 2008, 01:58
Darrel,

Thanks for the prompt response. There seems to be some confusion and perhaps I did not make myself clear.

I think I understand that all enabled interrupts are available at any time to cause the processor to go to the interrupt handler.

My point was that there can only be ONE interrupt handler (the single interrupt handler referred to in your reply) and that that single interrupt handler is referenced by a unique instance of the 'ON INTERRUPT GOTO' statement within the program.

Can you provide a sample of code showing the viable use of multiple 'ON INTERRUPT GOTO' statements? Your support of MELabs documentation which states that more than one 'ON INTERRUPT' is permissable in a program suggests that you can.

My understanding is that the purpose of 'ON INTERRUPT GOTO' is to direct program execution to a unique label when an interrupt, from whatever source, occurs (or rather is detected - in the case of compiler interrupt handling) and to deal with it.

Having the possibilty of more than one 'ON INTERRUPT GOTO' in a program with the same label would be redundant and having two or more with different labels would suggest the possibilty of multiple interrupt handlers with no way of steering program execution to the right one.

So, again, as PBP only supports a single global interrupt handler, why does the documentation state that more than one compiler level interrupt re-direction statement is allowed?

The question is - can more than one 'ON INTERRUPT GOTO' exist in a PBP program in a viable way and if so how can you use them differentially?

Regards,

Brian Walsh.

Darrel Taylor
- 20th April 2008, 02:20
Oh, I see what you're saying. But it's still not a typo.

You can have multiple ON INTERRUPT statements, but it gets a little tricky.
This will be hard to explain, so give me a little time.
<br>

Darrel Taylor
- 20th April 2008, 03:25
This example should show how you can use multiple ON INTERRUPTS.
But it's not much use for anything else.

The key thing to remember here, is that the assignments of the Interrupt Handlers only happens at Compile-Time. Attempting to execute an ON INTERRUPT statement at Run-Time to change the handler will not work.

As the program gets compiled, starting from the top, the interrupts are considered DISABLED, and no interrupt checks will be placed between the PBP lines of code.

When it encounters an ON INTERRUPT statement, the status changes to ENABLED, and in between every PBP statement, it will place an Interrupt Check, that jumps to the last assigned Handler.

In the example below, if an interrupt occurs while the program flow is within the Main loop, then the Handler0 will be jumped to.

Then when it encounters the second ON INTERRUPT statement, all lines following that assignment will interrupt to Handler1.

It does not matter if they are subroutines, main routines, or whatever, ANY lines following an ON INTERRUPT will jump to the last known handler (if interrupted).

It really does get tricky, because then each handler must be capable of handling any interrupt, which leads to multiple copies of the same handler or gosubs to common handlers. Or you have to make sure that before switching modes, ONLY the interrupts that the next mode can handle are enabled, I mean SERIOUSLY Tricky!

Just remember, It all happens at Compile-Time.


Mode VAR BYTE
Mode = 0

ON INTERRUPT GOTO Handler0

Main:
R0 = R0 ; just some stuff to put int checks between
R1 = R1
IF Mode = 1 then DoMode1
IF Mode = 2 then DoMode2
GOTO Main

DISABLE
Handler0:
; Interrupt handler for the Main Loop
RESUME
ENABLE

;--------------------------------------------------------
ON INTERRUPT GOTO Handler1

DoMode1:
; Do Mode 1 tasks here

IF Mode = 0 then Main
IF Mode = 2 then DoMode2
GOTO DoMode1

DISABLE
Handler1:
; Interrupt handler for Mode 1
RESUME
ENABLE

;--------------------------------------------------------
ON INTERRUPT GOTO Handler2

DoMode2:
; Do Mode 2 tasks here

IF Mode = 0 then Main
IF Mode = 1 then DoMode1
GOTO DoMode2

DISABLE
Handler2:
; Interrupt handler for Mode 2
RESUME
ENABLE


hth,

Brian J Walsh
- 20th April 2008, 16:20
Thanks Darrel. That's quite an explanation!

Regards,

Brian Walsh.