TITLE "Alcor-FS3 for PIC16F84 - M. Covington 2006" ; Fast-slewing version of: ; Alcor telescope drive corrector, version 1.2, 1999 May 22 ; Modified by M. Covington, 2006 July 14 ; THIS VERSION: ; Slews east and west at full sidereal speed instead of 4" per second. ; Does not support 50-Hz motors (the _50HZ pin is ignored). ; Does not support diagonal slewing. This is intentional so that the ; output frequency will always be 60 Hz when slewing north and south, ; and the output can be used to run low-power AC declination motors. ; ; For PIC16F84A with 4.000-MHz crystal. ; Should port to lower PICs with 13 i/o pins. ; ; Pin assignments: ; ; Inputs, all active low, with weak pullups: ; ; Buttons: ; B0 _NORTH Ground this pin to slew northward ; B1 _SOUTH Ground to slew southward ; B2 _EAST Ground to slew eastward (slow down) ; B3 _WEST Ground to slew westward (speed up) ; Jumpers: ; B4 _LUNAR Ground to select lunar rate ; B5 _50HZ Ground to select 50 Hz -- NOT USED IN THIS VERSION ; B6 _SWAPNS Ground to swap _NORTH and _SOUTH ; B7 _SWAPEW Ground to swap _EAST and _WEST ; ; Outputs: ; ; A0 GONORTH High when dec motor shd go north ; A1 GOSOUTH High when dec motor shd go south ; A2 PHASE1 Phase 1 of 2-phase drive ; A3 PHASE2 Phase 2 of 2-phase drive ; A4 SQWAVE Square wave out (REQUIRES PULL-UP) ; ; ; Remarks on program logic: ; ; The basic task of this program is to produce output waveforms ; of the correct frequency at all times, depending on buttons. ; Frequency changes are gradual. ; ; The program has a table of 10 frequencies (indexed 0..9 for ; 60Hz), most of which are used only during transitions: ; Frequency 0 = west slewing ; Frequency 4 = sidereal rate ; Frequency 5 = lunar rate ; Frequency 9 = east slewing ; ; ACTFRQ is the frequency currently in use, and DESFRQ is the ; frequency that the user is requesting. ACTFRQ is incremented ; or decremented once per AC cycle to make it match DESFRQ. ; ; During the delay loop, there is a 10-way branch that selects ; the right length of delay for the variable part of the AC cycle. ; ; ; Remark on programming technique: ; ; Conditionals within timing loops are arranged so that they ; take equal amounts of time on either branch. On the PIC, ; this is done as follows: ; ; btfsc addr,bit ;; if bit is 0 ; goto L1 ;; ; nop ;; then ; ------------------- ; -- block of code -- ; ------------------- ; goto L2 ;; else ; L1 ;; ; ------------------- ; -- block of code -- ; ------------------- ; goto L2 ;; end if ; L2 ;; ; ; This takes 5 cycles on either branch, plus the time ; taken by the appropriate block of code. ; ; A much simpler approach, if only a single instruction ; is involved, is something like this: ; ; btfsc reg,bit ;; if bit is 1 ; xorwf reg ;; do this ; ; If the skip is taken, a nop is executed in place of xorwf. ; ; ; Frequencies and delays ; ; Drive rate 60 Hz motor 50 Hz motor ; ; Sidereal 60.164 Hz 50.137 Hz ; Lunar 58.696 Hz 48.912 Hz ; updated ver. 1.2 ; (Average topocentric, moon high in sky, temperate latitudes) ; East slewing 0 Hz ; West slewing 120 Hz ; ; Caution! Because of the use of integer counts in the ; program, and because of crystal tolerances, these ; frequencies are accurate only to 0.01% (100 ppm). ; For much greater accuracy, trim the crystal frequency ; with a variable capacitor. ; ; The timing loop has a fixed part and a variable part. ; ; Fixed part of loop 4156 CPU cycles (= microseconds) ; ; Variable part of loop: ; ; ALCOR ALCOR-FS2 ; freq 0 2410 0 ; for 120 Hz output ; freq 1 2761 1000 ; freq 2 3164 2000 ; freq 3 3626 3000 ; freq 4 (sid.) 4155 4155 ; freq 5 (lunar) 4363 4363 ; freq 6 5032 8000 ; freq 7 5661 16000 ; freq 8 6369 32000 ; freq 9 7166 infinity ; motors powered off ; ; Main loop takes 64 cycles in addition to the delay loops, ; so we subtract 32 cy. from the fixed part and 32 from var. part. ; ; ; CPU CONFIGURATION ; processor 16f84a include __config _XT_OSC & _WDT_OFF & _PWRTE_ON ; Oscillator type XT ; Watchdog timer OFF ; Power-up timer ON ; ; (In MPLAB, be sure to set these from menus.) ; Store identifying data in data EEPROM ORG 2100H DE "Alcor-FS3 Copyright 2006 M. Covington" ; ; DATA MEMORY ; DESFRQ equ 0x1F ; desired frequency setting ACTFRQ equ 0x1E ; frequency setting currently in use BUTTONS equ 0x1D ; holds button input bits PHFLAG equ 0x1C ; flag for distinguishing the 2 phases R1 equ 0x1B ; used by delay loops R2 equ 0x1A ; used by delay loops R3 equ 0x19 ; used by delay loops R4 equ 0x18 ; used by delay loops inner equ R1 outer equ R2 loopvar equ R1 _NORTH equ 0 ; Bit numbers for BUTTONS and PORTB _SOUTH equ 1 _EAST equ 2 _WEST equ 3 _LUNAR equ 4 _50HZ equ 5 ; ignored in ALCOR-FS _SWAPNS equ 6 _SWAPEW equ 7 GONORTH equ 0 ; Bit numbers for PORTA GOSOUTH equ 1 PHASE1 equ 2 PHASE2 equ 3 SQWAVE equ 4 ; ; MAIN PROGRAM ; org 0 START ; Initialize variables movlw 4 movwf DESFRQ ; DESFRQ := 4 movwf ACTFRQ ; ACTFRQ := 4 clrf PHFLAG ; PHFLAG := b'00000000' ; Initialize port A as outputs movlw b'00000000' tris PORTA ; deprecated instruction clrf PORTA ; take all outputs low ; Initialize port B as input movlw b'11111111' tris PORTB ; deprecated instruction ; Enable weak pull-ups on port B movlw b'01111111' option ; deprecated instruction MAIN ; Copy _NORTH, _SOUTH, _EAST, _WEST from PORTB into BUTTONS movfw PORTB andlw b'00001111' movwf BUTTONS ; If _SWAPNS is active (low), toggle both _NORTH and _SOUTH movlw b'00000011' btfss PORTB,_SWAPNS xorwf BUTTONS,F ; If _NORTH and _SOUTH are both 0, set them both to 1 ; ; (This handles two situations: user pressing both buttons, ; or user pressing neither button and swap requested.) movfw BUTTONS andlw b'00000011' ; isolate bottom two bits btfsc STATUS,Z ; if result was zero movlw b'00000011' ; accumulator = 00000011 iorwf BUTTONS,F ; put back in BUTTONS ; If _SWAPEW is active (low), toggle both _EAST and _WEST movlw b'00001100' btfss PORTB,_SWAPEW xorwf BUTTONS,F ; If _EAST and _WEST are both 0, set them both to 1 movfw BUTTONS andlw b'00001100' ; isolate the two bits btfsc STATUS,Z ; if result was 0 movlw b'00001100' ; accumulator = 00001100 iorwf BUTTONS,F ; put back in BUTTONS ; NEW CODE IN ALCOR-FS3, taking 7 cycles ; If oscillator is not running at freq 4 or 5, ; ignore the dec buttons ; Note: bsf does not affect the zero flag. movfw ACTFRQ subwf d'4',W ; w := ACTFRQ - 4 andlw b'11111110' ; if it's 1 change to 0 btfss STATUS,Z ; if result is not zero bsf BUTTONS,_NORTH ; assert north button is not pressed btfss STATUS,Z ; same condition again bsf BUTTONS,_SOUTH ; assert south button is not pressed ; Set declination outputs, avoiding glitches btfsc BUTTONS,_NORTH ; if BUTTONS._NORTH = 1 bcf PORTA,GONORTH ; then GONORTH := 0 btfss BUTTONS,_NORTH ; if BUTTONS._NORTH = 0 bsf PORTA,GONORTH ; then GONORTH := 1 btfsc BUTTONS,_SOUTH ; if BUTTONS._SOUTH = 1 bcf PORTA,GOSOUTH ; then GOSOUTH := 0 btfss BUTTONS,_SOUTH ; if BUTTONS._SOUTH = 0 bsf PORTA,GOSOUTH ; then GOSOUTH := 1 ; Select desired frequency movlw 4 ; default is sidereal rate, 4 btfss PORTB,_LUNAR ; if lunar rate selected, use 5 movlw 5 btfss BUTTONS,_EAST ; if east slewing, use 9 movlw 9 btfss BUTTONS,_WEST ; if west slewing, use 0 movlw 0 movwf DESFRQ ; DESFRQ := what was just chosen ; Adjust actual frequency for this cycle ; Comparisons rely on the fact that SUBWF ; *clears* the Carry flag iff the result is negative, ; and sets it otherwise. ; If ACTFRQ < DESFRQ, increment ACTFRQ movfw DESFRQ subwf ACTFRQ,W ; w := ACTFRQ - DESFRQ btfss STATUS,C ; if negative result then incf ACTFRQ,F ; increment ACTFRQ ; If DESFRQ < ACTFRQ, decrement ACTFRQ movfw ACTFRQ subwf DESFRQ,W ; w := DESFRQ - ACTFRQ btfss STATUS,C ; if negative result then decf ACTFRQ,F ; decrement ACTFRQ ; Perform fixed-length part of cycle ; toggle SQWAVE movlw B'00010000' ; pick out SQWAVE xorwf PORTA,F ; toggle it ; raise PHASE1 or PHASE2 as appropriate comf PHFLAG,F ; toggle PHFLAG btfss PHFLAG,1 ; if PHFLAG.1 bsf PORTA,PHASE1 ; set PHASE1 btfsc PHFLAG,1 ; if PHFLAG.1 bsf PORTA,PHASE2 ; set PHASE2 ; delay code ; In this version the maximum duty cycle is not 100%; ; it is 3703/(3703+2+416) or about 90%. ; Delay 3703 cycles ; ###################################################### ; # Code generated by PICDELAY 2.0 from JBE AB, Sweden # ; ###################################################### ; 3703 cycle delay movlw 10 movwf outer loop1 movlw d'122' movwf inner loop2 decfsz inner,F goto loop2 decfsz outer,F goto loop1 goto $+1 ; test for 50 Hz removed here ; lower PHASE1 and PHASE2 bcf PORTA,PHASE1 bcf PORTA,PHASE2 ; Delay 416 cycles ; ###################################################### ; # Code generated by PICDELAY 2.0 from JBE AB, Sweden # ; ###################################################### movlw d'138' movwf loopvar d416top decfsz loopvar,F goto d416top nop ; Depending on actfrq, perform appropriate delay for ; variable-length part of cycle ; Jump table has 10 entries, ; corresponding to freqs 0-9 for 60 Hz motor movfw ACTFRQ ; w := ACTFRQ ; test for 50 Hz removed here nop nop addwf PCL,F ; Add w to program counter. ; WARNING! We must be ; entirely within the ; first 256 words of program ; memory to avoid a page boundary. goto d60_0 ; The infamous 10-way branch. goto d60_1 goto d60_2 goto d60_3 goto d60_4 goto d60_5 goto d60_6 goto d60_7 goto d60_8 goto d60_9 ; It's OK for the GOTOs to jump across a page boundary. ; Accordingly, the following code can fall anywhere. d60_0 ; Zero delay GOTO MAIN d60_1 ; ###################################################### ; # Code generated by PICDELAY 2.0 from JBE AB, Sweden # ; ###################################################### ; inner and outer are any ram bytes (file registers) ; 1000 cycle delay starts movlw d'27' movwf outer d60_11 movlw d'11' movwf inner d60_12 decfsz inner,F goto d60_12 decfsz outer,F goto d60_11 ; Delay ends GOTO MAIN d60_2 ; ###################################################### ; # Code generated by PICDELAY 2.0 from JBE AB, Sweden # ; ###################################################### ; inner and outer are any ram bytes (file registers) ; 2000 cycle delay starts movlw d'54' movwf outer d60_21 movlw d'11' movwf inner d60_22 decfsz inner,F goto d60_22 decfsz outer,F goto d60_21 nop ; Delay ends GOTO MAIN d60_3 ; ###################################################### ; # Code generated by PICDELAY 2.0 from JBE AB, Sweden # ; ###################################################### ; inner and outer are any ram bytes (file registers) ; 3000 cycle delay starts movlw d'81' movwf outer d60_31 movlw d'11' movwf inner d60_32 decfsz inner,F goto d60_32 decfsz outer,F goto d60_31 goto $+1 ; Delay ends GOTO MAIN d60_4 ;;;;;; ; Code generated by PICDELAY v5 10-16-1997 20:16:38 ; Delay loop, 4123 cycles - sidereal rate ; ; MOVLW 0x56 MOVWF R1 MOVLW 0x6 MOVWF R2 DELAY1005: DECFSZ R1,F GOTO DELAY1005 DECFSZ R2,F GOTO DELAY1005 GOTO $+1 GOTO $+1 GOTO $+1 GOTO $+1 GOTO $+1 ; ;;;;;; GOTO MAIN d60_5 ;;;;;; ; Code generated by PICDELAY v5 05-22-1999 14:15:36 ; Delay loop, 4331 cycles - lunar rate ; MOVLW 0x9C MOVWF R1 MOVLW 0x6 MOVWF R2 MOVLW 0x1 MOVWF R3 MOVLW 0x1 MOVWF R4 DELAY1006: DECFSZ R1,F GOTO DELAY1006 DECFSZ R2,F GOTO DELAY1006 DECFSZ R3,F GOTO DELAY1006 DECFSZ R4,F GOTO DELAY1006 ; ;;;;;; GOTO MAIN d60_6 ; ###################################################### ; # Code generated by PICDELAY 2.0 from JBE AB, Sweden # ; ###################################################### ; inner and outer are any ram bytes (file registers) ; 8000 cycle delay starts movlw d'19' movwf outer d60_61 movlw d'139' movwf inner d60_62 decfsz inner,F goto d60_62 decfsz outer,F goto d60_61 ; Delay ends GOTO MAIN d60_7 ; ###################################################### ; # Code generated by PICDELAY 2.0 from JBE AB, Sweden # ; ###################################################### ; inner and outer are any ram bytes (file registers) ; 16000 cycle delay starts movlw d'38' movwf outer d60_71 movlw d'139' movwf inner d60_72 decfsz inner,F goto d60_72 decfsz outer,F goto d60_71 nop ; Delay ends GOTO MAIN d60_8 ; ###################################################### ; # Code generated by PICDELAY 2.0 from JBE AB, Sweden # ; ###################################################### ; inner and outer are any ram bytes (file registers) ; 32000 cycle delay starts movlw d'76' movwf outer d60_81 movlw d'139' movwf inner d60_82 decfsz inner,F goto d60_82 decfsz outer,F goto d60_81 goto $+1 nop ; Delay ends GOTO MAIN d60_9 ; Instead of a time delay, we power off the output ; and leave it off until PORTB._EAST goes high. ; lower PHASE1 and PHASE2 bcf PORTA,PHASE1 bcf PORTA,PHASE2 d60_91 btfsc PORTB,_EAST goto MAIN goto d60_91 ; Large amount of 50 Hz code removed here END