Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Microcontroller Programming. Thi Micro Chip PIC (Julio Sanchez, 2007).pdf
Скачиваний:
475
Добавлен:
12.08.2013
Размер:
4.99 Mб
Скачать

Interrupts

217

Multiple External Interrupts

One of the practical applications of the port-B line-change interrupt is in handling several different interrupt sources; for example, a circuit containing four push-button switches that activate four different circuit responses. If the switches are wired to the corresponding pins in Port-B (RB4 to RB7) and the line-change interrupt is enabled, the interrupt takes place when any one of the four switches changes level, that is, when any one of the interrupt lines go from high to low or from low to high. The interrupt handler software can easily determine which of the switches changed state and if the change took place on the signal’s rising or falling edge. The corresponding software routines then handle each case.

Later in this chapter we develop a sample program that uses the Port-B line-change interrupt to respond to action on four pushbutton switches.

11.1.4 EEPROM Data Write Interrupt

The origin of this interrupt relates to the relative slowness of the EEPROM data write operation, which is of 10 ms. The interrupt serves no other function than to allow the microcontroller to continue execution while the data write operation is in progress. The interrupt service routine informs the microcontroller when writing has ended through the EEIF bit located in the EECON1 register. The use of this interrupt is considered in Chapter 15, in the context of EEPROM data memory access and programming.

11.2 Interrupt Handlers

The interrupt handler, also called the interrupt service routine or the ISR, is the code that receives control upon occurrence of the interrupt. Most of the programming that goes into the service routine is specific to the application; however, there are certain housekeeping operations that should be included. The following list describes the structure of an interrupt service routine for the mid-range PICs:

1.Preserve the value in the w register.

2.Preserve the value of the STATUS register.

3.Execute the application-specific operations.

4.Restore the value of the STATUS register at the time of the interrupt.

5.Restore the value of the w register at the time of the interrupt.

6.Issue the RETFIE instruction to end the interrupt handler.

In the PIC 16F84, the interrupt service routine must be located at offset 0x004 in code memory. A simple org directive takes care of ensuring this location, as in the following code fragment:

org

0x000

; Beginning of code area

goto

start

;

Jump to program start

org

0x004

;

Start of Service routine

.

 

.

; SERVICE ROUTINE GOES HERE

.

 

218

 

Chapter 11

retfie

;

End of ISR

start:

;

Program starts here

Alternatively, code can place a jump at offset 0x004 and locate the Service Routine elsewhere in the code. In this case, it is important to remember not to call the Service Routine, but to access it with a goto instruction. The reason is that the call opcode places a return address in the stack, which then polls for the retfie instruction.

11.2.1 Context Saving Operations

The only value automatically preserved by the interrupt mechanism is PC (the Program Counter), which is stored in the stack. Applications often need to restore the processor to the same state as when the interrupt took place, so the first operation of most interrupt handlers is saving the processor’s context. This usually includes the w and the STATUS registers and occasionally others used by the specific implementation.

Saving w and STATUS Registers

Saving the w and the STATUS registers requires using register variables, but the process requires special care. Saving the w register is simple enough: its value at the start of the Service Routine is stored in a local variable from which it is restored at termination. But saving the STATUS register cannot be done with the MOVF instruction, since this instruction changes the zero flag. The solution is to use the SWAPF instruction which does not affect any of the flags. Of course, SWAPF inverts the nibbles in the operand, so it must be repeated so as to restore the original state. The following code fragment assumes that file register variables named old_w and old_status were previously created.

save_cntx:

 

 

 

movwf

old_w

;

Save w register

swapf

STATUS,w ; STATUS to w

movwf

old_status

;

Save STATUS

;

; Interrupt handler operations go here

;

 

swapf

old_status,w ; Saved status to w

movfw

STATUS ; To STATUS register

;At this point all operations that change the

;STATUS register must be avoided, but swapf does not.

swapf

old_w,f

;

Swap file register in itself

swapf

old_w,w

;

reswap back to w

retfie

 

 

 

11.3 Interrupt Programming

In the sections that follow, we discuss programming interrupts that originate in Port-B, line 0, and those that originate in changes of port-B lines RB4 to RB7. Interrupts that relate to the Timer0 overflow or to EEPROM data write operations are cov-

Interrupts

219

ered in the chapter on Serial Communications and the one on EEPROM Data Operations, respectively.

11.3.1 Programming the External Interrupt

Port-B, line 0, is referred to as the External Interrupt source. The name is not the most adequate since other interrupts can also have external sources. One of the important uses of this interrupt source is to wake the processor from the SLEEP mode. This allows developing applications that can run on a small power source (such as batteries) since the program uses almost no power until some action associated with the interrupt source wakes up the PIC. A sample program using the RB0 interrupt is developed later in this chapter. Our first sample program is a simple demonstration of the installation and action of the interrupt. The program is based on the circuit in Figure 11-4.

 

 

 

 

 

 

 

2x470 Ohms

 

4 MHz

 

 

 

 

 

 

 

 

 

Osc

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

green

red

 

 

 

 

+5 V

 

 

 

 

 

18

17

16

15

14

13

12

11

10

 

RA1 RA0 OSC1 OSC2 Vdd RB7 RB6 RB5 RB4

16F84

RA2 RA3 T0Tkl MCLR Vss RB0/INT RB1 RB2 RB3

 

 

 

 

 

 

 

 

 

 

1

2

3

4

5

6

7

8

9

 

+5 V

10K Ohms

4.7K Ohms

+5 V

Figure 11-4 Circuit for RB0 Interrupt Demonstration

In the circuit of Figure 11-4, a pushbutton switch is wired to the RB0 port. It is this switch which produces the interrupt when pressed. A red LED is wired to port RB1 and a green LED to port RB2. The main program flashes the green LED on and off at a rate of approximately one-half second. The red LED is toggled on and off when the pushbutton switch is pressed. The switch contains a 4.7K Ohm resistor that keeps the port high until the contact is made and sent to ground. This makes the

220

Chapter 11

switch active low and the interrupt is programmed on the falling edge of the signal, which takes place when the contact is made.

RB0 Interrupt Initialization

In order to initialize the RB0 interrupt, the following operations must take place:

1.Port-B, line 0, must be initialized for input.

2.The interrupt source must be set to take place either on the falling or the rising edge of the signal.

3.The external interrupt flag (INTF in the INTCON Register) must be initially cleared.

4.Global interrupts must be enabled by setting the GIE bit in the INTCON Register.

5.The External Interrupt on RB0 must be enabled by setting the INTE bit in the INTCON Register.

The following code fragment, from the program RB0Int in the book’s online software package, performs these operations:

;============================= ; interrupt handler ;=============================

org 0x04 goto IntServ

;=============================

;main program ;============================= main:

;Set up interrupt on falling edge

;by clearing OPTION register bit 6 movlw b’10111111’

option

movlw

b’11111111’

; Set Port-A

for input

tris

porta

; (not necessary for this program)

movlw

b’00000001’

; Port-B bit

0 is input

tris

portb

; all others

are output

clrf

portb

; All Port-B

to 0

; Initially turn on LED

 

 

bsf

portb,0

; Set line 0

bit

;============================

 

;setup interrupts ;============================

;Clear external interrupt flag (intf = bit 1)

bcf

INTCON,intf

; Clear flag

;Enable global interrupts (gie = bit 7)

;Enable RB0 interrupt (inte = bit 4)

 

bsf

INTCON,gie

;

Enable

global int (bit

7)

 

bsf

INTCON,inte

;

Enable

RB0 int (bit 4)

 

;============================

 

 

 

 

;

flash LED

 

 

 

 

Interrupts

221

;============================

; Program flashes LED wired to Port-B, line 2 lights:

movlw

b’00000010’

; Mask with bit 1 set

xorwf

portb,f

; Complement bit 1

call

long_delay

; Local delay routine

call

long_delay

 

call

long_delay

 

goto

lights

 

RB0 Interrupt Service Routine

The Service Routine for the RB0 interrupt depends on the specific application. Nevertheless, the following processing steps should be considered:

1.Determine if the source is an RB0 interrupt.

2.Clear the RB0 interrupt flag (INTF bit) in the INTCON Register.

3.Save the context. Which registers and variables need to be saved depends on the specific application.

4.Perform the interrupt action.

5.Restore the context.

6.Return from the interrupt with the retfie instruction.

In addition, the interrupt handler may have to perform operations that are specific to the application. For example, debounce a switch or initialize local variables. The following Interrupt Service routine is from the program RB0Int in the book’s online software:

;=======================================================

;

Interrupt Service Routine

;=======================================================

;Service routine receives control when there is

;action on pushbutton switch wired to port-B, line 0 IntServ:

;First test if source is an RB0 interrupt

btfss

INTCON,INTF

; INTF flag

is RB0 interrupt

goto

notRB0

; Go if not

RB0 origin

; Save context

 

 

 

movwf

old_w

; Save w register

swapf

STATUS,w

; STATUS to

w

movwf

old_status

; Save STATUS

;=========================

;interrupt action ;=========================

;Debounce switch

;Logic:

;Debounce algorithm consists in waiting until the

;same level is repeated on a number of samplings of the

222

Chapter 11

;switch. At this point the RB0 line is clear since the

;interrupt takes place on the falling edge. The routine

;waits until the low value is read several times.

movlw

D’10’

;

Number of repetitions

movwf

count2

;

To counter

wait:

;Check to see that port-B bit 0 is still 0

;If not, wait until it changes

btfsc

portb,0

;

Is

bit set?

goto

exitISR

;

Go

if

bit not 0

; At this point RB0 bit is clear

 

decfsz

count2,f ;

Count

this iteration

goto

wait

 

 

 

; Continue if not zero

;Interrupt action consists of toggling bit 2 of

;port-B to turn LED on and off

movlw

b’00000100’; Xoring with a 1-bit produces

 

;

the complement

 

xorwf

portb,f ;

Complement bit

2, port-B

;=========================

;exit ISR ;========================= exitISR:

;Restore context

swapf

old_status,w

; Saved status to w

movfw

STATUS

; To STATUS register

swapf

old_w,f

; Swap file register in itself

swapf

old_w,w

; re-swap back to w

notRB0:

 

 

 

; Reset interrupt

 

 

 

bcf

INTCON,intf

; Clear INTCON bit 1

retfie

 

 

 

Note that the interrupt handler listed previously contains a debouncing routine that cleans the switch’s signal. In this particular implementation the detection of a signal of the wrong value determines that the interrupt is aborted. For the particular switch used in the test circuit this approach seemed to work better. Alternatively, the routine can be designed so that if a wrong edge is detected, execution continues in the wait loop. In any case, the entire complication of software debouncing can be avoided by debouncing the switch in hardware.

11.3.2 Wakeup from SLEEP Using the RB0 Interrupt

The PIC microcontroller sleep mode provides a useful mechanism for saving power. It is particularly useful in battery-operated devices.

The sleep mode is activated by executing the SLEEP instruction; it suspends all normal operations and switches of the clock oscillator.

Interrupts

223

The sleep mode is suitable for applications that are not required to run continuously. For example, a device that records temperature at daybreak can be designed so that a light-sensitive switch generates an interrupt that turns the device on each morning. Once the data is recorded, the device goes into the sleep mode until the next daybreak.

Several events can make the device wake up from the sleep mode:

1.A device reset on the !MCLR pin

2.Watchdog timer wake-up signal, if WDT is enabled

3.Interrupt on RB0 line

4.Port change interrupt on RB4 to RB7 lines

5.EEPROM write complete interrupt

In the sleep mode, the device is placed on a power-down state that generates the lowest power consumption. The system clock is turned off in the sleep mode so signals that depend on the clock cannot be used to terminate the sleep. If enabled, the Watchdog Timer is cleared by the sleep instruction but keeps running. The PD bit in the STATUS register is also cleared and the TO bit is set. The ports maintain the status they had before the SLEEP instruction was executed.

The TO and PD bits in the STATUS register can be used to determine the cause of wake-up, since the TO bit is cleared if a Watchdog Timer wake-up took place. The corresponding interrupt enable bit must be set for the device to wake-up up due to an interrupt. Wake-up takes place regardless of the state of the General Interrupt Enable (GIE) bit. If the bit is clear, the device continues execution at the instruction following SLEEP. Otherwise, the device executes the instruction after the SLEEP instruction and then branches to the interrupt address. If the execution of the instruction following SLEEP is undesirable, the program should contain a NOP instruction after the SLEEP instruction.

The SleepDemo Program

The program named SleepDemo in the book’s online software package is a trivial demonstration of using the RB0 interrupt to wake the processor from sleep mode. The program can be tested using the circuit in Figure 11-4. SleepDemo flashes the green LED at ½ second intervals during 20 iterations and then goes into sleep mode. Pressing the pushbutton switch on line RB0 generates an interrupt that wakes the processor from sleep mode. The following code fragment shows the coding of the main loop in the program:

;============================

;flash LED 20 times ;============================ wakeUp:

;Program flashes LED wired to port-B, line 2

;20 times before entering the sleep state

movlw

D’20’

;

Number of iterations

movwf

count2

;

To counter

224

 

Chapter 11

lights:

 

 

movlw

b’00000010’; Mask with bit 1 set

xorwf

portb,f

; Complement bit 1

call

long_delay

call

long_delay

call

long_delay

decfsz

count2

; Decrement counter

goto

lights

 

; 20 iterations have taken place

clrwdt

 

; Clear WDT

sleep

 

 

nop

 

; Recommended!

goto

wakeUp

; Resume execution

In the SleepDemo program the Interrupt Service Routine does nothing. Its coding is as follows:

;=======================================================

;Interrupt Service Routine ;=======================================================

;The interrupt service routine performs no operation IntServ:

bcf

INTCON,INTF

; Clear flag

retfie

The initialization of the RB0 interrupt is identical to the one in the RB0Int program previously listed.

11.3.3 Port-B Bits 4-7 Status Change Interrupt

In the PIC 16F84 microcontroller, a change of input signal on Port-B, lines 4 to 7, generates an interrupt. This interrupt sets the RBIF bit in the INTCON Register to indicate that at least one of the ports have changed value. The port change takes place when the port’s previous value changes from logic one to logic zero or vice versa. In order for port pins to recognize this interrupt, they must have been defined as input. If any one of the port pins (4 to 7) is defined as output the interrupt takes place. The status change of the ports is in reference to the last time port-B was read.

The principal application of this interrupt source is in detecting several different interrupt sources. Its principal disadvantage is that it forces the declaration of four port-B lines as input, although during processing not all lines need be recognized as interrupt sources. The conclusion is that applications that only need a single external interrupt source should use the RB0 interrupt described in previous sections. Only applications that require more than one external interrupt should use the Port-B lines 4 to 7 interrupt on change source.

Interrupts

225

Since the interrupt takes place on any status change (high-to-low or low-to-high) the service routine executes on both signal edges. If interrupt processing is required on only one edge, that is, either when the port goes high or low, then the filtering must be performed in software. The circuit in Figure 11-5 allows testing the Port-B Status Change Interrupt.

+5 V

+5 V

4 MHz

 

 

 

 

 

 

 

 

 

4.7K Ohm

 

 

 

 

 

 

 

 

 

 

 

4.7K Ohm

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Osc

 

 

 

 

 

 

 

 

 

 

 

 

+5 V

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

16

 

15

 

14

 

 

 

 

 

 

 

 

 

 

 

10

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

17

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

18

 

 

 

 

 

13

 

12

 

11

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

RA1

RA0

OSC1 OSC2

Vdd

 

RB7

 

RB6

 

RB5

RB4

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

green

 

 

 

 

 

 

 

16F84

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

red

 

 

 

 

RA2

 

 

T0Tkl

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

RA3

MCLR Vss

RB0/INT RB1

 

RB2

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

RB3

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

1

 

2

 

3

 

4

 

5

 

6

 

7

 

8

 

 

9

 

 

 

 

 

 

 

 

 

 

 

 

2x470 Ohm

+5 V

10K Ohm

Figure 11-5 Circuit for Testing the Port-B Status Change Interrupt

In the circuit of Figure 11-5, a pushbutton switch is wired to the RB7 port and another one to RB4. Both of these switches produce the interrupt when pressed. A red LED is wired to port RA1 and a green LED to port RA0. The red and green LEDs are toggled on and off when the corresponding pushbutton switches are pressed. The switches contain a 4.7K Ohm resistor that keeps the port high until the contact is made and sent to ground. This makes both switches active low and the interrupt is programmed on the falling edge of the signal.

RB4-7 Interrupt Initialization

In order to initialize the RB4-7 change interrupt the following operations must take place:

1.Port-B lines 4 to 7 must be initialized for input.

2.The interrupt source must be set to take place either on the falling or the rising edge of the signal.

226

Chapter 11

3.The RB port change interrupt flag (RBIF in the INTCON Register) must be initially cleared.

4.Global interrupts must be enabled by setting the GIE bit in the INTCON Register.

5.The RB port change interrupt must be enabled by setting the RBIE bit in the INTCON Register.

6.Internal pull-ups on port-B should be disabled in the OPTION register.

The following code fragment from the program RB4to7Int in the book’s online software package shows the required processing:

;=============================

;main program ;============================= main:

;Disable port-B internal pull-ups

;Interrupts on falling edge of pushbutton action

 

Movlw

 

 

 

 

b’10111111’

 

option

 

 

 

 

 

 

; Wiring:

 

 

 

 

 

 

 

 

;

7

6

5

4

3

2

1

0

<= port-B

;

|

 

 

|_______________ red pushbutton

;

|________________________ black pushbutton

;

 

 

 

 

 

 

 

 

 

;

7

6

5

4

3

2

1

0

<= Port-A

;

 

 

 

 

 

 

|

|_____ red LED

;

 

 

 

 

 

 

|________ green LED

;

 

 

 

 

 

 

 

 

 

 

movlw

 

b’00000000’

 

; Set Port-A for ouput

 

tris

 

porta

 

 

 

 

 

movlw

 

b’11110000’

 

; Port-B bit 0-3 are output

 

 

 

 

 

 

 

 

 

; bits 4-7 are input

 

tris

 

portb

 

 

 

; all others are output

 

clrf

 

portb

 

 

 

; All port-B to 0

 

movlw

 

b’00000000’

 

; Zero to w

 

movwf

 

bitsB47

 

 

; Store in local variable

; Initially turn on LEDs

 

 

 

 

bsf

 

porta,0

 

 

; Set LEDs on line 0

 

bsf

 

porta,1

 

 

; and on line 1

;============================

;setup interrupts ;============================

;Clear external interrupt flag (intf = bit 1)

bcf

INTCON,rbif

; Clear flag

;Enable global interrupts (gie = bit 7)

;Enable RB0 interrupt (inte = bit 4)

bsf

INTCON,gie

;

Enable

global int (bit

7)

bsf

INTCON,rbie

;

Enable

RB0 int (bit 3)

 

Interrupts

227

RB4-7 Change Interrupt Service Routine

The Service Routine for the RB4-7 change interrupt depends on the specific application. Nevertheless, the following processing steps should be considered:

1.Determine if the source is an RB4-7 change interrupt.

2.Clear the RBIF interrupt flag in the INTCON Register.

3.Save the context. Which registers and variables need to be saved depends on the specific application.

4.Perform the interrupt action.

5.Restore the context.

6.Return from the interrupt with the retfie instruction.

In addition, the interrupt handler may have to perform operations that are specific to the application; for example, debounce a switch or initialize local variables. The following Interrupt Service routine is from the program RB4to7Int in the book’s online software:

;=======================================================

;

Interrupt Service Routine

;=======================================================

;Service routine receives control whenever any of

;port-B lines 4 to 7 change state

IntServ:

; First test: make sure source is an RB4-7 interrupt

btfss

INTCON,rbif

; RBIF flag is interrupt

goto

notRBIF

; Go if not RBIF origin

; Save context

 

 

movwf

old_w

; Save w register

swapf

STATUS,w

; STATUS to w

movwf

old_status

; Save STATUS

;=========================

;interrupt action ;=========================

;The interrupt occurs when any of port-B bits 4 to 7

;have changed status.

movf

portb,w

; Read port-B bits

movwf

temp

; Save reading

xorwf

bitsB47,f

;

Xor with old bits,

 

 

;

result in f

; Test each meaningful bit (4 and 7 in this example)

btfsc

bitsB47,4

; Test bit 4

goto

bit4Chng ; Routine for changed bit 4

; At this point bit 4 did not change

btfsc

bitsB47,7

; Test bit 7

goto

bit7Chng ; Routine for changed bit 7

; Invalid port line change. Exit

 

goto

pbRelease

 

228

Chapter 11

;========================

;bit 4 change routine ;========================

;Check for signal falling edge, ignore if not bit4Chng:

btfsc

portb,4

; Is bit

4 high

goto

pbRelease

; Bit is

high. Ignore

; Toggling bit 1 of Port-A turns LED on and off

movlw

b’00000010’

; Xoring

with a 1-bit produces

 

 

; the complement

xorwf

porta,f

; Complement bit 1, Port-A

goto

pbRelease

 

 

;========================

 

 

;bit 7 change routine ;========================

;Check for signal falling edge, ignore if not bit7Chng:

btfsc

portb,7

; Is bit 7 high

goto

exitISR

; Bit is high. Ignore

; Toggling bit 0 of Port-A turns LED on and off

movlw

b’00000001’

; Xoring with a 1-bit produces

 

 

; the complement

xorwf

porta,f

; Complement bit 1, Port-A

;

 

 

pbRelease:

 

 

call

delay

; Debounce switch

movf

portb,w ; Read port-B into w

andlw

b’10010000’ ; Eliminate unused bits

btfsc

STATUS,z ; Check for zero

goto

pbRelease

; Wait

;At this point all port-B pushbuttons are released ;=========================

;exit ISR

;=========================

 

exitISR:

 

 

 

; Store new value of port-B

 

movf

temp,w

 

; This port-B value to w

movwf

bitsB47

 

; Store

; Restore context

 

 

 

swapf

old_status,w

; Saved status to w

movfw

STATUS

; To STATUS register

swapf

old_w,f

; Swap file register in itself

swapf

old_w,w

; re-swap back to w

; Reset,interrupt

 

 

 

notRBIF:

 

 

 

bcf

INTCON,rbif

; Clear INTCON bit 0

retfie