;****************************************************************************** ;Filename: clock.asm ;Author: Eric Torrence ;Date: 17/03/06 ;Version: 1.00 ;Description: ; This firmware implements an octal counter output on GP0-2 based on a ; clock with approximately half second period. ; ;****************************************************************************** ;Revision History: ; none ;****************************************************************************** ;************************** COMPILER INSTRUCTIONS ***************************** ; The following lines specify the processor hardware, and must match ; the specific processor being used. ; The include file gives names to commonly used system registers ; which are used below rather than the specific hardware addresses. ; This makes the code more readable and less error-prone. list p=12f675 ; list directive to define processor #include ; processor specific variable definitions ; Turn off annoying warning messages about BANK0/BANK1 errorlevel -302 ; suppress message 302 from list file __CONFIG _CP_OFF & _CPD_OFF & _BODEN_OFF & _MCLRE_OFF & _WDT_OFF & _PWRTE_ON & _INTRC_OSC_NOCLKOUT ; '__CONFIG' directive is used to embed the processor configuration word ; within the .asm file. See data sheet for additional information on ; configuration word settings. ;************************** VARIABLE DEFINITIONS ****************************** ; cblock defines a specific range of memory locations and gives each byte ; a specific name which can be used elsewhere in the code. cblock 0x20 COUNT ; Counter value DELAY_hi ; Hi word of delay counter DELAY_mid ; Mid word of delay counter DELAY_lo ; Lo word of delay counter endc ;*************************** DEFINE STATEMENTS ******************************** ; ; Timing is controled by a delay loop. Each loop cycle takes 4 us when ; the chip is driven from the internal 4 MHz clock. We want to increment ; the counter every half second, so we should count down from 125k or ; 0x01e848. This (just) takes three bytes, so we need to nest three ; delay loops to do the job. ; ; Because of the way the loop works, we must add one to each value ; (only really matters for the hi loop). There are also some extra ; operations for checking the mid and hi loop, so the mid loop isn't ; exactly 2^8 x 4 us, but it is determinsitic. To adjust the timing, ; simply change the values defined below. ; ; With an external clock and careful counting of operations, ; this can be made extremely precise. #define WAIT_hi 0x02 ; Countdown time for wait loop #define WAIT_mid 0xe9 ; Countdown time for wait loop #define WAIT_lo 0x49 ; Countdown time for wait loop ; Set GP0-2 as output, rest as input (high-Z) ; Note: GP3 can only be an input #define TRIS B'111000' ;****************************** Start of Program ****************************** org 0x000 ; processor reset vector goto Initialize ; Skip interrupt handler ;****************************************************************************** ; Initialize ; Initialize Special Function Registers ;****************************************************************************** org 0x005 ; Start of Programm Memory Vector Initialize: ; The following resets the factory calibration for the internal oscillator. ; This will give (slightly) more accurate timing values. banksel OSCCAL call 0x3FF ; retrieve factory calibration value movwf OSCCAL ; update register with factory calib ; Set I/O pins direction banksel TRISIO movlw TRIS ; Fill value into working register (W) movwf TRISIO ; Move W to Tri-state register clrf ANSEL ; Make all inputs digital ; Turn off weak pullups on outputs by setting hi bit of OPTION_REG movlw B'10000000' ; Fill value into W movwf OPTION_REG ; Move value from W to OPTION_REG clrf INTCON ; disable all interrupts banksel GPIO ; Select Bank 0 clrf COUNT ; clear counter at start CountLoop: incf COUNT, w ; increment COUNT and store result in W andlw 0x07 ; mask off three lowest bits in W movwf GPIO ; copy result to output register movwf COUNT ; copy result back to COUNT call WaitSub ; Call sub-routine to wait for a while ; Execution returns here when done goto CountLoop ; Go back to start of loop ;****************************************************************************** ; WaitSub ; Wait for defined time, nominally one-half second. ; ;****************************************************************************** WaitSub: ; Initialize the countdown counter movlw WAIT_hi movwf DELAY_hi movlw WAIT_mid movwf DELAY_mid movlw WAIT_lo movwf DELAY_lo ; Most operations take 1 us to complete using the internal clock, the ; goto takes 2, so each counter cycle takes 4 us. There are a few ; extra cycles for the mid and hi loop logic, but these make a small ; error. For precise timing, we should take these into account as well. ; DelayLoop: nop ; No operation. Needed to waste some time decfsz DELAY_lo, f ; Decrement lo byte, skip next line if zero goto DelayLoop decfsz DELAY_mid, f ; Decrement mid byte, skip next line if zero goto DelayLoop decfsz DELAY_hi, f ; Decrement hi byte, skip next if zero goto DelayLoop ; Check if wait counter has bit set return ; Return to call statement end ; directive 'end of program'