;**************************************************************************
; Source code for Direct Digital Synthesis VFO controller
; includes mods by sjm
;
; **** NOW PORTED TO PIC16C84 ****  (see revision note for 10/01/98)
; **** NOW USING MICROCHIP MPASM ASSEMBLER (see revision note for 10/14/98)
;
; This code is available as is.
; 
; Description:
; The program main loop, (Check_Encoder) polls a rotary shaft encoder.
; If the input from the shaft encoder has changed, then direction (up/down)
; is determined.  The program then computes the corresponding
; frequency digits to be displayed on the Liquid Crystal Display. 
; This data is transfered to the LCD using a 4 bit interface. 
; A new DDS control word is then computed and transfered
; serially to the AD9850 DDS chip.
; The program then returns to the shaft encoder polling loop.
; 
; Target Controller - PIC1654A (originally)
; Program Size - 474 words, 38 words free
; Assembler - Parallax SPASM v4.2
; Author - Curtis W. Preuss - WB2V
; Initial creation 11/08/96
; Modification History
;   11/24/96 Finished debugging
;   12/14/96 Edited comments 
;   10/01/98 Ported source to PIC16C84 -- G. Heron, N2APB
;    1) Needed to shift the variables down by 5 bytes due to
;       changes in memory architecture
;    2) Needed to modify some of the indirect addressing "reads"
;       during compares to list ends (16C84 has more FSR bits)
;    3) Changed assembler directive device code
;    4) Added 2 more function sets during LCD init, per the data
;       sheets for my wacko (bargain basement) Seiko M1641 displays
;    5) Changed delays during LCD init (added wait60ms rtn),
;       (again, due to wacko Seiko M1641 LCDs?)
;    6) Removed assembler directive for reset vector and just
;       added "jmp start" at loc 0 and a new "org 5" to bypass
;       some of the interrupt vector locs at start of code space
;      7) Added explicit and separate "setb LCD_rw" in Busy_check
;       routine to more reliably read Busy bit.  (Again, perhaps
;       only because of my wacko model Seiko LCD.)
;    8) Slightly modified source formatting to make it easier 
;       (for me) to read
;    9) Comments & questions welcome! Email to: n2apb@amsat.org
;
;   10/14/98 Ported source to Microchip MPASM -- Craig B. Johnson, AA0ZZ
;    1) Generates identical HEX code as previous PIC16C84 version
;    2) Added a few comments (for me!)
;    3) Comments & questions -- Email to: johns516@tc.umn.edu
;   10/23/98
;    1) Corrected translation bug in routine SendMax1 ; sjm - SetMax1 ??
;
;**************************************************************************
           list p=16c84		; sjm was 16f84
           radix hex

Indirect   equ  0
Status     equ  3
FSR        equ  4
PortA      equ  5
PortB      equ  6
trisa	equ	0x85 ; bank 1
trisb	equ	0x86 ; bank 1

;Assign names to IO pins
AD9850_fqu equ  0              ;(PortB)Update pin on AD9850
LCD_rs     equ  1              ;(PortB)0=instruction, 1=data
LCD_rw     equ  2              ;(PortB)0=write, 1=read
LCD_e      equ  3              ;(PortB)0=disable, 1=enable
AD9850_wc  equ  5              ;(PortB)AD9850 write clock
AD9850_dat equ  7              ;(PortB)AD9850 serial data input
step_butt	equ	2	; Port A.2

LCD_Dat    equ  0x0C           ;current Display data    
AD9850     equ  0x14           ;control word for DDS chip 
OP1        equ  0x19           ;Work Space for                      
OP2        equ  0x1D           ;  the multiply routine
temp1      equ  0x1E           ;Temp storage         
temp2      equ  0x1F           ;Temp storage          
temp3      equ  0x20           ;Temp storage           
old        equ  0x21           ;old encoder input data
new        equ  0x22           ;new encoder input data
count1     equ  0x23           ;used for timing the shaft encoder 
step		equ 0x24	; frequency step size
locked		equ 0x25	; Is opto locked?

;Status Bits
C          equ  0              ;Carry
DC         equ  1              ;Digit (Half) Carry
Z          equ  2              ;Zero
RP0		equ	5	
RP1		equ	6
         
     org     0
     goto    Start             ;

     org     5
;**************************************************************************
;BusyCheck Subroutine
;
;LCD read/write operations are slooooow, this subroutine
;polls the LCD busy flag to determine if previous operations are completed.
;Note side effect that the LCD_rw and LCD_rs are left in write data mode. 

BusyCheck 

     movlw   0xF0              ;Tristate the 4 data pins
	tris PortB
;	bsf Status,RP0
;	movwf trisb
;	bcf Status,RP0
     bsf     PortB,LCD_rw      ;Raise the r/w bit to read the LCD
	bcf PortB,LCD_rs	; command mode
Busy
     bsf     PortB,LCD_e       ;
     movf    PortB,w           ;Get first nibble of input data
     movwf   temp1             ;  and save it 
     bcf     PortB,LCD_e       ;
     nop                       ;
     bsf     PortB,LCD_e       ;Get next nibble to keep LCD happy
     bcf     PortB,LCD_e       ;
     btfsc   temp1,7           ;Check for busy flag 
     goto    Busy              ;It is busy
	movlw 0x00
	tris PortB
;	bsf Status,RP0
;	movwf trisb
;	bcf Status,RP0

     bcf     PortB,LCD_rw      ;Leave LCD in Write Data mode
     bsf     PortB,LCD_rs      ; 
     return

;**************************************************************************
;Send Character to LCD Subroutine
;
;The character to be sent must have been placed in "temp2" prior to calling
;the subroutine. LCD_rw and LCD_rs must be set up prior to entry.

SendChar

     movf    temp2,w           ;Save temp2 
     movwf   temp1             ;  in temp1

     movlw   0x0F              ;
     andwf   PortB,f           ; 

     movlw   0xF0              ;
     andwf   temp2,f           ; 

     movf    temp2,w           ;
     iorwf   PortB,f           ;Load first nibble

     bsf     PortB,LCD_e       ;Transfer first nibble
     bcf     PortB,LCD_e       ;

     swapf   temp1,f           ;

     movlw   0x0F              ;
     andwf   PortB,f           ;

     movlw   0xF0              ;
     andwf   temp1,f           ;Clear data nibble

     movf    temp1,w           ;
     iorwf   PortB,f           ;

     bsf     PortB,LCD_e       ;Transfer second nibble
     bcf     PortB,LCD_e       ;

     return

;**************************************************************************
;BCD increment
;
;This routine does a binary coded decimal increment to the values in LCD_Dat.
;On entry the FSR register must point to the LCD_Dat digit to be incremented. 
;If the result is over 30MHz the value is reset back to 30MHz.

BCDInc
     movf    Indirect,w        ; 
     movwf   temp2             ;
     movlw   0x01              ;
     addwf   temp2,f           ;    
     movf    temp2,w           ;
     movwf   temp1             ;     
     movlw   0x06              ;	sjm should this be 7 ?
     addwf   temp1,f           ;
     btfsc   Status, DC        ;See if  Digit Carry is clear
     goto    BCDIncCarry       ;Digit Carry is set, so jump
     movlw   0x0F              ;
     andwf   temp2,f           ;
     movf    temp2,w           ;
     movwf   Indirect          ;
     movlw   0x03              ;       
     subwf   LCD_Dat+0,w       ;Test for max frequency
     btfsc   Status, C         ;See if Carry is clear
     goto    SetMax            ;Carry is set, so jump
     return
BCDIncCarry
     clrf    temp2             ;
     movf    temp2,w           ;
     movwf   Indirect          ; 
     decf    FSR,f             ; 
     goto    BCDInc            ; 
SetMax
	movlw	LCD_Dat+7	
     movwf   FSR               ;
SetMax1   
     movlw   0x00              ;
     movwf   Indirect          ;
     decf    FSR,f             ;  
     movlw   0xF3              ;
     addwf   FSR,w             ;
     btfsc   Status, C         ;See if Carry is clear
     goto    SetMax1           ;Carry is set, so jump
     movlw   0x03              ; 
     movwf   Indirect          ;
     return                    ;
;**************************************************************************
;BCD decrement
;
;This routine does a binary coded decimal decrement to the values in LCD_Dat.
;On entry the FSR register must point to the LCD_Dat digit to be decremented,

BCDDec
     movf    Indirect,w        ; 
     movwf   temp2             ;
     movlw   0x01              ;
     subwf   temp2,f           ;
     btfss   Status, DC        ;See if Digit Carry is set
     goto    BCDDecCarry       ;Digit Carry is clear, so jump

     movf    temp2,w           ;
     movwf   Indirect          ;
     movlw   0xFF              ;
     addwf   LCD_Dat+0,w       ;  
     btfsc   Status, C         ;See if Carry is clear
     goto    BCDDecExit        ;Carry is set, so jump to exit

     movlw   0xFF              ;  
     addwf   LCD_Dat+1,w       ; 
     btfsc   Status, C         ;See if Carry is clear
     goto    BCDDecExit        ;Carry is set, so jump to exit

     movlw   0xFF              ;
     addwf   LCD_Dat+2,w       ; 
     btfsc   Status, C         ;See if Carry is clear
     goto    BCDDecExit        ;Carry is set, so jump to exit

	movlw LCD_Dat+2
	subwf step,0
	btfss Status,Z
	goto next1
	goto SetMin

next1
     movlw   0xFF              ;
     addwf   LCD_Dat+3,w       ; 
     btfsc   Status, C         ;See if Carry is clear
     goto    BCDDecExit        ;Carry is set, so jump to exit

	movlw LCD_Dat+3
	subwf step,0
	btfss Status,Z
	goto next2
	goto SetMin

next2
     movlw   0xFF              ;
     addwf   LCD_Dat+4,w       ; 
     btfsc   Status, C         ;See if Carry is clear
     goto    BCDDecExit        ;Carry is set, so jump to exit

	movlw LCD_Dat+4
	subwf step,0
	btfss Status,Z
	goto next3
	goto SetMin

next3
     movlw   0xFF              ;
     addwf   LCD_Dat+5,w       ; 
     btfsc   Status, C         ;See if Carry is clear
     goto    BCDDecExit        ;Carry is set, so jump to exit

	movlw LCD_Dat+5
	subwf step,0
	btfss Status,Z
	goto next4
	goto SetMin

next4
     movlw   0xFF              ;
     addwf   LCD_Dat+6,w       ; 
     btfsc   Status, C         ;See if Carry is clear
     goto    BCDDecExit        ;Carry is set, so jump to exit

	movlw LCD_Dat+6
	subwf step,0
	btfss Status,Z
	goto next5
	goto SetMin

next5
     movlw   0xFF              ;
     addwf   LCD_Dat+7,w       ; 
     btfsc   Status, C         ;See if Carry is clear
     goto    BCDDecExit        ;Carry is set, so jump to exit
     goto    SetMin            ;

BCDDecExit
     return

BCDDecCarry
     movlw   0x09              ;
     movwf   temp2             ;
     movf    temp2,w           ; 
     movwf   Indirect          ; 
     decf    FSR,f             ;
     goto    BCDDec            ;

; Here we need to set the "STEP_SIZE" to 1, and all others to 0
; eg, if step_size=1kHz, then minimum freq = 1kHz.
SetMin
	clrf	LCD_Dat+0
	clrf	LCD_Dat+1
	clrf	LCD_Dat+2
	clrf	LCD_Dat+3
	clrf	LCD_Dat+4
	clrf	LCD_Dat+5
	clrf	LCD_Dat+6
	clrf	LCD_Dat+7

	movlw	0x01
	movf	step,1
	movwf	Indirect

	return


;**************************************************************************
; Delay 24ms subroutine
;

Wait24ms
     movlw   0x28              ; use 40 for 24ms wait if clock is 4Mhz
     movwf   temp1             ;
Wait24Outer
     movlw   0xC8              ; use 200 for 24 ms wait
     movwf   temp2             ;
Wait24Inner
     decfsz  temp2,f           ;
     goto    Wait24Inner       ;
     decfsz  temp1,f           ;
     goto    Wait24Outer       ;
     return

;**************************************************************************
; Delay 60ms subroutine
;
Wait60ms
     movlw   0x64              ; use 100 for 60ms wait if clock is 4Mhz
     movwf   temp1             ;
Wait60Outer
     movlw   0xC8              ; use 200 for 60ms wait
     movwf   temp2             ;
Wait60Inner
     decfsz  temp2,f           ;
     goto    Wait60Inner       ;
     decfsz  temp1,f           ;
     goto    Wait60Outer       ;
     return                    ;

;**************************************************************************
; 32 bit add
;
;The value in registers OP1 is added to the current 32 bit value in AD9850

Add32
     movf    OP1+0,w           ;
     addwf   AD9850+0,f        ;
     btfss   Status, C         ;See if Carry is set
     goto    Add1              ;Carry is clear, so jump
     incfsz  AD9850+1,f        ;
     goto    Add1              ; 
     incfsz  AD9850+2,f        ;
     goto    Add1              ;
     incf    AD9850+3,f        ;
Add1
     movf    OP1+1,w           ;
     addwf   AD9850+1,f        ;
     btfss   Status, C         ;See if Carry is set
     goto    Add2              ;Carry is clear, so jump
     incfsz  AD9850+2,f        ;
     goto    Add2              ;
     incf    AD9850+3,f        ;
Add2
     movf    OP1+2,w           ;
     addwf   AD9850+2,f        ;
     btfss   Status, C         ;See if Carry is set
     goto    Add3              ;Carry is clear, so jump
     incf    AD9850+3,f        ;
Add3    
     movf    OP1+3,w           ; 
     addwf   AD9850+3,f        ; 
     return                    ;

;**************************************************************************
; Adjust cursor position
MoveCursor
	movf	step,w		; cursor position
	addlw	0x77
	movwf   temp2             ;
	call    BusyCheck         ;
	bcf     PortB,LCD_rs      ; Set LCD for instruction write
	call    SendChar          ;
	return


;**************************************************************************
;Write Data
;
;This subroutine does two things:
; (1) it sends the contents LCD_dat to the LCD,
;     (LCD_Dat must contain BCD digits)
; (2) the contents of AD9850 (40 bits) are serial shifted
;     into the AD9850 module

WriteData

     movlw   0x82              ; LCD position for first digit
     movwf   temp2             ;
     call    BusyCheck         ;
     bcf     PortB,LCD_rs      ; Set LCD for instruction write
     call    SendChar          ;

     movf    LCD_Dat+0,w       ;  
     movwf   temp2             ;
     movlw   0x20              ;Send a space if first digit is zero
     iorwf   temp2,f           ;
     movlw   0x20              ;Set up for space check
     subwf   temp2,w           ;Subtract to compare
     btfsc   Status, Z         ;See if Zero is clear (not a space)  
     goto    Wd2               ;Zero is set, so go send the space
     movlw   0x10              ;Zero is clear, so convert BCD 
     iorwf   temp2,f           ;  to ASCII
Wd2
     call    BusyCheck         ;
     call    SendChar          ;Send 10Mhz digit

     movf    LCD_Dat+1,w       ;
     movwf   temp2             ;
     movlw   0x30              ;
     iorwf   temp2,f           ;
     call    BusyCheck         ;
     call    SendChar          ;Send 1Mhz digit


     movlw   0x2E              ;
     movwf   temp2             ;
     call    BusyCheck         ;  
     call    SendChar          ;Send a period (comma = 2C)

     movf    LCD_Dat+2,w       ; 
     movwf   temp2             ;
     movlw   0x30              ;
     iorwf   temp2,f
     call    BusyCheck         ;
     call    SendChar          ;Send a 100KHz digit

     movf    LCD_Dat+3,w
     movwf   temp2
     movlw   0x30
     iorwf   temp2,f
     call    BusyCheck         ;Send 10 KHz digit
     call    SendChar

     movf    LCD_Dat+4,w 
     movwf   temp2
     movlw   0x30
     iorwf   temp2,f
     call    BusyCheck
     call    SendChar          ; Send 1Khz digit


;     movlw   0x2E
;     movwf   temp2
;     call    BusyCheck
;     call    SendChar          ; Send a period

     movf    LCD_Dat+5,w       ; 
     movwf   temp2
     movlw   0x30
     iorwf   temp2,f
     call    BusyCheck
     call    SendChar          ; Send 100Hz digit

     movf    LCD_Dat+6,w       ; 
     movwf   temp2
     movlw   0x30
     iorwf   temp2,f
     call    BusyCheck         ;
     call    SendChar          ; Send 10Hz digit

     movf    LCD_Dat+7,w 
     movwf   temp2
     movlw   0x30
     iorwf   temp2,f
     call    BusyCheck 
     call    SendChar          ; Send 1Hz digit

;     movlw   ' '
;     movwf   temp2
;     call    BusyCheck
;     call    SendChar         
     movlw   'M'
     movwf   temp2
     call    BusyCheck
     call    SendChar         
     movlw   'H'
     movwf   temp2
     call    BusyCheck
     call    SendChar         
     movlw   'z'
     movwf   temp2
     call    BusyCheck
     call    SendChar         

; Display opto locked state

	movlw   0xC2              ; LCD position for char 3, 2nd line
	movwf   temp2             ;
	call	BusyCheck         ;
	bcf     PortB,LCD_rs      ; Set LCD for instruction write
	call    SendChar          ;

	movf	locked,0	; get locked state, and put in w
	sublw	0x00
	btfss	Status,Z	
	goto	display_lock

	; blank second line

	movlw   ' '
	movwf   temp2
	call    BusyCheck
	call    SendChar         
	movlw   ' '
	movwf   temp2
	call    BusyCheck
	call    SendChar         
	movlw   ' '
	movwf   temp2
	call    BusyCheck
	call    SendChar         
	movlw   ' '
	movwf   temp2
	call    BusyCheck
	call    SendChar         
	movlw   ' '
	movwf   temp2
	call    BusyCheck
	call    SendChar         
	movlw   ' '
	movwf   temp2
	call    BusyCheck
	call    SendChar         

	goto	end_lock
	
display_lock
	movlw   'L'
	movwf   temp2
	call    BusyCheck
	call    SendChar         
	movlw   'o'
	movwf   temp2
	call    BusyCheck
	call    SendChar         
	movlw   'c'
	movwf   temp2
	call    BusyCheck
	call    SendChar         
	movlw   'k'
	movwf   temp2
	call    BusyCheck
	call    SendChar         
	movlw   'e'
	movwf   temp2
	call    BusyCheck
	call    SendChar         
	movlw   'd'
	movwf   temp2
	call    BusyCheck
	call    SendChar         
end_lock
	call	MoveCursor

WriteAD9850
;     clrf    PortB             ; Clear PortB
     movlw   0x05              ; Send 5 bytes
     movwf   temp3             ;   to AD9850
;     movlw   0x00              ; 
;     tris    PortB             ; Enable PortB
;sjm     movlw   0x13              ; Point at AD9850+0
     movlw   AD9850+0
     movwf   FSR
NextByte
     movf    Indirect,w        ; 
     movwf   temp1 
     movlw   0x08              ; set bit counter to 8
     movwf   temp2
NextBit
     rrf     temp1,f
     btfss   Status, C         ;See if carry is set
     goto    Send0             ;Carry is clear, so jump
     bsf     PortB,AD9850_dat
     bsf     PortB,AD9850_wc   ; toggle write clock
     bcf     PortB,AD9850_wc   ; (repeated 40 times)
     goto    Break
Send0
     bcf     PortB,AD9850_dat
     bsf     PortB,AD9850_wc
     bcf     PortB,AD9850_wc
Break
     decfsz  temp2,f
     goto    NextBit
     incf    FSR,f
     decfsz  temp3,f
     goto    NextByte
     bsf     PortB,AD9850_fqu  ; send load signal to AD9850
     bcf     PortB,AD9850_fqu  ; Clear after last data dbit is written
     return

;***************************************************************************  
;7 Digit BCD by 32 bit binary mulitply
;
;The 7 BCD digits stored in LCD_dat are each multiplied by a precalculated digit
;weight, (Digit weights assume a 66.666MHz input clock). The sum of all 7
;digits times their weight is stored in the AD9850 registers.

; sjm - digit weights for a 66.666MHz clock
; calculate weight using: (freq * 2^32) / clk
; where freq and clk are both in MHz.

; 10's		284
; 100's		192A
; 1k		FBA9
; 10k		9D49B
; 100k		624E13
; 1M		3D70CC1
; 10M		26667F90

; sjm For a 66.000 MHz clk, we have:
; 1		41
; 10		28A
; 100		196B
; 1k		FE33
; 10k		9EE00
; 100k		634C06
; 1M		3E0F83E
; 10M		26C9B26C


Mult
     clrf    temp1  
     clrf    AD9850+0
     clrf    AD9850+1
     clrf    AD9850+2
     clrf    AD9850+3
     clrf    AD9850+4

;sjm
Mult1
	movlw 	0x41
	movwf	OP1+0
	clrf	OP1+1
	clrf	OP1+2
	clrf	OP1+3
	movf	LCD_Dat+7,w
	movwf	OP2
	goto	Go

Mult10
     movlw   0x8A		; sjm was 84
     movwf   OP1+0
     movlw   0x02
     movwf   OP1+1
     clrf    OP1+2  
     clrf    OP1+3  
     movf    LCD_Dat+6,w       ;
     movwf   OP2               ; 
     goto    Go
Mult100
     movlw   0x6B		; sjm was 2A
     movwf   OP1+0             ;
     movlw   0x19              ;
     movwf   OP1+1
     clrf    OP1+2
     clrf    OP1+3  
     movf    LCD_Dat+5,w       ;
     movwf   OP2
     goto    Go
Mult1K
     movlw   0x33		; sjm was A9
     movwf   OP1+0             ;
     movlw   0xFE		; sjm was FB
     movwf   OP1+1
     clrf    OP1+2
     clrf    OP1+3
     movf    LCD_Dat+4,w       ;
     movwf   OP2
     goto    Go
Mult10K
     movlw   0x00		; sjm was 9B
     movwf   OP1+0
     movlw   0xEE		; sjm was D4
     movwf   OP1+1
     movlw   0x09
     movwf   OP1+2
     clrf    OP1+3             ; 
     movf    LCD_Dat+3,w       ; 
     movwf   OP2
     goto    Go
Mult100K
     movlw   0x06		; sjm was 13
     movwf   OP1+0
     movlw   0x4C		; sjm was 4E
     movwf   OP1+1
     movlw   0x63		; sjm was 62
     movwf   OP1+2
     clrf    OP1+3
     movf    LCD_Dat+2,w       ; 
     movwf   OP2               ; 
     goto    Go
Mult1M
     movlw   0x3E		; sjm was C1
     movwf   OP1+0
     movlw   0xF8		; sjm was 0C
     movwf   OP1+1
     movlw   0xE0		; sjm was D7
     movwf   OP1+2
     movlw   0x03
     movwf   OP1+3
     movf    LCD_Dat+1,w        ; 
     movwf   OP2                ;
     goto    Go
Mult10M
     movlw   0x6C		; sjm was 90
     movwf   OP1+0
     movlw   0xB2		; sjm was 7F
     movwf   OP1+1
     movlw   0xC9		; sjm was 66
     movwf   OP1+2
     movlw   0x26
     movwf   OP1+3
     movf    LCD_Dat+0,w       ;
     movwf   OP2               ;
     goto    Go
Go
     movlw   0x04 
     movwf   temp2      
DigitLoop
     bcf     Status, C         ;Clear Carry bit
     rrf     OP2,f             ;Rotate right (through carry)
     btfss   Status, C         ;See if Carry is set
     goto    NoCarry           ;Carry is clear, so jump
     call    Add32
NoCarry
     bcf     Status, C         ;Clear Carry bit
     rlf     OP1+0,f           ;Rotate left through carry
     rlf     OP1+1,f           ;
     rlf     OP1+2,f           ;
     rlf     OP1+3,f           ;
     decfsz  temp2,f 
     goto    DigitLoop
     incf    temp1,f

;sjm
     movlw   0x01
     subwf   temp1,w
     btfsc   Status, Z         ;See if Zero is clear 
     goto    Mult10           ;Zero is set, so jump

     movlw   0x02	; sjm was 1
     subwf   temp1,w
     btfsc   Status, Z         ;See if Zero is clear 
     goto    Mult100           ;Zero is set, so jump

     movlw   0x03	; sjm was 2
     subwf   temp1,w
     btfsc   Status, Z         ;See if Zero is clear
     goto    Mult1K            ;Zero is set, so jump  

     movlw   0x04	; sjm was 3
     subwf   temp1,w
     btfsc   Status, Z         ;See if Zero is clear
     goto    Mult10K           ;Zero is set, so jump

     movlw   0x05	; sjm was 4
     subwf   temp1,w
     btfsc   Status, Z         ;See if Zero is clear
     goto    Mult100K          ;Zero is set, so jump

     movlw   0x06	; sjm was 5
     subwf   temp1,w
     btfsc   Status, Z         ;See if Zero is clear
     goto    Mult1M            ;Zero is set, so jump

     movlw   0x07	; sjm was 6
     subwf   temp1,w
     btfsc   Status, Z         ;See if Zero is clear
     goto    Mult10M           ;Zero is set, so jump
     return

;**************************************************************************
;Initialize PIC controller

Start
     clrf    PortA             ; Clear data Port A
     clrf    PortB             ; Clear data Port B

;	bcf Status,RP0
;	bcf Status,RP1

     movlw   0x00              ;
	tris PortB
;	bsf Status,RP0
;	movwf trisb
;	bcf Status,RP0

     movlw   0x0F		; PA4 = output, PA0-PA3 = input
	tris PortA
;	bsf Status,RP0
;	movwf trisa
;	bcf Status,RP0

     movlw   0x02
     movwf   LCD_Dat+0
     movlw   0x01
     movwf   LCD_Dat+1
     movlw   0x00
     movwf   LCD_Dat+2
     movlw   0x00
     movwf   LCD_Dat+3
     movlw   0x00
     movwf   LCD_Dat+4
     movlw   0x00
     movwf   LCD_Dat+5
     movlw   0x00
     movwf   LCD_Dat+6
     movlw   0x00
     movwf   LCD_Dat+7

     clrf    count1

Init_LCD:

     call    Wait60ms          ; Wait for LCD to power up

     movlw   0x30
     movwf   PortB
     bsf     PortB,LCD_e       ; 
     bcf     PortB,LCD_e

     call    Wait60ms          ; 

     movlw   0x30              ; func set + enable to LCD
     movwf   PortB
     bsf     PortB,LCD_e
     bcf     PortB,LCD_e       ; 

     call    Wait60ms          ;

     movlw   0x28              ; 4bit_mode instruction + enable
     movwf   PortB
     bsf     PortB,LCD_e
     bcf     PortB,LCD_e
     call    Wait60ms

     movlw   0x0E              ; Display on, cursor on, blink off
     movwf   temp2
     call    BusyCheck 
     bcf     PortB,LCD_rs
     call    SendChar

     movlw   0x01              ;Clear display
     movwf   temp2
     call    BusyCheck
     bcf     PortB,LCD_rs
     call    SendChar

     movlw   0x06              ; Increment display after write
     movwf   temp2
     call    BusyCheck
     bcf     PortB,LCD_rs
     call    SendChar
    

     call    Mult
     call    Wait24ms          ; allow AD9850 clock time to start
     call    Wait24ms          ;
     call    WriteData         ; side effect reset power down bits of AD9850
     call    WriteData         ; load the initial display value
    

     movf    PortA,w           ; get encoder value
     movwf   temp2
     movlw   0x03
     andwf   temp2,w           ; isolate direction bits
     movwf   old               ; save initial values

	movlw	LCD_Dat+4	; Set initial step size to 1kHz
	movwf	step

	clrf	locked		; enable opto
	movlw 	0x1F		; set PA.4 high to turn on transistor
	movwf	PortA


	call MoveCursor

;**************************************************************************   
;Check encoder
; PortA.0 shaft encoder output A
; PortA.1 shaft encoder output B
; PortA.2 step button

ChkEncoder

; debounce lock switch
	movf	PortA,w
	movwf	temp2
	btfsc	temp2,3
	goto	step_sw

	call	Wait60ms
	call	Wait60ms

	movf	PortA,w
	movwf	temp2
	btfsc	temp2,3
	goto	step_sw


; toggle locked state
	movf	locked,0	; get locked state, and put in w
	sublw	0x00
	btfss	Status,Z
	goto	clear_lock

; set locked state	
	movlw	0x01
	movwf	locked
	goto	xyz
	
clear_lock
	clrf	locked
xyz
	goto CeWrite


; debounce step switch
step_sw
	movf    PortA,w           ;Get encoder value
	movwf   temp2             ;Double latch the input
	btfsc	temp2,2
	goto	getenc
	
	call Wait60ms
	call Wait60ms

	movf    PortA,w           ;Get encoder value
	movwf   temp2             ;Double latch the input
	btfsc	temp2,2
	goto	getenc
	
	decf step,1		; dec f and put result back in f
	movlw LCD_Dat+1		
	subwf step,0		; f-w, don't put result back in f
	btfss   Status, Z 	; if Z=1, result of sub was 0
	goto abcd
	movlw LCD_Dat+7	
	movwf step

abcd	goto CeWrite

getenc
	; if locked, don't get new encoder value
	movf	locked,0	; get locked state, and put in w
	sublw	0x00
	btfss	Status,Z	
	goto	ChkEncoder


     movlw   0x03
     andwf   temp2,w
     movwf   new
     xorwf   old,w
     btfsc   Status, Z         ;See if Zero is clear
     goto    ChkEncoder        ;Zero is set, so jump

	movf step,0	; put step in W
	movwf FSR
CeGo

     bcf     Status, C         ;Clear Carry bit
     rlf     old,f             ;Rotate left
     movf    new,w
     xorwf   old,f             ;Determine direction
     btfsc   old, DC           ;See if Digit Carry is clear
     goto    CeUp              ;Digit Carry is set, so jump
     call    BCDDec            ;Calculate new LCD display
     call    Mult              ;Calculate new AD9850 control word
     goto    CeWrite

CeUp
     call    BCDInc            ; calculate new LCD display
     call    Mult              ; calculate new AD9850 control word

CeWrite
     call    WriteData
     movf    new,w
     movwf   old
     goto    ChkEncoder        ; continue polling the encoder

     END
