Blinking LEDs with Interrupts
30-Dec-2001
Hot on the heels of my success with BLINKY, we do iBLINKY, the interrupt driven version! The cool thing for me was that by the time I got this running I have Visual SlickEdit configured to execute MPASM when I tell it to compile, and the EPICC program to program the PIC when I "execute." Now I never have to leave the IDE to compile and test, woo-hoo!
;
; IBLINKY.ASM
;
; Ok, so if you followed BLINKY.ASM this is just the
; version that uses TMR0 interrupts to do the blinking.
;
TITLE "IBLINKY - Blink an LED on 628"
LIST P=PIC16F628, R=HEX, C=120, N=50
include "P16f628.inc"
__FUSES _CP_OFF&_LP_OSC&_WDT_OFF&_LVP_OFF&_MCLRE_OFF
;
; Data bits
;
CBLOCK H'20'
COUNT
ENDC
;
; Initialization
;
ORG H'0000' ; Start VECTOR
BCF STATUS, RP0 ; Set to
BCF STATUS, RP1 ; .. bank 0
GOTO MAIN ; Reset the part
;
; Interrupt service routines
;
; Interrupts on the PIC vector to 0x0004 and then you have
; to figure out why you were interrupted and deal with it.
; The preamble saves W and STATUS the postamble Restores W
; and Status. Note that the SWAPF instruction is the only
; way to move data around without changing the actual
; status bits.
;
; Data Section
;
; These two variables, TMP_W and TMP_STATUS, are located
; at 0x70 because this memory appears in all banks of RAM.
; Thus the ISR does not have to mess with the bank number
; to work correctly.
;
CBLOCK H'70'
TMP_W ; Holder for W
TMP_STATUS ; Holder for Status
ENDC
LED1 EQU 4
LED2 EQU 5
I_CNT EQU H'10'
;
; Code Section
;
; The code section of the ISR lives at 0x0004. Its possible
; to put a jump here however doing so adds two clocks of
; latency to servicing any interrupt.
;
ORG H'0004' ; Interrupt service routine
INTR_SVC:
MOVWF TMP_W ; Copy W to a temp
SWAPF STATUS,W ; Preserve Status
MOVWF TMP_STATUS ; Copy STATUS to a temp
BCF STATUS, RP0 ; Force Bank 0
BCF STATUS, RP1 ;
;
; State is saved, and we've expended 3 Tcy plus the 3 Tcy
;(4 worst case) of interrupt latency for a total of
;6(7) Tcy.
;
; Now loop through until we've satisfied all the
; pending interrupts.
;
INTR_POLL:
; ... test bit to see if it is set
BTFSS INTCON,T0IF ; Did Timeer0 Overflow?
GOTO ISR_1 ; Nope, so check next thing.
;
; Process Timer 0 Overflow Interrupt
;
BCF INTCON, T0IF ; Clear Timer 0 interrupt
DECF COUNT,F ; Decrement interrupt counter
INCFSZ COUNT,W ; check for overflow
GOTO ISR_1 ; Nope, keep counting
;
; Count underflows when we've hit this interrupt "n"
; times, where n is the number in COUNT.
;
MOVLW I_CNT ; Restore counter value
MOVWF COUNT
CALL TOGGLE ; Toggle the LEDs
;
; Process next interrupt.
;
ISR_1:
;
; Exit the interrupt service routine.
; This involves recovering W and STATUS and then
; returning. Note that putting STATUS back
; automatically pops the bank back as well.
; This takes 6 Tcy for a total overhead of
; 12 Tcy for sync interrupts and 13 Tcy for
; async interrupts.
;
INTR_EXIT:
SWAPF TMP_STATUS,W ; Pull Status back into W
MOVWF STATUS ; Store in status
SWAPF TMP_W,F ; Prepare W to be restored
SWAPF TMP_W,W ; Restore it
RETFIE
;
; * * * * * * * * * * * *
; * M A I N *
; * * * * * * * * * * * *
;
; Main Body with initialization Etc.
;
MAIN:
BSF STATUS, RP0 ; Select Bank 1
MOVLW B'0000011' ; Set TMR0 prescaler to 256
MOVWF OPTION_REG ; Store it in OPTION
BCF PORTB, LED1 ; Enable LEDs to be outputs
BCF PORTB, LED2 ;
BCF STATUS, RP0 ; Back to page 0
BSF INTCON, T0IE ; Enable Timer 0 to interrupt
BCF INTCON,T0IF ; Reset interrupt flag
BSF INTCON, GIE ; Enable interrupts
BCF PORTB, LED1
BCF PORTB, LED2
;
; At this point we've got nothing to do except wait.
; In the input capture program we'll be printing out
; to the LCD what the current pulse width is.
;
WAIT:
GOTO WAIT
;
; Toggle the two LEDs.
;
TOGGLE:
BTFSS PORTB, LED1 ; If LED2 is on turn it off
GOTO $+4
BCF PORTB, LED1 ; Turn LED2 off
BSF PORTB, LED2
RETURN
BSF PORTB, LED1 ; Turn LED2 on
BCF PORTB, LED2
RETURN
END
|
||
| Listing 1: LED Blinking Program |