Let me outline the solution I have in mind. There are two parts to the program. The first part is generating the encoder sequence at a set frequency. The second part is reading from an analog input, perform A/D conversion, and translating the result to a frequency setting used in the first part.
The way to generate the sequence is through interrupts. 50Khz is a relatively high rate and a 20Mhz PIC16F628 should give you enough headroom. The ff. steps are needed to setup:
a. Setup CCP1CON register for "compare mode, trigger special event". I.E., initialize CCP1CON to 00001011B.
b. Initialize TMR1CON with the value 00010001 (TMR1ON and 1:2 prescale). This will supply a 2.5Mhz clock to TMR1 from a 20Mhz oscillator.
c. Initialize CCPR1H,CCPR1L with the value 50. This will give an initial interrupt rate of 50KHz. To get an interrupt rate of 50Hz, the registers should be intialized to 50. To get a specific frequency, a suitable value from 50-50,000 should be entered. Notice there are 1000 values. A lookup table is best to achieve a linear relationship to the analog input. However, this exceeds the capacity of the PIC. You may have to limit the table to 500 items and interpolate in-between values.
d. Enable interrupts for the CCP1 by setting CCP1IE bit in PIE1 register. When everthing is all setup, enable interrupts by setting GIE and PEIE in the INTCON register.
The following is a sample interrupt service routine:
Code:
;=======================================
ORG 4
INT_SERVE: ; 2
MOVWF TEMP_W
SWAPF STATUS,W
CLRF STATUS ; Select RAM BANK0
MOVWF TEMP_S
MOVF PCLATH,W
MOVWF TPCLATH
CLRF PCLATH
;--------------------------------------------------
BTFSC SELECT_PIN
INCF PHASE_CNT,F
BTFSS SELECT_PIN
DECF PHASE_CNT,F
;
CALL GET_PHASE ; 8
MOVWF PORTB
;--------------------------------------------------
UPD_TIMER:
BTFSS UPD_TMR_VAL
GOTO UPD_TIMER_END
BCF UPD_TMR_VAL
;
MOVF TMR_VAL,W
MOVWF CCPR1L
MOVF TMR_VAL+1,W
MOVWF CCPR1H
UPD_TIMER_END:
;--------------------------------------------------
INT_SERVE_END:
BCF PIR1,CCP1IF
;
MOVF TPCLATH,W
MOVWF PCLATH
SWAPF TEMP_S,W
MOVWF STATUS
SWAPF TEMP_W,F
SWAPF TEMP_W,W
;
RETFIE ; 2
;=======================================
GET_PHASE:
MOVF PHASE_CNT,W
ANDLW B'00000011'
ADDWF PCL,F
RETLW B'00000101'
RETLW B'00001001'
RETLW B'00001010'
RETLW B'00000110'
;--------------------------------------------------
The ISR uses 38 instruction cycles or 7.6usec. At 50Khz interrupt rate, there are 100 or 20usec instruction steps between interrupts. This gives a utilization of 38% of CPU cycles for pulse generation.