Interrupts
Interrupts are generated by an internal event such as timer overflow, or an external asynchronous
received at any time during the execution of another process. In the PC, when you hit the keyboard or move the mouse, an interrupt signal is sent to the processor from the keyboard interface to request that the key be read in, or the mouse movement transferred to the screen. The code that is executed as a result of the interrupt is called the ‘interrupt service routine’ (ISR).
When the ISR has finished its task, the process that was interrupted must be resumed as though nothing has happened. This means that any information being processed at the time of the interrupt needs be stored temporarily, so that it can be recalled later. This is known as context saving. As part of the ISR execution, the program counter is saved automatically on the stack, as when a subroutine is called, so that the program can return to the original execution point after the ISR has been completed. This system allows the CPU to get on with other tasks without having to keep checking all the possible input sources.
Interrupt Setup
A block diagram of the interrupt system in the 16F84A is shown in Figure 6.4. There are four possible interrupt sources:
• RB0 can be set up as an edge triggered interrupt input by setting INTCON,4 (INTE).
• RB7 to RB4 can be set up to trigger an interrupt if any changes state, by setting INTCON,3 (RBIE).
• TMR0 overflow interrupt can be selected by setting INTCON,5 (T0IE).
• EEPROM write operation completion can be used to trigger the interrupt.
The interrupt source must be selected in the INTCON (Interrupt Control) register. Then, the global interrupt enable (GIE) bit, which enables all interrupts, must be set (INTCON,7). The MCU will then be ready to respond to the enabled interrupt (RBIF, INTF or T0IF). When the interrupt condition is detected (e.g. TMR0 overflow), the program counter will be automatically loaded with the address 004. That means that an ISR, or a jump to it, must be located at this address. This is the same for any of the interrupts, so if more than one has been enabled, a mechanism for identifying which is active must be included in the ISR. This means checking the interrupt flags to see which is set and jumping to the appropriate ISR. There is generally an interrupt associated with each peripheral interface, so most PICs have numerous interrupt sources. For example, the 16F690 has 12.
Interrupt Execution
Interrupt execution is also illustrated in Figure 6.4. Each interrupt source has a corresponding flag, which is set if the interrupt event has occurred. For example, if the timer overflows, T0IF (INTCON,2) is set. When this happens, and the interrupt is enabled, the current instruction is completed and the next program address is saved on the stack. The program counter is then loaded with 004, and the routine found at this address is executed. Alternatively, location 004
can contain a ‘GOTO addlab’ (address label) if the ISR is to be placed elsewhere in the program memory. This is known as an interrupt vector.
If interrupts are to be used, a GOTO should be used at the reset address, 000, to redirect the program execution to the start of the main program at a higher memory address, because the ISR (or GOTO addlab) will occupy address 004. The ISR must be created and placed at address 004 (ORG 004) as part of the program source code, or, alternatively, the interrupt vector placed at this address.
Context saving may be included in the ISR; this is illustrated in the interrupt demonstration program INT1 (Program 6.2) by saving and restoring the contents of port B data register. The ISR must be terminated with the instruction RETFIE, Return From Interrupt. This causes the address following that of the instruction that was interrupted to be pulled from the stack, with program execution resuming from that point.
INT1 Interrupt Program
A demonstration program, Program 6.2, illustrates the use of interrupts. The BIN hardware must be modified to run this program, with the push buttons connected to RB0 and RA4. This is necessary because only port B pins can be used for external interrupts (Figure 6.1).
The program outputs the same binary count to port B (except RB0), as seen in the previous BINx programs, to represent its normal activity. This process is interrupted by RB0 being pulsed manually. The interrupt service routine causes all the outputs to be switched on, and then waits for the restart button to be pressed. The routine then terminates, restores the value in port B data register and returns to the main program at the original point. The program structure and sequence are illustrated by the flowcharts in Figure 6.5.
The program is in three parts: the main sequence which runs the output count, the delay subroutine which controls the speed of the output count and the interrupt service routine. The delay process in the main program is implemented as a subroutine, and expanded in a separate flowchart. The ISR must be shown as a separate chart because it can run at any time within the program sequence. In this particular program, most of the time is spent executing the software delay, so this is the process that is most likely to be interrupted. If the program included additional tasks that could be carried out concurrently with the delay, a hardware timer interrupt could be added.
The interrupt routine is placed at address 004. The instruction ‘GOTO setup’ jumps over it at run time to the initialization process at the start of the main program. The interrupt and delay routines are assembled before the main program, because they contain the subroutine start address labels referred to in the main program. The last instruction in the ISR must be RETFIE. This instruction pulls the interrupt return address from the stack, and places it back in the program counter, where it was stored at the time of the interrupt call.
To illustrate context saving, the state of the LEDs is saved in register ‘tempb’ at the beginning of the interrupt, because port B is going to be overwritten with ‘FF’ to switch on all the LEDs. Port B is then restored after the program has been restarted. Note that writing a ‘1’ to the input bit has no effect. During the ISR execution, the stack will hold both the ISR return address and the subroutine return address.
The active edge of the RB0 interrupt is, by default, the rising edge (OPTION,6 ¼ 1). When this input is operated, the interrupt only takes effect when the button is released. This eliminates the need for debouncing the switch in hardware or software. Mechanical switches often momentarily bounce open again when closed, before finally closing, and this can cause program malfunction in the real hardware which would not necessarily be apparent in simulation mode.
It is easier to test this particular application by interactive simulation using Proteus VSM (ISIS), because the interrupt is a real-time process, and the effect can be seen immediately on the output LEDs. By contrast, when tested in MPSIM, the effect of the program on the MCU registers can only be seen when the program execution is stopped. However, MPSIM provides more powerful simulation control and a complete record of the simulation. Both can provide a virtual logic analyzer to display the output changes in time. The simulation methods are shown together in Figure 6.6 for comparison. The files for both forms of simulation may be downloaded from the support website.
Multiple Interrupts
In larger PIC 16 chips, many additional interrupt sources are present, such as analogue inputs, serial ports and additional timers. These all have to be set up and controlled via additional special function registers, but there is still only one interrupt vector address, 004, to handle
them. Therefore, when an interrupt is requested, these individual interrupt bits must be checked in the software to see which is active before calling the appropriate ISR. The stack will still only hold eight return addresses, meaning that only eight levels of interrupt or subroutine are allowed. The limit of eight levels of subroutine or interrupt can easily be exceeded if the program is too highly structured (i.e. multiple subroutine levels), so this must be borne in mind when planning the program design. Higher power PIC chips have deeper stacks.