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: