Software Interrupts in BASIC |
Although the most efficient method of using an interrupt is in assembler,
hardware interrupts and BASIC are poor bedfellows. By far the easiest way to
write an interrupt handler is to write it in BASIC, in combination with the
ON INTERRUPT statement. This is not the same as the compiler's original
ON_INTERRUPT statement, which initiates a
HARDWARE interrupt. ON INTERRUPT (two separate words.. ON INTERRUPT)
informs the compiler to activate its internal interrupt handling and to jump to
the BASIC interrupt handler as soon as it's capable, after receiving an
interrupt. However, there's no such thing as a free lunch, and there are some
penalties to pay for the ease of use that this method brings.
Important Note
The
compiler will highlight the hardware interrupt directive (ON_INTERRUPT)
as
BOLD RED.
While the software interrupt directive (ON INTERRUPT) will highlight
BOLD BLACK. This makes for easy debugging should the underscore be
forgotten.
When ON INTERRUPT is used, the compiler simply flags that the interrupt
has happened and immediately goes back to what it was doing before it was rudely
interrupted. Unlike a hardware interrupt, the code does not immediately jump to
the interrupt handler. And since the compiler's commands are non re-entrant,
there could be a considerable delay before the interrupt is actually handled.
For example, if the program has just started to execute a DelayMS 2000 command
when an interrupt occurs, the compiler will flag the interrupt and continue with
the delay. It could be as much as 2 seconds later before the interrupt handler
is executed. Any time critical routines dependant on the interrupt occurring
regularly will be ruined. For example, multiplexing seven segment display.
To minimise the above problem, use only statements that don't take long to
execute. For example, instead of DelayMS 2000, use DelayMS 1 in a for...next, or
repeat...until loop. This will allow the compiler to complete each command more
quickly and handle any awaiting interrupts: -
FOR
VAR1 =
0
TO
199
:
DELAYMS
1
: NEXT '
Delay for 200ms
If interrupt processing needs to occur more regularly, then there is no choice
but to use a hardware interrupt, with all it's quirks.
Exactly what happens when ON INTERRUPT is used is this: A short interrupt
handler is placed at location 4 in the PICmicro. This interrupt handler is
simply a Return. What this does is send the program back to what it was doing
before the interrupt occurred. It does not require any processor context saving.
What it doesn't do is re-enable Global Interrupts as happens when using a
RETFIE
instruction.
A Call to a short subroutine is placed before each command in the BASIC program
once an ON INTERRUPT statement is encountered. This short subroutine
checks the state of the Global Interrupt Enable bit (GIE). If it's off, an
interrupt is awaiting so it vectors to the users interrupt handler. Which is
essentially a BASIC subroutine.
If it is still set, the program continues with the next BASIC statement, after
which, the GIE bit is checked again, and so forth.
Return from Interrupt
When the RESUME statement is encountered at the end of the BASIC
interrupt handler, it sets the GIE bit to re-enable interrupts and returns to
where the program was before the interrupt occurred. DISABLE stops the
compiler from inserting the Call to the interrupt checker before each command.
This allows sections of code to execute without the possibility of being
interrupted. ENABLE allows the insertion to continue.
A DISABLE should be placed before the interrupt handler so that it will
not be restarted every time the GIE bit is checked. If it is desired to turn off
interrupts for some reason after ON INTERRUPT is encountered, you must
not turn off the GIE bit. Turning off this bit informs the compiler an interrupt
has happened and it will execute the interrupt handler forever.
Instead use: -
INTCON
=
$80
This disables all the individual interrupts but leaves the Global Interrupt
Enable bit set.
A final note about interrupts in BASIC is if the program uses the command
structure: -
Fin: GOTO Fin
You must remember the interrupt flag is checked before each instruction. It
immediately jumps to label Fin with no interrupt check. Other commands must be
placed in the loop for the interrupt check to happen: -
Fin: DELAYMS
1
GOTO Fin
Enabling an