; guider.asm ; ; Control program for USB telescope guider ; by J C Moore ; Fleet Electronics Consultancy ; Last update 26 May 2005. ; Uses PIC16F630 with external 8MHz crystal and FTDI FT232BM USB chip. ; Compatible with ASCOM 'Meade LX200 and Autostar' telescope choice. ; list p=16f630 #include __CONFIG _CPD_OFF & _CP_OFF & _BODEN_OFF & _MCLRE_ON & _PWRTE_ON & _WDT_OFF & _HS_OSC list r=dec list c=132 list n=0 ; Working Baud rate is 9600. We want to sample this three times per bit, ; i.e. every 34.722uS: ; TMR0RELOAD equ 202 ; shortens cycle to 34.75uS average ; Locations used by interrupt service routine: ; WStore equ 0x20 ; must be bankless SStore equ 0x21 PStore equ 0x22 ; Remaining locations: ; Flags equ 0x23 ; Bits in Flags: ; TXBUSY equ 0 ; set when TX process busy RXRDY equ 1 ; set when byte received TxByte equ 0x24 TxByte2 equ 0x25 ; 16 bits hold start & stop bits as well TxJump equ 0x26 TxBits equ 0x27 TxBitWidth equ 0x28 RxByte equ 0x29 RxJump equ 0x2a RxBitWidth equ 0x2b RxBits equ 0x2c TempRx equ 0x2d ramtop equ 0x5f ; common banks ; Banked RAM locations (not used): ; bank0begin equ 0x60 bank0top equ 0x7f bank1begin equ 0xe0 bank1top equ 0xff ; Port connections: ; ; RA0 programming only ; RA1 programming only ; RA2 spare ; RA3 /MCLR ; RA4 crystal ; RA5 crystal ; RC0 RA- (East) output ; RC1 DEC- (South) output ; RC2 DEC+ (North) output ; RC3 RA+ (West) output ; RC4 serial out to USB chip ; RC5 serial in from USB chip ; EAST equ 0 SOUTH equ 1 NORTH equ 2 WEST equ 3 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; ; POWER ON RESET ; ; ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; org 0x000 clrf PCLATH goto Startup ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; ; INTERRUPT HANDLER ; ; ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; org 0x004 movwf WStore ; Save W register (in bank 0 or bank 1) swapf STATUS,w bcf STATUS,RP0 ; use bank 0 from now on movwf SStore ; Save status (reversed) movf PCLATH,w movwf PStore ; Save PC high ; Interrupt routine; caused by Timer0 overflow: ; TMR0 overflow occurs every 34.75uS on average: ; Int_Service: btfss INTCON,T0IF ; TMR0 ? goto Intret ; if not ; Service the Timer0 overflow: ; bcf INTCON,T0IF ; clear TMR0 interrupt flag movlw TMR0RELOAD ; Shorten cycle movwf TMR0 ; Do Tx process first before any variable timing paths occur: ; movf TxJump,w movwf PCL ; jump to assigned Tx location TxDone movwf TxJump ; Then Rx process: ; movf RxJump,w movwf PCL ; jump to assigned Rx location RxDone movwf RxJump ; (NB both computed jumps are safe using PCL only, because all this code ; resides comfortably on page 0) ; Restore registers and return from interrupt service routine: ; Intret movf PStore,w movwf PCLATH ; Restore PC high swapf SStore,w movwf STATUS ; Restore status (including RAM bank) swapf WStore,f ; from either bank swapf WStore,w ; Restore W without affecting Z bit retfie ; exit from interrupt service routine ; Transmit state machine: ; TxIdle btfsc Flags,TXBUSY goto Tx1 goto TxDone Tx1 decfsz TxBits,f goto Tx2 bcf Flags,TXBUSY ; signal that all done movlw TxIdle goto TxDone Tx2 rrf TxByte2,f rrf TxByte,f ; 16 bit word btfsc STATUS,C goto Tx3 nop ; equaliser bcf PORTC,4 ; start a 0 goto Tx4 Tx3 bsf PORTC,4 ; start a 1 Tx4 movlw 2 movwf TxBitWidth ; 3 periods total per bit Tx5 movlw Tx6 goto TxDone Tx6 decfsz TxBitWidth,f ; wait for whole bit time goto Tx5 movlw Tx1 goto TxDone ; Receive state machine: ; RxIdle btfss PORTC,5 goto Rx2 ; Rx start bit detected Rx1 movlw RxIdle goto RxDone Rx2 movlw 1 movwf RxBitWidth ; wait 1/3 bit to sample middle Rx3 movlw Rx4 goto RxDone Rx4 btfsc PORTC,5 ; resample possible start bit goto Rx1 ; restart on error decfsz RxBitWidth,f goto Rx3 movlw 8 movwf RxBits Rx5 movlw 3 movwf RxBitWidth Rx6 movlw Rx7 goto RxDone Rx7 decfsz RxBitWidth,f goto Rx6 btfsc PORTC,5 goto Rx8 bcf STATUS,C goto Rx9 Rx8 bsf STATUS,C Rx9 rrf RxByte,f ; shift in new bit decfsz RxBits,f goto Rx5 ; loop for another bit movlw 3 ; done all 8 bits movwf RxBitWidth ; so check at least 1 stop bit Rx10 movlw Rx11 goto RxDone Rx11 decfsz RxBitWidth,f goto Rx10 btfss PORTC,5 goto Frame_Error ; if no stop bit ; Receive completed: ; bsf Flags,RXRDY goto Rx1 ; success Frame_Error movlw 0xff movwf RxByte bsf Flags,RXRDY goto Rx1 ; finished ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; ; MAIN PROGRAMME ; ; ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Startup: bsf STATUS,RP0 ; bank 1 call 0x3ff ; get oscillator cal value movwf OSCCAL ; and apply it movlw 00111000b movwf TRISA ; RA2-RA0 outputs movlw 00100000b movwf TRISC ; RC4-RC0 outputs movlw 10001000b movwf OPTION_REG ; no weak pullups, TMR0, no prescaler clrf IOC ; no interrupts on change bcf STATUS,RP0 ; bank 0 movlw 00111111b movwf PORTC ; everything quiescent clrf Flags movlw TxIdle movwf TxJump movlw RxIdle movwf RxJump call IntInit Main call Rxchar xorlw ':' ; command prefix ? btfsc STATUS,Z goto Prefix xorlw ':' ^ 0x06 ; ACK ? btfss STATUS,Z goto Main ; ignore all others movlw 'P' call Txchar ; acknowledge with Polar goto Main ; ':' Command prefix recognised. Get next character: ; Prefix call Rxchar xorlw 'M' ; Move command ? btfsc STATUS,Z goto Move xorlw 'M' ^ 'Q' ; Quit command ? btfsc STATUS,Z goto Quit xorlw 'Q' ^ 'G' ; Get Telescope Information ? btfsc STATUS,Z goto Getinfo xorlw 'G' ^ 'S' ; Set Information ? btfsc STATUS,Z goto SetInfo xorlw 'S' ^ 'F' ; Focuser Control ? btfsc STATUS,Z goto Focus_Command xorlw 'F' ^ 'U' ; User Format ? btfsc STATUS,Z goto Ucommand goto Main ; else ignore ; Start movement: ; Move call Rxchar movwf TempRx xorlw 'e' ; move east ? btfss STATUS,Z goto m2 bcf PORTC,EAST goto Main m2 movf TempRx,w xorlw 'w' ; move west ? btfss STATUS,Z goto m3 bcf PORTC,WEST goto Main m3 movf TempRx,w xorlw 'n' ; move north ? btfss STATUS,Z goto m4 bcf PORTC,NORTH goto Main m4 movf TempRx,w xorlw 's' ; move south ? btfss STATUS,Z goto Main ; ignore bcf PORTC,SOUTH goto Main ; Quit movement: ; Quit call Rxchar movwf TempRx xorlw '#' ; quit all ? btfss STATUS,Z goto q1 movlw 00111111b movwf PORTC ; everything quiescent goto Main q1 movf TempRx,w xorlw 'e' ; quit east ? btfss STATUS,Z goto q2 bsf PORTC,EAST goto Main q2 movf TempRx,w xorlw 'w' ; quit west ? btfss STATUS,Z goto q3 bsf PORTC,WEST goto Main q3 movf TempRx,w xorlw 'n' ; quit north ? btfss STATUS,Z goto q4 bsf PORTC,NORTH goto Main q4 movf TempRx,w xorlw 's' ; quit south ? btfss STATUS,Z goto Main ; ignore bsf PORTC,SOUTH goto Main ; G command = Get Telescope Information: ; Getinfo call Rxchar xorlw 'S' btfsc STATUS,Z goto Sidereal xorlw 'V' ^ 'S' ; version numbers ? btfsc STATUS,Z goto Versions xorlw 'Z' ^ 'V' ; get azimuth ? btfsc STATUS,Z goto Azimuth xorlw 'R' ^ 'Z' ; get RA ? btfsc STATUS,Z goto RA xorlw 'D' ^ 'R' ; get Dec ? btfsc STATUS,Z goto Dec xorlw 't' ^ 'D' ; get site latitude ? btfsc STATUS,Z goto Dec ; same response as Dec xorlw 'A' ^ 't' ; get altitude ? btfsc STATUS,Z goto Dec ; same response as Dec goto Main Sidereal call GetHash bnz Main call SendZeros ; respond with dummy time goto Main Versions call Rxchar xorlw 'F' btfsc STATUS,Z goto ExtVersion ; ':GVF#' is Autostar only call WaitHash call SendQueries goto Main ExtVersion call WaitHash ; Autostar extended version call SendVersion goto Main ; Report Azimuth - send '000*00#': ; Azimuth call GetHash bnz Main call One0 Az2 call Double0 movlw '*' call Txchar call DZHash goto Main ; Report RA - send '00:00.0#': ; RA call GetHash bnz Main call Double0 movlw ':' call Txchar call Double0 movlw '.' call Txchar movlw '0' call Txchar call SendHash goto Main ; Report Declination or Site Latitude - send '+00*00#': ; Dec call GetHash bnz Main movlw '+' call Txchar goto Az2 ; S command = Set Information: ; SetInfo call WaitHash movlw '1' call Txchar ; return Valid to all commands goto Main ; F command = Focus Control: ; Focus_Command call WaitHash goto Main ; U command = Toggle the Precision: ; Ucommand goto Main ; no response required ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; ; SUBROUTINES ; ; ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Wait for the next character. ; Returns with zero set if terminator is received, clear otherwise: ; GetHash call Rxchar xorlw '#' return ; Continue to receive characters until the terminator arrives: ; WaitHash call GetHash btfss STATUS,Z goto WaitHash return ; Send my software version number as reply: ; SendVersion movlw 'V' call Txchar movlw '1' call Txchar movlw '.' call Txchar movlw '0' goto Txchar ; Send '???#' as a reply: ; SendQueries movlw '?' call Txchar movlw '?' call Txchar movlw '?' call Txchar goto SendHash ; Send '00:00:00#' as a reply: ; SendZeros call Double0 movlw ':' call Txchar call Double0 movlw ':' call Txchar DZHash call Double0 SendHash movlw '#' goto Txchar ; and return ; Initialize the interrupt process ; IntInit call IntsOff bcf INTCON,T0IF ; clear TMR0 interrupt flag movlw TMR0RELOAD movwf TMR0 ; Shorten cycle by required amount bsf INTCON,T0IE ; Enable TMR0 interrupt bsf INTCON,GIE ; Set global interrupt enable retlw 0 ; Turn off all interrupts: ; IntsOff bcf INTCON,GIE btfsc INTCON,GIE ; check that it worked goto IntsOff ; repeat if not return ; Wait for and receive a byte over the serial link from the USB chip: ; Rxchar btfss Flags,RXRDY goto Rxchar bcf Flags,RXRDY ; consume character movf RxByte,w return ; Send two zeros: ; Double0 movlw '0' call Txchar One0 movlw '0' ; Transmit a character over the serial link to the USB chip: ; Txchar btfsc Flags,TXBUSY goto Txchar ; wait while busy movwf TxByte movlw 0xff movwf TxByte2 bcf STATUS,C ; will be the start bit rlf TxByte,f rlf TxByte2,f movlw 12 movwf TxBits ; one frame = 11 bits bsf Flags,TXBUSY ; start transmission return end