CBC-USNA-T77 shares this code

;**********************************************************************
;       This program for the PIC16F874 solves the following program specification:
;       1.      Have the processor generate an interrupt every 1 ms.
;       2.      Toggle Port A <4> every 500 ms.
;**********************************************************************
;                                                                     *
;    Filename:      easysamp.asm                                      *
;    Date:          06 March 2001                                     *
;    File Version:  1                                                 *
;                                                                     *
;    Author:        CDR Charles B. Cameron, USN                       *
;    Company:       United States Naval Academy                       *
;                                                                     * 
;                                                                     *
;**********************************************************************
;                                                                     *
;    Files required:                                                  *
;                                                                     *
;                  p16f874.inc                                        *
;                                                                     *
;**********************************************************************
;                                                                     *
;    Notes:
;       This program generates an interrupt every 1 ms.   Upon interrupt
;       it updates a counter.

;       PORTA<4> is an output pin.  It is toggled every 500 ms.
;       
;       It's assumed the processor is driven with a 4.000 MHz crystal 
;       oscillator and is to operate in HS mode.
;**********************************************************************


        list      p=16f874            ; list directive to define processor
        #include <p16f874.inc>        ; processor specific variable definitions
        
        __CONFIG _CP_OFF & _WDT_OFF & _BODEN_OFF & _PWRTE_ON & _HS_OSC & _WRT_ENABLE_ON & _LVP_OFF & _CPD_OFF

; '__CONFIG' directive is used to embed configuration data within .asm file.
; The labels following the directive are located in the respective .inc file.
; See respective data sheet for additional information on configuration word.

; The particular choice given above turns code protection off, watch dog timer off,
; brown-out reset disabled, power-up timer enabled, HS oscillator mode selected,
; flash program memory write disabled, low-voltage in-circuit serial programming
; disabled, and data EE memory code protrection off.  Change these at will!




;***** VARIABLE DEFINITIONS
w_temp          EQU     0x20    ; variable used for context saving 
status_temp     EQU     0x21    ; variable used for context saving
        cblock 0x22             ; define a series of variables.
                count1          ; The MSB of a 2-byte register counting
                                ; the number of Timer 2 interrupts 
                                ; which have occurred.
                count0          ; The LSB of the same 2-byte register.
                flag500ms       ; Contains a 0 unless 500 1-ms Timer 2
                                ; interrupts have been processed.
        endc
; Bits within PORTA
ToggleBit       equ     4       ; An output bit, toggled every 500 ms.
PortAMask       equ     B'00000000' ;  We'll make all of PORT A an output.


;**********************************************************************
                ORG     0x000             ; processor reset vector
                clrf    PCLATH            ; ensure page 0 is used
                goto    main              ; go to beginning of program


                ORG     0x004           ; interrupt vector location
                movwf   w_temp          ; save off current W register contents
                swapf   STATUS,W        ; move status register into W register
                clrf    STATUS          ; select Bank 0
                movwf   status_temp     ; save off contents of STATUS register
                                        ; There's no need to save PCLATH since
                                        ; we'll stick to Bank 0 of program memory.

; isr code can go here or be located as a call subroutine elsewhere


                btfsc   PIR1,TMR2IF     ; If Timer 2 caused the interrupt, handle it.
                call    Timer2


                swapf   status_temp,w     ; retrieve copy of STATUS register
                movwf   STATUS            ; restore pre-isr STATUS register contents
                swapf   w_temp,f
                swapf   w_temp,w          ; restore pre-isr W register contents
                retfie                    ; return from interrupt

; *********************************************
;       Timer 2 Interrupt handler.
;       Timer 2 has overflowed
;
Timer2
                                ; Increment the LSB of the 1-ms counter.
        incf    count0,F
                                ; If it rolls over, increment the MSB.
        btfsc   STATUS,Z
        incf    count1,F
                                ; See if the count has reached 500.
                                ; If so, set the toggle flag for the main processor
                                ; to take action.
        movlw   1               ; Is the MSB of the count 1?
        subwf   count1,W
        btfss   STATUS,Z        ; If count1 is not 1, we haven't reached 500.
        goto    EndTimer2Interrupt
                                ; Is the LSB = 500 - 256 = 244?
        movlw   D'500' - D'256'
        subwf   count0,W
        btfss   STATUS,Z        ; If not, we still haven't reached 500.
        goto    EndTimer2Interrupt
; If we get here, it's because we have processed 500 1-ms Timer 2 Interrupts.
; Set the flag500ms variable to a non-zero value.
        movlw   H'FF'
        movwf   flag500ms
; Reinitialize count1 and count0
        clrf    count1
        clrf    count0

EndTimer2Interrupt

        BCF PIR1,TMR2IF ; Clear flag and continue.
        return

main
; ***********************************************************************************
; START OF CODE to initialize the processor
; The initialization code goes here since we'll end up here shortly after a reset.
; ***********************************************************************************

; ***********************************************************************************
; Most Bank 0 initializations are done here and they come first.
; ***********************************************************************************

        bcf     STATUS,RP0      ; Select Bank 0
        bcf     STATUS,RP1

        clrf    PORTA           ; Initialize Port A by clearing the output latches.

        clrf    count1          ; Re-initialize count1 and count0.
        clrf    count0

        clrf    flag500ms       ; Turn off the flag which, when set, says 500 ms has elapsed.

; ***********************************************************************************
; Most Bank 1 initializations come next.
; ***********************************************************************************

        bsf     STATUS,RP0      ; Select Bank 1

        movlw   PortAMask       ; Initialize direction pins for Port A using TRISA.
        movwf   TRISA
        movlw   B'00000110'     ; Don't use any pins of Port A for A/D conversions
        movwf   ADCON1

        bcf     STATUS,RP0      ; Revert to Bank 0

; ***********************************************************************************
; START OF CODE to initialize Timer 2
; These come next only because it's convenient to group them together, not because
; it's a necessity.

; Set up Timer 2 to generate interrupts every 1 ms.  Since we're assuming an instruction
; cycle consumes 1 us, we need to cause an interrupt every 1000 instruction cycles.
; We'll set the prescaler to 4, the PR2 register to 25, and the postscaler to 10.  This
; will generate interrupts every 4 x 25 x 10 = 1000 instruction cycles.  
; ***********************************************************************************

        CLRF    TMR2            ; Clear Timer2 register
        BSF     STATUS, RP0     ; Bank1
        bsf     INTCON,PEIE     ; Enable peripheral interrupts
        CLRF    PIE1            ; Mask all peripheral interrupts except
        bsf     PIE1,TMR2IE     ; the timer 2 interrupts.
        BCF     STATUS, RP0     ; Bank0
        CLRF    PIR1            ; Clear peripheral interrupts Flags
        movlw   B'01001001'     ; Set Postscale = 10, Prescale = 4, Timer 2 = off.
        movwf   T2CON
        BSF     STATUS, RP0     ; Bank1
        movlw   D'25'-1         ; Set the PR2 register for Timer 2 to divide by 25.
        movwf   PR2
        BCF     STATUS, RP0     ; Bank0
        bsf     INTCON,GIE      ; Global interrupt enable.
        BSF     T2CON,TMR2ON    ; Timer2 starts to increment

; ***********************************************************************************
; END OF CODE to initialize Timer 2
; ***********************************************************************************

; ***********************************************************************************
; main()
; This is the main program.  It does only one thing:  check to see if it's time to
; toggle PORTA<togglebit> and do so if it is time.  Otherwise it's busily engaged
; in using up all the instruction cycles not required by the interrupt handlers.

loop
        movf    flag500ms,W     ; Has the flag500ms been set?
        btfsc   STATUS,Z
        goto    loop            ; Not yet.  Keep looking.

        ; Yes, it's time to toggle PORTA<ToggleBit> and reset flag500ms.
        movlw   ToggleBit
        xorwf   PORTA,f
        clrf    flag500ms
        goto loop               ; Now wait for the next occurence.
; ***********************************************************************************




                END                       ; directive 'end of program''



See:

Questions: