title "" ;;; ********************************************************************* ;;; Filename: ;;; Purpose: ;;; Revision: ;;; Date: ;;; Author: ;;; Copyright: ;;; ********************************************************************* ;;; Revision History: ;;; ;;; ********************************************************************* list ; Turn on list output. ;; Include register, bit, and other info specific to ;; the specified device. ifdef __16F873 #include messg "Assembling for PIC16F873." endif ifdef __16F874 #include messg "Assembling for PIC16F874." endif ifdef __16F876 #include messg "Assembling for PIC16F876." endif ifdef __16F877 #include messg "Assembling for PIC16F877." endif ifdef __16F873A #define A_Device #include messg "Assembling for PIC16F873A." endif ifdef __16F874A #include #define A_Device messg "Assembling for PIC16F874A." endif ifdef __16F876A #define A_Device #include messg "Assembling for PIC16F876A." endif ifdef __16F877A #define A_Device #include messg "Assembling for PIC16F877A." endif ;;; -------------------------------------------------------------------- ;;; Included files (usually library headers). eg) #include "del_lib.h" ;;; -------------------------------------------------------------------- ;;; -------------------------------------------------------------------- ;;; Assembler Equates Section. Define assembly-time constants here ;;; using the EQU assembler directive. ;;; eg) DEBUGGING EQU 1 ;;; -------------------------------------------------------------------- ;;; --------------------------------------------------------------------- ;;; Variable Address Assignments. ;;; --------------------------------------------------------------------- UDATA ; Start of uninitialized data section. ; Reserve memory for variables using the ; "RES" directive here. Note that the ; linker will assign addresses. ; eg) ADcounter res 1 ; (reserves 1 byte for ADcounter). ;; For saving context. STATUS_Context: res 1 ; Saving of STATUS on interrupt. PCLATH_Context: res 1 ; Saving of PCLATH on interrupt. UDATA_OVR ; Uninitialized data overlay section. ; Upon occasion, temporary variables ; can be over-written by other temporary ; variables. These would appear here. ; BUT! If you ever intend on time-sliced ; or pre-emptive multitasking ; don't *ever* use this directive! UDATA_SHR ; Uninitialized data shared section. ; Variables that appear here appear ; across all banks, meaning that no ; bank selection will be required. ; Variables of this type are *required* ; when saving CPU context when an ; interrupt occurs. Not all devices ; have shared memory. In that case, you ; need to reserve memory across individual ; banks at the same offset by using ; multiple UDATA or UDATA_SHR assignments ; with an optional address specified. W_Context: res 1 ; Context saving on interrupt: W. ;;; --------------------------------------------------------------------- ;;; Establish the OPTION register bit values. ;;; --------------------------------------------------------------------- ;;; The '__CONFIG' directive is used to embed PIC configuration data ;;; within an assembly file. The labels following the directive ;;; are located in the .inc file. See the device data sheet for ;;; additional information on the configuration word. ifndef A_Device __CONFIG _CP_OFF & _WDT_OFF & _BODEN_ON & _PWRTE_ON & _XT_OSC & _WRT_ENABLE_ON & _LVP_OFF & _CPD_OFF endif ;;; _CP_OFF: turn off code protection. Don't change this unless you ;;; want a device that can never be programmed again. This ;;; is a "bug" in some PIC devices. ;;; _WDT_OFF: turn off the watchdog timer. ;;; _BODEN_ON: turn on power brown-out reset. ;;; _PWRTE_ON: turn on power-up timer. ;;; _XT_OSC: specify that the device is using an XT oscillator. ;;; _WRT_ENABLE_ON: enable writing to data EEPROM. ;;; _LVP_OFF: disable low-voltage in-circuit programming. ;;; _CPD_OFF: disable data EEPROM write protection. ifdef A_Device messg "A revision device." __CONFIG _CP_OFF & _WDT_OFF & _BODEN_ON & _PWRTE_ON & _XT_OSC & _WRT_OFF & _LVP_OFF & _CPD_OFF endif ;;; _CP_OFF: turn off code protection. Don't change this unless you ;;; want a device that can never be programmed again. This ;;; is a "bug" in some PIC devices. ;;; _WDT_OFF: turn off the watchdog timer. ;;; _BODEN_ON: turn on power brown-out reset. ;;; _PWRTE_ON: turn on power-up timer. ;;; _XT_OSC: specify that the device is using an XT oscillator. ;;; _WRT_OFF: disable write-protection of program FLASH. ;;; _LVP_OFF: disable low-voltage in-circuit programming. ;;; _CPD_OFF: disable data EEPROM write protection. ;;; -------------------------------------------------------------------- ;;; Main Program. ;;; -------------------------------------------------------------------- ISR: CODE 0x0004 ; Location of interrupt vector. ;; Save the CPU context. ;; Note that W_Context was declared under the UDATA_SHR section. ;; In the PIC16F876/7, it will appear across all banks of memory ;; and therefore no bank switching is required. For the ;; PIC16F873/4, a linker script and use of the UDATA_SHR section ;; reserves space for W_Context across all banks, even though ;; there are actually two separate locations. This code takes ;; this possible separation into account. See the linker script ;; (16F873.lkr), available from the same location as this ;; template for how this allocation occurs. movwf W_Context swapf STATUS,W banksel STATUS_Context movwf STATUS_Context movf PCLATH,W movwf PCLATH_Context ;; Why the swapf instruction, above? That's a good question. ;; The reason is that, unlike a move instruction, swapf doesn't ;; affect any bits in STATUS, which is important! ;; There are situations where you will need to save (and also ;; restore more than just these two registers. ;; ------------------------------------------------------------ ;; Your interrupt service routine code goes here. ;; ------------------------------------------------------------ ;; You'll generally need to follow these steps: ;; 1. Determine what caused the interrupt by checking ;; appropriate interrupt flags. You'll usually know which ;; ones to check, since you enable interrupts from certain ;; peripherals in the main program. ;; 2. Take appropriate action. ;; 3. Clear the interrupt source. How to do this depends ;; on the peripheral that caused the interrupt, but sometimes ;; it is as simple as clearing a flag. ;; ------------------------------------------------------------ ;; Come back to this point when your interrupt processing is ;; complete. ISR_Restore: ;; Restore the CPU context. banksel PCLATH_Context movf PCLATH_Context,W movwf PCLATH swapf STATUS_Context,W movwf STATUS ; Restores whichever bank W_Context ; actually appears in. swapf W_Context,F ; See the note above as to why swapf swapf W_Context,W ; is used. ;; Return from the interrupt, which pulls an address off the ;; (invisible) stack. retfie ;; ------------------------------------------------------------ ;; Your main code starts here. If it just follows the ISR, that ;; is usually OK. ;; ------------------------------------------------------------ Main: ;; Program initialization. !!! ;; Clear the interrupt flag for the individual peripheral(s), ;; just in case there is already an outstanding interrupt. ;; This is usually in a PIR register. !!! ;; Enable interrupts from individual peripheral(s). ;; This is usually in a PIE register. !!! ;; Turn on interrupts (in general -- this is the overall ;; interrupt "power switch"). This is usually done at ;; this location: after the rest of initialization but ;; just before the program goes into its overall loop. bsf INTCON, GIE ; INTCON appears in all banks. MainLoop: ;; Don't let execution fall down to here, otherwise the ;; subroutines (or whatever follows) will be executed without ;; parameters, and chaos reigns when a "return" instruction ;; executes with no return address on the stack! ;;; -------------------------------------------------------------------- ;;; Application-specific Subroutines. ;;; -------------------------------------------------------------------- ;;; ******************************************************************** ;;; Subroutine Name: ;;; Description: ;;; Requires: ;;; Returns: ;;; Locations Affected: ;;; ******************************************************************** ;;; -------------------------------------------------------------------- ;;; Code-section Constant Data. ;;; -------------------------------------------------------------------- ;;; --------------------------------------------------------------------- ;;; Vectors Section. ;;; --------------------------------------------------------------------- ;;; Establish the reset vector. Note that the "0x0000" after the CODE ;;; directive ensures that the linker places the code at program memory ;;; location 0x0000. Reset: CODE 0x0000 pagesel Main ; Selects page of program memory with. goto Main ; the actual program, then goes to it. END ; End of file.