Sie sind auf Seite 1von 6

Interrupts on 16F877-RB (RB4-RB7)

Abdel-Rahman M. Jaradat
April 24, 2012

Abstract
PIC 16F877 Interrupt System

1 How can the RB interrupt be used to detect a button press?


The RB interrupt will happen when there is any change (input or output) on pins B4-B7. There is only one interrupt
and the PIC does not tell you which pin changed. The programmer must determine the change based on the previously
known value of the port. Furthermore, a single button press may cause several interrupts due to bounce in the switch.
A debounce algorithm (or hardware) will need to be used. The following is a simple example:
byte previous_b; // global variable (byte=unsigned int8)
#int_rb
rb_isr() {
byte changes, port_b; // local variables
port_b=input_b(); // read portB (input or output)
changes = previous_b ^ port_b; // locate pins changed level (old xor new)
previous_b = port_b; // take a current reading and save it for next RB int

if (bit_test(changes,4)&& !bit_test(previous_b,4)){ do something 4} //b4 went low


if (bit_test(changes,5)&& bit_test (previous_b,5)){do something 5} //b5 went high
if (bit_test(changes,6)&& bit_test(previous_b,6)){do something 6} //b4 went high
if (bit_test(changes,7)&& !bit_test (previous_b,7)){do something 7} //b5 went low

delay_ms (20); //debounce


}

The delay=ms (20) is a crude way to debounce a (mechanical) switch. In general, you will not want to sit in an
ISR for 20 MS to allow the switch to debounce. A more elegant solution is to set a timer on the first interrupt and
wait until the timer overflows. Do not process further changes on the pin.

2 CCS C Register Manipulation Instructions


num can be: 8, 16, or 32 bit integer
bit_set(num,3);
bit_clear(num,5);
value=bit_test(num,7); // value=0 or 1
swap(abyte); // swap nybbles. Function does not return a value.

3 Example from Sanchez


#include "16f877a.h"
#use delay (clock=20000000) // 4MHz crystal
#fuses HS, NOWDT, NOPUT, NOPROTECT
// interrupt from RB (RB4 to RB7)
byte old_portb=0; // global var; assume initially zero
#int_rb
void rb4to7_isr()
{
// check what pin changed status
byte i, change;
delay_ms(20); // debouncing the switches
i=input_B(); //
change=i ^ old_portb;
old_portb=i; // save as old for next interrupt
if (bit_test(change,4)==1)
output_toggle(PIN_A1); // toggle RA1
if (bit_test(change,7)==1)
output_toggle(PIN_A0); // toggle RA0
}

void main()
{
port_b_pullups(0); // disable

enable_interrupts(int_rb);
enable_interrupts(global);
while(1) {

}
}
and in assembly language: Sanchez pages 235-240
; The RB4to7Int Program
; File: RB4to7Int.asm
; Date: April 26, 2006
; Author: Julio Sanchez
; Processor: 16F84A
;
; Description:
; Program to test the port-B, bits 4 to 7, STATUS change interrupt. Pushbutton
switches are connected
; to port-B lines 4 and 7. A red LED is wired to port RA1 and a green LED to port
RA0. The pushbuttons
; generate interrupts that toggle a LED on and off.
;===========================
; switches
;===========================
; Switches used in __config directive:
; _CP_ON Code protection ON/OFF
; * _CP_OFF
; * _PWRTE_ON Power-up timer ON/OFF
; _PWRTE_OFF
; _WDT_ON Watchdog timer ON/OFF
; * _WDT_OFF
; _LP_OSC Low power crystal occilator
; * _XT_OSC External parallel resonator/crystal oscillator
; _HS_OSC High speed crystal resonator (8 to 10 MHz)
; Resonator: Murate Erie CSA8.00MG = 8 MHz
; _RC_OSC Resistor/capacitor oscillator (simplest, 20% error)
; |
; |_____ * indicates setup values
;=========================
; set up and configuration
;=========================
processor 16f84A
include <p16f84A.inc>
__config _XT_OSC & _WDT_OFF & _PWRTE_ON & _CP_OFF
;=====================================================
; variables in PIC RAM
;=====================================================
; Local variables
cblock 0x0d ; Start of block
J ; counter J
K ; counter K
count1 ; Auxiliary counter
count2 ; ISR counter
old_w ; Context saving
old_STATUS ; Idem
bitsB47 ; Storage for previous value in port-B bits 4-7
temp ; Temporary storage
endc
;========================================================
; m a i n p r o g r a m
;========================================================
org 0 ; start at address 0
goto main
;
;=============================
; interrupt handler
;=============================
org 0x04
goto IntServ
;=============================
; main program
;=============================
main:
; Disable port-B internal pullups
; 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
;============================
; set up 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)
;============================
; flash LED
;============================
; Main program does nothing. All action takes place in
; Interrupt Service Routine
lights:
nop
goto lights
;=======================================================
; 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
;========================
; 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
movwf 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
;=======================
; Procedure to delay
; 10 machine cycles
;=======================
delay:
movlw D’6’ ; Repeat 18 machine cycles
movwf count1 ; Store value in counter
repeat:
decfsz count1,f ; Decrement counter
goto repeat ; Continue if not 0
return
;=============================
; long delay sub-routine
; (for debugging)
;=============================
long_delay
movlw D’200’ ; w = 200 decimal
movwf J ; J = w
jloop:
movwf K ; K = w
kloop:
decfsz K,f ; K = K-1, skip next if zero
goto kloop
decfsz J,f ; J = J-1, skip next if zero
goto jloop
return
end
;

Das könnte Ihnen auch gefallen