Using Interrupts to blink the LEDs on the LAB-X3

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