LIST P=16F84, F=INHX8M ; ERRORLEVEL 2 __CONFIG _CP_OFF & _WDT_OFF & _XT_OSC ; Program ddsxx.ASM ; Date 19990618 ; Author Charlos Potma ; charlos.potmarivm.nl ; ; Program to control an Analog Devices AD9850 DDS. ; The DDS frequency is entered through a keyboard. ; Frequency must be entered in a xxyyyzzz format ; where xx is 00-50 MHz and yyyzzz is 0-999999 Hz. ; (Assuming a 100MHz AD9850 clock) ; Frequency is limited to the range 0.1-40MHz. ; Frequency can be incremented or decremented using ; a Bourns ECWIJ-B24-AC0024 encoder. ; The AD9850 control word is calculated using ; pre-determined weight factors for all seperate ; xxyyyzzz digits. ; ; Program reads 4x4 keyboard using PortB pin 0 ; interrupt line. The keyboard is read using another ; PIC (keyb441.asm). This PIC scans the keyboard on ; interrupt and sends a number of pulses through the PIC's ; RA4 pin. This pin must be connected to the RB0 pin of ; this PIC. If a RB0 interrupt occurs, a counter ; is incremented and the RTCC is started. It is setup to ; overflow in two milliseconds, unless interrupted by ; RB0. If a RTCC interrupt occurs, it is assumed that no ; more RB0 interrupts will occur. The number of pulses ; counted minus one is the keyboard code received. ; Timing is quite relaxed here. It may take ; as long as 40 milliseconds (keyboard debounce time) ; plus (1 [trigger pulse] +16 [keyboard code pulses] ; +2 (time-out time])=59 milliseconds to receive the complete ; pulse train from the moment a key is pressed. ; ; LCD routines have been modified from Peer Ouwehand's ; (http://www.iaehv.nl/users/pouweha/) ; ; Note that LCD data is written to lower nibble of PortA without ; regard for RA4 use. This should not be a problem as long as ; nibbles sent to the LCD are <= 0x0f. ; ; Program reads an incremental encoder connected to PortB, ; pins 4 and 5. Normally, pin 4 is enabled as input. PortB ; interrupts on change are enabled. Only interrupts generated ; by a falling edge on pin 4 are honored. Encoder status is ; determined by making pin 5 an input, checking pin 5 level and ; making pin 5 an output again. ; ; Program calculates a 32-bit word which is sent serially to ; an AF9850 DDS. Calculation is based on a 100MHz clock crystal. ; ; Frequency must be entered in a xxyyyzzz format. No enter key ; function is provided. ; ; Frequency can be swept up/down using the A/B keys. Sweeping is ; stopped by pressing any key, or rotating the encoder. ; Also a 'wobble' function is provided using the C key. ; Wobbling means repeatedly sweeping up/down. Wobbling is done ; in exactly 250 steps. The program writes the step value serially ; to an eight-bit shift register. This register functions as a ; cheap DAC using a R-2R network connected to the register ; parallel output. This voltage can then be used for the ; horizontal sweep of an oscilloscope trace. If the output of the ; generator is connected to a DUT, and the output of the ; DUT to a log-detector, and the output of the detector is ; connected to the Y-input of an oscilloscope, this setup can be ; used for making measurements on filters etc. ; When wobbling starts, the step-counter is set to 125. This means ; that the DAC output voltage is always at half-range at the ; frequency where wobbling starts. When LCD update is switched off ; (see below) the frequency displayed is the frequency at half-range. ; During wobbling, the encoder may be rotated and the mid-way ; frequency id updated accordingly. This has the effect that the ; centre-frequency during wobbling is always centered on the ; oscilloscope screen. ; ; Key D is used to choose the following functions: ; 0: select frequency step: 1Hz - 10kHz ; 1: select step multiplier: 1-9. This can result in ; step sizes between 1Hz and 90kHz. ; 3: select yes/no LCD update during sweep/wobble. Not updating ; the LCD results in faster wobbling. However, ; encoder rotation will result in an updated display. ; 6: select frequency storage memory location:0-2 ; 7: select frequency recall memory location:0-2 ; (not all functions could be realised in the code-space available) ; ; Most of the subroutines in this program have been replaced ; with in-line code. Less structure and readability, but ; necessary to get the minimum of features realised. ; ; ; Used portions of code written by Mick Hodges ; (mick@g4ope.demon.co.uk) developed for ; controlling a AD7008 DDS. ; ;***************************************************************************** ; Fosc = 4MHz ; Cycle_time = 1/Fosc / 4 = 1uSec ;***************************************************************************** ; Modify next line to reflect your MPLAB setup ; include ;***************************************************************************** ; Equates, I/O, vars ;***************************************************************************** RESET_V EQU 0x0000 ; Address of RESET Vector ISR_V EQU 0x0004 ; Address of Interrupt Vector OSC_FREQ EQU D'4000000' ; Oscillator Frequency is 4 MHz LCD_LINE0 EQU 0x000 ; Address of first location in upper LCD line LCD_LINE1 EQU 0x040 ; Address of first location in lower LCD line LCD_E EQU 1 ; LCD Enable control line, PortB,pin 1 LCD_RW EQU 7 ; LCD Read/Write control line, PortB,pin 7 LCD_RS EQU 6 ; LCD Register-Select control line, PortB,pin 6 AD9850_FQUP EQU 4 ; PORTA, pin 4 AD9850 Frequency update pin AD9850_CLOCK EQU 2 ; PORTB, pin 2 AD9850 Frequency update clock pin AD9850_DATA EQU 3 ; PORTB, pin 3 AD9850 Frequency update data pin SREG_UPDATE EQU 4 ; PORTA, pin 4 (Shared with AD9850 FQUP) SREG_DATA EQU 0 ; PORTA, pin 0 (Shared with LCD data pin) SREG_CLOCK EQU 5 ; PORTB, pin 5 (Shared with encoder input) ; BYTE TO ASCII 0-9 : ADD 0x30 DECAD EQU 0x30 FCHARMAX EQU d'8' ; Maximum number of frequency input characters, ; assuming an 8 digit input format TCHARSTRT EQU 0x015 ; This is the location of the first frequency ; input character, temporary string FCHARSTRT EQU 0x01E ; This is the location of the first frequency ; input character TWSTART EQU 0x028 ; This is the location of the first AD9850 control ; word byte KEYA EQU d'15' ; Keyboard code, (A), sweep-up KEYB EQU d'14' ; Keyboard code, (B), sweep-down KEYC EQU d'13' ; Keyboard code, (C), wobble KEYD EQU d'12' ; Keyboard code, (D), function ; D-0 Step size ; D-1 Step mult ; D-2 Step wait (not used) ; D-3 Display update y/n ; D-4 offset value (not used) ; D-5 offset +/- (not used) ; D-6 store # ; D-7 recall # ; D-8 (not used) ; D-9 (not used) KEYENT EQU d'10' ; Keyboard code, (#), enter KEYPNT EQU d'11' ; Keyboard code, (*), decimal point ;***************************************************************************** ; Equates, registers ;***************************************************************************** ; 0x00C is FIRST location in RAM LCD_TEMP EQU 0x00C ; LCD subroutines internal use COUNT EQU 0x00D ; A counter used in delay routines DELAY EQU 0x00E ; Used in DELAYxxx routines X_DELAY EQU 0x00F ; Used in X_DELAYxxx routines WTEMP EQU 0x010 ; Temp for W _W EQU 0x011 ; TEMPORARY STORE FOR W _STATUS EQU 0x012 ; TEMPORARY STORE FOR STATUS PULSECNT EQU 0x013 ; Number of RB0 interrupts KEYIN EQU 0x014 ; Input key code T10M EQU 0x015 ; Input frequency characters, temporary storage T1M EQU 0x016 ; T100K EQU 0x017 ; We allow for a 2.6 entry format: T10K EQU 0x018 ; 2 digits for MHz, a decimal point T1K EQU 0x019 ; and 6 digits for frequency in Hz T100H EQU 0x01A T10H EQU 0x01B ; Note: do not move Txx to another location T1H EQU 0x01C ; without also changing TCHARSTRT ! FSTEP EQU 0x01E ; Frequency step value (coded: 1=1Hz, ; 2=10Hz, 3=100Hz, 4=1kHz, 5=10kHz) SWEEP EQU 0x01F ; Sweep/wobble: 0000=no sweep ; 0001=sweep-up ; 0010=sweep-down ; 0100=wobble-up (repeat up/down) ; 1000=wobble-down (repeat up/down) NSTEPS EQU 0x020 ; Steps counter to use in wobble, ; wobbling is from start-frequency with ; NSTEPS of FSTEP up, then repeat down, ; then up etc, until interrupted FUNCTION EQU 0x021 ; Function code reading flag (bit 0) DISPLAYUPDATE EQU 0x021 ; Yes/No update display (bit 1) ENTERFREQ EQU 0x021 ; Entering frequency (bit 2) RB0INTFLAG EQU 0x021 ; Interrupt on RB0 seen (bit 3) FUNCTIONCODE EQU 0x022 ; Function code MULT EQU 0x023 ; Step multiplicator (1,2,5) MULTTMP EQU 0x024 ; Temporary mult ;0x025 free ;0x026 free FCHARCNT EQU 0x027 ; Counter for frequency characters PW0 EQU 0x028 ; AD9850 control word 0 PW1 EQU 0x029 ; AD9850 control word 1 PW2 EQU 0x02A ; AD9850 control word 2 PW3 EQU 0x02B ; AD9850 control word 3 ; PWx and TWx have to be in one consequitive (???) row ! ; because we use TW0 as fifth AD9850 control byte TW0 EQU 0x02C ; Temporary control word 0 TW1 EQU 0x02D ; Temporary control word 0 TW2 EQU 0x02E ; Temporary control word 0 TW3 EQU 0x02F ; Temporary control word 0 CTEMP EQU 0x00C ; Temporary storage for character ; SHARED with LCD_TEMP TTEMP EQU 0x00D ; Temporary storage for digit pointer ; SHARED with COUNT FB1 EQU 0x030 ; First location of frequency backup string FB2 EQU 0x031 FB3 EQU 0x032 FB4 EQU 0x033 FB5 EQU 0x034 FB6 EQU 0x035 FB7 EQU 0x036 FB8 EQU 0x037 ; 0x038 - 0x04F free ; !!! 0x02F is LAST location in RAM (16C84) ; !!! 0x04F is LAST location in RAM (16F84) ;***************************************************************************** ; Program start ;***************************************************************************** ORG RESET_V ; RESET vector location RESET GOTO START ;***************************************************************************** ; Interrupt service routine. ;***************************************************************************** ORG ISR_V ; Interrupt vector location MOVWF _W ; Save registers SWAPF STATUS,W MOVWF _STATUS BCF STATUS,RP0 ; Select bank 0 BTFSC INTCON, RBIF ; Interrupt from encoder? GOTO ENCINTSERV ; yes NEXTINT BTFSS INTCON, INTF ; Interrupt from RB0 (keyboard)? GOTO TMR0INTSERV ; no, must be from TMR0 interrupt then GOTO RB0INTSERV ; yes ;***************************************************************************** ; Initialize processor registers ;***************************************************************************** START ; POWER_ON Reset (Beginning of program) CLRF STATUS ; Do initialization, Select bank 0 CLRF PCLATH ; Keep in lower 2KByte CLRF PORTA ; ALL PORT output should be low. CLRF PORTB BSF STATUS, RP0 ; Select bank 1 MOVLW B'00000000' ; PortA all output MOVWF TRISA MOVLW B'00010001' ; PortB: RB4,0 input, RB7,6,5,3,2,1 output MOVWF TRISB MOVLW B'11000010' ; Set option register in one go MOVWF OPTION_REG ; See below ;BSF OPTION_REG, NOT_RBPU ; Disable PORTB pull-ups ;BSF OPTION_REG, INTEDG ; Interrupt on RB0 rising edge ;BCF OPTION_REG, T0CS; Increment TMR0 on internal clock ;BCF OPTION_REG, PSA ; Prescaler is assigned to TMR0 ;BCF OPTION_REG, PS2 ; Prescaler set to 010 (1:8) ;BSF OPTION_REG, PS1 ; Time-out time will be ;BCF OPTION_REG, PS0 ; app. 256x8uSec = 2mSec. BCF STATUS, RP0 ; Select bank 0 CALL LCDINIT ; Initialize LCDisplay ;MOVLW 'P' ;CALL LCDPUTCHAR ;MOVLW 'A' ;CALL LCDPUTCHAR ;MOVLW '3' ;CALL LCDPUTCHAR ;MOVLW 'C' ;CALL LCDPUTCHAR ;MOVLW 'K' ;CALL LCDPUTCHAR ;MOVLW 'R' ;CALL LCDPUTCHAR CALL SECWAIT ; Wait for AD9850 Clock to start CALL SECWAIT MOVLW B'10011000' ; Set intcon register in one go MOVWF INTCON ; See below ;BCF INTCON, INTF ; Clear RB0 interrupt flag ;BCF INTCON, T0IF ; Clear TMR0 interrupt flag ;BSF INTCON, INTE ; Enable interrupt on RB0 change ;BSF INTCON, RBIE ; Enable PortB (Encoder) interrupt on change ;BSF INTCON, GIE ; Global Interrupt Enable CLRF FSTEP ; FSTEP = 1Hz MOVLW d'1' ; Step multiplicator is 1 MOVWF MULT CLRF FUNCTION ; No function prompt, update display yes. CLRF FUNCTIONCODE CLRF PULSECNT ; Next time we start with an empty counter CLRF SWEEP ; No sweep/wobble ;***************************************************************************** ;Initialize strings,LCD, calculate AD9850 control word, program AD9850 ;***************************************************************************** MOVLW 0x00 ; start of eeprom to W MOVWF EEADR ; move to eeadr register CALL READPARS ; Read first frequency from eeprom CALL FSTR2WORD ; Frequency string to control word CALL CNTRLAD9850 ; Send control bits to AD9850 CALL CNTRLAD9850 ; And again, because after startup, the ; AD9850 is most probably in an undetermined ; state CALL TSTR2LCD ; Send frequency string to LCD CALL MHZ ;GOTO LOOP ;***************************************************************************** LOOP BTFSC RB0INTFLAG, 3 ; Did we have an interrupt on RB0? GOTO LOOP ; Yes, loop until TMR0 says valid entry MOVF SWEEP, W ; Sweep/wobble flags on ? BTFSC STATUS, Z GOTO LOOP ; no,loop until interrupted SWP BCF INTCON, GIE ; Disable interrupts BTFSC INTCON, GIE ; Really disabled? GOTO SWP ; No, try again BTFSS SWEEP, 0 ; Sweep-up? GOTO CHKDWN ; no, GOTO INCFR ; yes, increment frequency CHKDWN BTFSS SWEEP, 1 ; Sweep-down? GOTO CHKWUP ; no, GOTO DECFR ; yes, decrement frequency CHKWUP BTFSS SWEEP, 2 ; Wobble-up? GOTO CHKWD ; no, GOTO WUP ; yes, do wobble-up stuff CHKWD BTFSS SWEEP, 3 ; Wobble-down? GOTO CHKDWN ;=== WDOWN MOVF NSTEPS, W SUBLW d'1' BTFSC STATUS, Z GOTO WP DECFR DECF NSTEPS CALL FSTRDEC GOTO CONTSND WP BSF SWEEP, 2 BCF SWEEP, 3 GOTO CONTSND WUP MOVF NSTEPS, W SUBLW d'250' BTFSC STATUS, Z GOTO WDN INCFR INCF NSTEPS CALL FSTRINC GOTO CONTSND WDN BCF SWEEP, 2 BSF SWEEP, 3 GOTO CONTSND ;=== ;WDOWN DECFSZ NSTEPS ; yes, wobbling-down, decrement counter ; GOTO DECFR ; no-overflow, decrement frequency ; BCF SWEEP, 3 ; overflow, clear wobble-down bit, ; BSF SWEEP, 2 ; set wobble-up bit, ; GOTO DECFR ; ;WUP INCFSZ NSTEPS ; Wobbling-up, increment counter ; GOTO INCFR ; no-overflow, increment frequency ; BCF SWEEP, 2 ; overflow, clear wobble-up bit, ; BSF SWEEP, 3 ; set wobble-down bit, ; DECF NSTEPS ; GOTO CONTSND ; ;INCFR CALL FSTRINC ; Increment frequency ; GOTO CONTSND ; ;DECFR CALL FSTRDEC ; Decrement frequency CONTSND CALL WDAC ; update DAC CALL FSTR2WORD ; Frequency string to control word CALL CNTRLAD9850 ; Send control bits to AD9850 BTFSS DISPLAYUPDATE, 1; Update display? CALL TSTR2LCD ; Yes, send frequency string to LCD BSF INTCON, GIE ; No, enable interrupts GOTO LOOP ; loop again ;***************************************************************************** ; Program ends here. ; Routines follow. ;***************************************************************************** ;***************************************************************************** ; Write to shift register (used as dac) ;***************************************************************************** WDAC MOVF NSTEPS, W ; Load byte MOVWF CTEMP ; in temporary location MOVLW d'8' ; Eight bits to deal with MOVWF WTEMP DNEXTBIT RRF CTEMP, 1 ; Push next bit to carry BTFSS STATUS, C ; Carry not set? GOTO DSENDZERO ; No, send a "zero" DSENDONE BSF PORTA, SREG_DATA; Yes, send a "one", first, set data pin high BSF PORTB, SREG_CLOCK ; then, set clock pin high BCF PORTB, SREG_CLOCK ; then, set clock pin low again GOTO DDETNXTBIT ; Determine next bit to send DSENDZERO BCF PORTA, SREG_DATA; Set data pin low BSF PORTB, SREG_CLOCK ; then, set clock pin high BCF PORTB, SREG_CLOCK ; then, set clock pin low again DDETNXTBIT DECFSZ WTEMP, 1 ; Decrement bit counter, zero? GOTO DNEXTBIT ; No, handle next bit ;DSENDUPD ;BSF PORTA, SREG_UPDATE ; Set shift-register update pin high ;BCF PORTA, SREG_UPDATE ; and low again, not done here, ; is done in updating 9850, update pin shared RETURN ; with shift register ;***************************************************************************** ; Read contents of EEADR in W ;***************************************************************************** REEPROM BSF STATUS,RP0 ;bank 1 BSF EECON1,RD ;eeprom read BCF STATUS,RP0 ;bank 0 MOVF EEDATA, W RETURN ;***************************************************************************** ; Write contents of EEDATA to eeprom address EEADR ;***************************************************************************** WREEPROM BSF STATUS, RP0 ; Bank 1 BCF INTCON, GIE ; Disable Interrupts BCF EECON1, EEIF ; Clear write completion bit BSF EECON1, WREN ; Set eeprom write-enable bit NOP ; Why ? MOVLW 0x55 ; Initiate eeprom write MOVWF EECON2 MOVLW 0xAA MOVWF EECON2 BSF EECON1, WR ; Eeprom write cycle start WAITEE BTFSS EECON1, 4 ; Wait until write complete GOTO WAITEE BCF EECON1, 4 ; Reset write complete flag BCF EECON1,WREN ; Eeprom write-disable BSF INTCON, GIE ; Enable Interrupts BCF STATUS,RP0 ; Bank 0 RETURN ;***************************************************************************** ;Read next eight bytes from eeprom ;***************************************************************************** READPARS MOVLW FCHARMAX MOVWF FCHARCNT ; Set character count MOVLW TCHARSTRT MOVWF FSR ; Set character pointer CHKFCNT MOVF FCHARCNT, W ; All characters handled? BTFSC STATUS, Z RETURN ; Yes, return CALL REEPROM ; No, read character from eeprom MOVWF INDF ; And store in string INCF EEADR, 1 ; Increment eeprom address INCF FSR ; Increment character pointer DECF FCHARCNT, 1 ; Decrement character pointer GOTO CHKFCNT ;***************************************************************************** ;Write next eight bytes from eeprom ;***************************************************************************** WRITEPARS MOVLW FCHARMAX MOVWF FCHARCNT ; Set character count MOVLW TCHARSTRT MOVWF FSR ; Set character pointer CHKFCNT1 MOVF FCHARCNT, W ; All characters handled? BTFSC STATUS, Z RETURN ; Yes, MOVF INDF, W MOVWF EEDATA ; No, move character from pointer pos. to eedata CALL WREEPROM ; Write character to eeprom INCF EEADR, 1 ; Increment eeprom address INCF FSR ; Increment character pointer DECF FCHARCNT, 1 ; Decrement character counter GOTO CHKFCNT1 ;***************************************************************************** ; Send control word to AD9850, 32 bits, sent bit 0 first, ; bit31 last, plus 8 control/phase (?) bits, here set to zero ;***************************************************************************** CNTRLAD9850 MOVLW d'5' ; We have to deal with five bytes MOVWF TTEMP ; 4 control bytes and a control/phase byte MOVLW 0x00 ; Set fifth byte to: all zero's MOVWF TW0 MOVLW TWSTART ; Load location of first control word byte MOVWF FSR NEXTBYTE MOVF INDF, W ; Load byte MOVWF CTEMP ; in temporary location MOVLW d'8' ; Eight bits to deal with MOVWF WTEMP NEXTBIT RRF CTEMP, 1 ; Push next bit to carry BTFSS STATUS, C ; Carry not set? GOTO SENDZERO ; No, send a "zero" SENDONE BSF PORTB, AD9850_DATA ; Yes, send a "one", first, set data pin high BSF PORTB, AD9850_CLOCK ; then, set clock pin high BCF PORTB, AD9850_CLOCK ; then, set clock pin low again GOTO DETNXTBIT ; Determine next bit to send SENDZERO BCF PORTB, AD9850_DATA ; Set data pin low BSF PORTB, AD9850_CLOCK ; then, set clock pin high BCF PORTB, AD9850_CLOCK ; then, set clock pin low again DETNXTBIT DECFSZ WTEMP, 1 ; Decrement bit counter, zero? GOTO NEXTBIT ; No, handle next bit DECFSZ TTEMP, 1 ; Yes, decrement byte counter, zero? GOTO NBYTE ; No, next byte GOTO SENDFQUP ; Send frequency update pulse NBYTE INCF FSR, 1 ; No, set pointer to next byte GOTO NEXTBYTE SENDFQUP BSF PORTA, AD9850_FQUP ; Set frequency update pin high BCF PORTA, AD9850_FQUP ; and low again RETURN ;***************************************************************************** ; Add temporary control word to AD9850 control word ;***************************************************************************** ADDCW MOVF TW0, W ; Load TW0 ADDWF PW0, 1 ; Add to PW0 BTFSS STATUS, C ; Carry set? GOTO ADD1 ; No, goto add1 part INCFSZ PW1, 1 ; Yes, increment next byte, result zero? GOTO ADD1 ; No, goto add1 part INCFSZ PW2, 1 ; Yes, increment next byte, result zero? GOTO ADD1 ; No, goto add1 part INCF PW3 ; Yes, increment last byte, no test needed ADD1 MOVF TW1, W ; Load TW1 ADDWF PW1, 1 ; Add to PW1 BTFSS STATUS, C ; Carry set? GOTO ADD2 ; No, goto add2 part INCFSZ PW2, 1 ; Yes, increment next byte, result zero? GOTO ADD2 ; No, goto add2 part INCF PW3 ; Yes, increment last byte, no test needed ADD2 MOVF TW2, W ; Load TW2 ADDWF PW2, 1 ; Add to PW2 BTFSS STATUS, C ; Carry set? GOTO ADD3 ; No, goto add3 part INCF PW3 ; Yes, increment last byte, no test needed ADD3 MOVF TW3, W ; Load TW3 ADDWF PW3, 1 ; Add to PW3, no test needed RETURN ;***************************************************************************** ; Calculate AD9850 32 bit control word by multiplying the 8 digits with ; their respective weights, assuming a 100MHz clock ;***************************************************************************** FSTR2WORD CLRF TTEMP ; Clear digit pointer CLRF PW0 ; and AD9850 control word CLRF PW1 CLRF PW2 CLRF PW3 _1H MOVLW 0x2B ; Load 1Hz byte MOVWF TW0 ; in TW0 CLRF TW1 ; And clear remainder of word CLRF TW2 CLRF TW3 MOVF T1H, W ; Load 1Hz digit GOTO CALC ; Goto calculate part _10H MOVLW 0xAE ; Load 10Hz byte MOVWF TW0 ; in TW0 MOVLW 0x01 ; and next byte MOVWF TW1 ; in TW1 CLRF TW2 ; And clear remainder of word CLRF TW3 MOVF T10H, W ; Load 10Hz digit GOTO CALC ; Goto calculate part _100H MOVLW 0xC7 ; Load 100Hz byte MOVWF TW0 ; in TW0 MOVLW 0x10 ; and next byte MOVWF TW1 ; in TW1 CLRF TW2 ; And clear remainder of word CLRF TW3 MOVF T100H, W ; Load 10Hz digit GOTO CALC ; Goto calculate part _1K MOVLW 0xC5 ; Load 1kHz byte MOVWF TW0 ; in TW0 MOVLW 0xA7 ; and next byte MOVWF TW1 ; in TW1 CLRF TW2 ; And clear remainder of word CLRF TW3 MOVF T1K, W ; Load 1kHz digit GOTO CALC ; Goto calculate part _10K MOVLW 0xB9 ; Load 10kHz byte MOVWF TW0 ; in TW0 MOVLW 0x8D ; and next byte MOVWF TW1 ; in TW1 MOVLW 0x06 ; and next byte MOVWF TW2 ; in TW2 CLRF TW3 ; And clear remainder of word MOVF T10K, W ; Load 10kHz digit GOTO CALC ; Goto calculate part _100K MOVLW 0x37 ; Load 100kHz byte MOVWF TW0 ; in TW0 MOVLW 0x89 ; and next byte MOVWF TW1 ; in TW1 MOVLW 0x41 ; and next byte MOVWF TW2 ; in TW2 CLRF TW3 ; And clear remainder of word MOVF T100K, W ; Load 100kHz digit GOTO CALC ; Goto calculate part _1M MOVLW 0x29 ; Load 1MHz byte MOVWF TW0 ; in TW0 MOVLW 0x5C ; and next byte MOVWF TW1 ; in TW1 MOVLW 0x8F ; and next byte MOVWF TW2 ; in TW2 MOVLW 0x02 ; and next byte MOVWF TW3 ; in TW3 MOVF T1M, W ; Load 1MHz digit GOTO CALC ; Goto calculate part _10M MOVLW 0x9A ; Load 10MHz byte MOVWF TW0 ; in TW0 MOVLW 0x99 ; and next byte MOVWF TW1 ; in TW1 MOVLW 0x99 ; and next byte MOVWF TW2 ; in TW2 MOVLW 0x19 ; and next byte MOVWF TW3 ; in TW3 MOVF T10M, W ; Load 10MHz digit GOTO CALC ; Goto calculate part CALC MOVWF CTEMP ; load digit value into temporary place holder MOVLW d'4' ; 4 Bits to handle in next part MOVWF WTEMP LOOPD BCF STATUS, C ; Clear carry RRF CTEMP ; Shift out next bit of CTEMP BTFSS STATUS, C ; Carry set? GOTO NOCARRY ; No, goto no carry part CALL ADDCW ; Yes, add TW to PW NOCARRY BCF STATUS, C ; Clear carry RLF TW0, 1 ; Shift TW bytes one bit to the left RLF TW1, 1 ; meaning multiply by two RLF TW2, 1 RLF TW3, 1 DECFSZ WTEMP, 1 ; Decrement bit counter, zero? GOTO LOOPD ; No, repeat loop INCF TTEMP, 1 ; Yes, increment pointer to digit MOVF TTEMP, W ; and store in W SUBLW FCHARMAX ; If we subtract W from the max number of digits BTFSC STATUS, Z ; And test if the result is zero? RETURN ; Yes, we have handled all digits MOVF TTEMP, W ; NO, store CTEMP in W SUBLW d'7' ; If we subtract W from the number 7 BTFSC STATUS, Z ; Is the result zero? GOTO _10M ; Yes, goto digit 7 handler MOVF TTEMP, W ; NO, store CTEMP in W SUBLW d'6' ; If we subtract W from the number 6 BTFSC STATUS, Z ; Is the result zero? GOTO _1M ; Yes, goto digit 6 handler MOVF TTEMP, W ; NO, store CTEMP in W SUBLW d'5' ; If we subtract W from the number 5 BTFSC STATUS, Z ; Is the result zero? GOTO _100K ; Yes, goto digit 5 handler MOVF TTEMP, W ; NO, store CTEMP in W SUBLW d'4' ; If we subtract W from the number 4 BTFSC STATUS, Z ; Is the result zero? GOTO _10K ; Yes, goto digit 4 handler MOVF TTEMP, W ; NO, store CTEMP in W SUBLW d'3' ; If we subtract W from the number 3 BTFSC STATUS, Z ; Is the result zero? GOTO _1K ; Yes, goto digit 3 handler MOVF TTEMP, W ; NO, store CTEMP in W SUBLW d'2' ; If we subtract W from the number 2 BTFSC STATUS, Z ; Is the result zero? GOTO _100H ; Yes, goto digit 2 handler MOVF TTEMP, W ; NO, store CTEMP in W SUBLW d'1' ; If we subtract W from the number 1 BTFSC STATUS, Z ; Is the result zero? GOTO _10H ; Yes, goto digit 1 handler RETURN ;***************************************************************************** ;Decrement frequency string with step value ;***************************************************************************** FSTRDEC MOVF T10M, W ; Check first frequency character BTFSS STATUS, Z ; Zero? GOTO DECC ; No MOVF T1M, W ; Yes, check second frequency character BTFSS STATUS, Z ; Zero? GOTO DECC ; No MOVF T100K, W ; Yes, check third frequency character BTFSS STATUS, Z ; Zero? GOTO DECC ; No, continue CLRF SWEEP ; Yes, set sweep/wobble off and return RETURN DECC MOVF MULT, W MOVWF MULTTMP ; Keep mult in a safe place MOVLW FCHARMAX MOVWF FCHARCNT ; Set maximum number of characters in string MOVLW TCHARSTRT ; Set pointer to last frequency digit ADDLW FCHARMAX MOVWF CTEMP MOVF FSTEP, W ; Load fstep SUBWF CTEMP, 0 ; Correct FSR for fstep MOVWF FSR ; input character location, temporary DECF FSR DEC MOVF INDF, W ; Get character from pointer position MOVWF CTEMP MOVF MULTTMP, W SUBWF CTEMP, 1 ; Subtract mult BTFSS STATUS, DC ; Check if Digit Carry is not (!) set GOTO DECCARRY ; Yes, handle carry GOTO DCOK ; No, we don't have a carry and we are ready DCOK MOVF CTEMP, W MOVWF INDF RETURN DECCARRY MOVF MULTTMP, W MOVWF CTEMP MOVF INDF, W SUBWF CTEMP, 0 SUBLW d'10' MOVWF INDF MOVLW d'1' MOVWF MULTTMP ; Next character(s), mult is one DECFSZ FCHARCNT, 1 ; Decrement character counter, zero? GOTO NEXTCHARDEC ; No, handle next character RETURN NEXTCHARDEC DECF FSR GOTO DEC ;***************************************************************************** ;Increment frequency string with step value ;***************************************************************************** FSTRINC MOVLW FCHARMAX MOVWF FCHARCNT ; Set maximum number of characters in string MOVLW TCHARSTRT ; Set pointer to last frequency digit ;ADDLW FCHARMAX MOVWF FSR MOVF INDF, W MOVWF CTEMP MOVLW d'4' BCF STATUS, C SUBWF CTEMP, F BTFSS STATUS, C ; Is first frequency character >3 ? GOTO FIN ; No, ignore CLRF SWEEP ; Sweep and wobble off RETURN FIN MOVF MULT, W MOVWF MULTTMP ; Keep mult in a safe place MOVLW TCHARSTRT ; Set pointer to last frequency digit ADDLW FCHARMAX MOVWF CTEMP MOVF FSTEP, W ; Load fstep SUBWF CTEMP, 0 ; Correct FSR for fstep MOVWF FSR ; input character location, temporary DECF FSR INC MOVF INDF, W ; Get character from pointer position MOVWF CTEMP MOVF MULTTMP, W ADDWF CTEMP, 1 ; Add mult MOVF CTEMP, W MOVWF WTEMP MOVLW d'10' BCF STATUS, C SUBWF WTEMP, F BTFSC STATUS, C ; Is result >9? GOTO INCCARRY ; Yes, handle carry MOVF CTEMP, W ; No, we don't have a carry and we are ready MOVWF INDF RETURN INCCARRY MOVLW d'10' ; If there was a carry, this character SUBWF CTEMP, 0 ; must be set to value - 10 MOVWF INDF MOVLW d'1' MOVWF MULTTMP ; Next character(s), mult is one DECFSZ FCHARCNT, 1 ; Decrement character counter, zero? GOTO NEXTCHARINC ; No, handle next character RETURN NEXTCHARINC DECF FSR GOTO INC ;***************************************************************************** ;Copy frequency string to LCD ;***************************************************************************** TSTR2LCD MOVLW LCD_LINE0 CALL LCDSDDA ; Position cursor leftmost on first line MOVLW FCHARMAX MOVWF FCHARCNT ; Set number of characters to handle MOVLW TCHARSTRT ; Set pointer to first frequency MOVWF FSR ; input character location, temporary MOVLW LCD_LINE0 CALL LCDSDDA ; Position cursor leftmost on first line CHARLINE0 MOVF FCHARCNT, W SUBLW d'6' BTFSC STATUS, Z ; Third character? GOTO DECPNT ; Yes, decimal point MOVF FCHARCNT, W BTFSS STATUS, Z ; Last character handled? GOTO CHARTOLCD ; No, get character and send it to LCD RETURN CHARTOLCD MOVF INDF, W ; Get character from pointer position CALL LCDPUTASC ; To LCD DECF FCHARCNT ; Decrement character counter INCF FSR ; Increment pointer GOTO CHARLINE0 DECPNT MOVLW '.' CALL LCDPUTCHAR GOTO CHARTOLCD ;***************************************************************************** ; Service interrupt from encoder ;***************************************************************************** ENCINTSERV BCF INTCON, RBIE ; No interrupts on PortB change now BTFSS SWEEP, 2 ; Was wobble-up on? BTFSC SWEEP, 3 ; No, was wobble-down on? CALL FRESTORE ; Yes, restore old frequency ;CLRF SWEEP ; Sweep/wobble off BTFSC PORTB, 4 ; We will only honor falling edge interrupts GOTO RETENC ; on channel A MOVLW d'2' ; Debounce time 1 millisecond CALL X_DELAY500 BTFSC PORTB, 4 ; Channel A should still be low GOTO RETENC BSF STATUS, RP0 ; Select bank 1 BSF TRISB, 5 ; Channel B pin input now BCF STATUS, RP0 ; Select bank 0 BTFSC PORTB, 5 ; Test channel B pin GOTO RIGHT GOTO LEFT RIGHT CALL FSTRINC GOTO BRES LEFT CALL FSTRDEC BRES CALL FSTR2WORD CALL CNTRLAD9850 CALL TSTR2LCD BSF STATUS, RP0 ; Select bank 1 BCF TRISB, 5 ; Channel B pin output again BCF STATUS, RP0 ; Select bank 0 RETENC CALL FBACKUP ; Backup this frequency MOVLW d'125' MOVWF NSTEPS ; and reset step-counter CALL WDAC ; and send to DAC BCF INTCON, RBIF ; OK, we have serviced this interrupt BSF INTCON, RBIE ; Enable interrupts on PortB change SWAPF _STATUS, W ; Restore registers MOVWF STATUS SWAPF _W, F SWAPF _W, W RETFIE ;***************************************************************************** ; Interrupt on TMR0 overflow, this means that we have detected the last input pulse ; and we have a valid keyboard character ;***************************************************************************** TMR0INTSERV BCF INTCON, T0IE ; Disable interrupt on TMR0 overflow BCF INTCON, T0IF ; OK, we have serviced this interrupt BCF RB0INTFLAG, 3 ; Clear flag, we can resume normal loop MOVF SWEEP, W BTFSC STATUS, Z ; Sweep/wobble on? GOTO DECPULSE ; No, ;GOTO SETSWEEPOFF ; Yes, SETSWEEPOFF BTFSS SWEEP, 2 ; Was wobble-up on? BTFSC SWEEP, 3 ; No, was wobble-down on? CALL FRESTORE ; Yes, restore old frequency CLRF SWEEP ; Sweep/wobble off GOTO ENDCHAR ; restore stuff and return DECPULSE DECF PULSECNT, W ; Decrement Pulsecnt to account for MOVWF KEYIN ; trigger pulse and store key code CLRF PULSECNT ; Next time we start with an empty counter ; Process the input character, ; depending on 'mode' BTFSC ENTERFREQ, 2 ; Entering frequency? ;GOTO CHKFP ; No, check other responses GOTO STORCHAR ; Yes, go to store character string CHKFP BTFSS FUNCTION, 0 ; Response to function prompt? GOTO CHKFN1 ; No, BCF FUNCTION, 0 ; Yes, clear function flag MOVF KEYIN, W ADDLW b'00001111' ; Shift functioncode 4 bits left MOVWF FUNCTIONCODE MOVF KEYIN, W ; BTFSC STATUS, Z ; Response=0? GOTO STEPSPRMPT ; Yes, prompt for step size MOVF KEYIN, W SUBLW d'1' ; Response=1? BTFSC STATUS, Z GOTO MULTPRMPT ; Yes, prompt for mult factor MOVF KEYIN, W SUBLW d'3' ; Response=3? BTFSC STATUS, Z GOTO DUPPRMPT ; Yes, prompt for display update yes/no MOVF KEYIN, W SUBLW d'6' ; Response=6? BTFSC STATUS, Z GOTO STOREPRMPT ; Yes, prompt for store number MOVF KEYIN, W SUBLW d'7' ; Response=7? BTFSC STATUS, Z GOTO RECALLPRMPT ; Yes, prompt for recall number BCF FUNCTION, 0 ; No, wrong response GOTO RESTREG ;---------------------------------------------------------------- RECALLPRMPT CALL LCDCLR ; Recall number prompt string MOVLW 'R' CALL LCDPUTCHAR GOTO NM ;---------------------------------------------------------------- STOREPRMPT CALL LCDCLR ; Store number prompt string MOVLW 'S' CALL LCDPUTCHAR NM MOVLW '0' CALL LCDPUTCHAR MOVLW '-' CALL LCDPUTCHAR MOVLW '2' CALL LCDPUTCHAR GOTO RESTREG ; Exit here ;---------------------------------------------------------------- MULTPRMPT CALL LCDCLR ; Multiplier number prompt string MOVLW 'M' CALL LCDPUTCHAR MOVLW 'u' CALL LCDPUTCHAR MOVLW 'l' CALL LCDPUTCHAR MOVLW 't' CALL LCDPUTCHAR MOVLW ' ' CALL LCDPUTCHAR MOVLW '1' CALL LCDPUTCHAR MOVLW '-' CALL LCDPUTCHAR MOVLW '9' CALL LCDPUTCHAR GOTO RESTREG ; Exit here ;---------------------------------------------------------------- DUPPRMPT CALL LCDCLR ; Display update prompt string MOVLW d'52' MOVWF EEADR DUPLINE0 CALL REEPROM ADDLW d'0' BTFSC STATUS, Z GOTO RESTREG ; Exit here CALL LCDPUTCHAR INCF EEADR GOTO DUPLINE0 ;---------------------------------------------------------------- STEPSPRMPT CALL LCDCLR ; Step size prompt string MOVLW d'24' MOVWF EEADR STEPLINE0 CALL REEPROM ADDLW d'0' BTFSC STATUS, Z GOTO STEPL CALL LCDPUTCHAR INCF EEADR GOTO STEPLINE0 STEPL MOVLW LCD_LINE1 CALL LCDSDDA ; Position cursor leftmost on first line MOVLW d'39' MOVWF EEADR STEPLINE1 CALL REEPROM ADDLW d'0' BTFSC STATUS, Z GOTO RESTREG ; Exit here CALL LCDPUTCHAR INCF EEADR GOTO STEPLINE1 ;-------------------------------------------------------------------- FNCPRMPT CALL LCDCLR ; Function prompt string MOVLW '0' CALL LCDPUTCHAR MOVLW '1' CALL LCDPUTCHAR MOVLW '3' CALL LCDPUTCHAR MOVLW '6' CALL LCDPUTCHAR MOVLW '7' CALL LCDPUTCHAR MOVLW LCD_LINE1 CALL LCDSDDA ; Position cursor leftmost on first line MOVLW 's' CALL LCDPUTCHAR MOVLW 'm' CALL LCDPUTCHAR MOVLW 'u' CALL LCDPUTCHAR MOVLW 's' CALL LCDPUTCHAR MOVLW 'r' CALL LCDPUTCHAR BSF FUNCTION, 0 ; next time here we know it is a function CLRF FUNCTIONCODE ; Clear function code GOTO RESTREG ; Exit here ;---------------------------------------------------------------- CHKFN1 MOVF FUNCTIONCODE, W SUBLW d'22' ; Was functioncode 7? BTFSC STATUS, Z GOTO GETRECALLN ; Yes, get memory recall number MOVF FUNCTIONCODE, W SUBLW d'21' ; Was functioncode 6? BTFSC STATUS, Z GOTO GETSTOREN ; Yes, get memory store number MOVF FUNCTIONCODE, W SUBLW d'18' ; Was functioncode 3? BTFSC STATUS, Z GOTO STOREDUP ; Yes, store display update yes/no MOVF FUNCTIONCODE, W SUBLW d'16' ; Was functioncode 1? BTFSC STATUS, Z GOTO STOREMULT ; Yes, store mult MOVF FUNCTIONCODE, W SUBLW d'15' ; Was functioncode 0? BTFSC STATUS, Z GOTO STORESTEP ; Yes, store step size GOTO CHKA ; No, check for a,b,c or d input GETRECALLN MOVF KEYIN, W MOVWF CTEMP MOVLW d'3' BCF STATUS, C SUBWF CTEMP, F BTFSC STATUS, C ; Is input key >2 ? GOTO RESTREG ; Yes, ignore GOTO RECALL GETSTOREN MOVF KEYIN, W MOVWF CTEMP MOVLW d'3' BCF STATUS, C SUBWF CTEMP, F BTFSC STATUS, C ; Is input key >2 ? GOTO RESTREG ; Yes, ignore ;GOTO STORE STORE RLF KEYIN, 1 ; Memory store number RLF KEYIN, 1 RLF KEYIN, 1 ; Shift keyin 3 bits left = mult by 8 MOVF KEYIN, W MOVWF EEADR ; that is the start of the frequency string in eeprom CALL WRITEPARS ; Store string GOTO ENDCHAR RECALL RLF KEYIN, 1 ; Memory recall number RLF KEYIN, 1 RLF KEYIN, 1 ; Shift keyin 3 bits left = mult by 8 MOVF KEYIN, W MOVWF EEADR ; that is the start of the frequency string in eeprom CALL READPARS ; Read string GOTO ENDCHAR STOREDUP MOVF KEYIN, W SUBLW d'1' ; A 1 entered? BTFSC STATUS, Z GOTO DNOUPDATE ; Yes, set display to no update ;GOTO DUPDATE ; No, all other input sets display to update DUPDATE BCF DISPLAYUPDATE, 1; update display GOTO ENDCHAR DNOUPDATE BSF DISPLAYUPDATE, 1; no update GOTO ENDCHAR STOREMULT MOVF KEYIN, W BTFSC STATUS, Z ; Is input key 0? GOTO RESTREG ; Yes, ignore MOVWF CTEMP MOVLW d'10' BCF STATUS, C SUBWF CTEMP, F BTFSC STATUS, C ; Is input key >9 ? GOTO RESTREG ; Yes, ignore MOVF KEYIN, W MOVWF MULT ; No, store mult GOTO ENDCHAR STORESTEP MOVF KEYIN, W MOVWF CTEMP MOVLW d'5' BCF STATUS, C SUBWF CTEMP, F BTFSC STATUS, C ; Is input key >4 ? GOTO RESTREG ; Yes, ignore MOVF KEYIN, W MOVWF FSTEP ; Store step code GOTO ENDCHAR CHKA MOVF KEYIN, W SUBLW KEYA ; Was this the sweep-up ("A") key? BTFSC STATUS, Z GOTO SETSWEEPUPON ; Yes, ;GOTO CHKB ; No, CHKB MOVF KEYIN, W SUBLW KEYB ; Was this the sweep-down ("B") key? BTFSC STATUS, Z GOTO SETSWEEPDOWNON ; Yes, ;GOTO CHKC ; No, CHKC MOVF KEYIN, W SUBLW KEYC ; Was this the wobble ("C") key? BTFSC STATUS, Z GOTO SETWOBBLE ; Yes, ;GOTO CHKD ; No, CHKD MOVF KEYIN, W SUBLW KEYD ; Was this the function ("D") key? BTFSC STATUS, Z GOTO FNCPRMPT ; Yes, GOTO STORCHAR ; No, SETSWEEPUPON BSF SWEEP, 0 ; Yes, set sweep-up flag on GOTO ENDCHAR ; restore stuff and return SETSWEEPDOWNON BSF SWEEP, 1 ; Yes, set sweep-down flag on GOTO ENDCHAR ; restore stuff and return SETWOBBLE BSF SWEEP, 2 ; Yes, set wobble flag, MOVLW d'125' MOVWF NSTEPS ; and set step counter to one CALL FBACKUP ; and backup frequency, so it can be restored later GOTO ENDCHAR ; restore stuff and return STORCHAR MOVF FCHARCNT, W ; No, continue reading frequency string BTFSS STATUS, Z ; Is this the first character in the frequency string? ;GOTO EFPROMPT ; Yes, 'Enter frequency' prompt, GOTO ENTERFRQ ;--------------------------------------------------------- EFPROMPT CALL LCDCLR ; Frequency prompt string MOVLW 'F' CALL LCDPUTCHAR MOVLW 'r' CALL LCDPUTCHAR MOVLW 'e' CALL LCDPUTCHAR MOVLW 'q' CALL LCDPUTCHAR MOVLW 'u' CALL LCDPUTCHAR MOVLW 'e' CALL LCDPUTCHAR MOVLW 'n' CALL LCDPUTCHAR MOVLW 'c' CALL LCDPUTCHAR MOVLW 'y' CALL LCDPUTCHAR MOVLW ':' CALL LCDPUTCHAR MOVLW LCD_LINE1 CALL LCDSDDA ; Position cursor leftmost on first line MOVLW '-' CALL LCDPUTCHAR MOVLW '-' CALL LCDPUTCHAR MOVLW '.' CALL LCDPUTCHAR MOVLW '_' CALL LCDPUTCHAR MOVLW '_' CALL LCDPUTCHAR MOVLW '_' CALL LCDPUTCHAR MOVLW '_' CALL LCDPUTCHAR MOVLW '_' CALL LCDPUTCHAR MOVLW '_' CALL LCDPUTCHAR MOVLW ' ' CALL LCDPUTCHAR ;MOVLW 'M' ;CALL LCDPUTCHAR ;MOVLW 'H' ;CALL LCDPUTCHAR ;MOVLW 'z' ;CALL LCDPUTCHAR CALL MHZ MOVLW LCD_LINE1 CALL LCDSDDA ; Position cursor leftmost on first line ;--------------------------------------------------------- BSF ENTERFREQ, 2 ; and set enter-frequency flag MOVLW TCHARSTRT MOVWF FSR ; Set pointer to first frequency input character location ;GOTO ENTERFRQ ENTERFRQ MOVF KEYIN, W MOVWF CTEMP MOVLW d'10' BCF STATUS, C SUBWF CTEMP, F BTFSC STATUS, C ; Is input key >9 ? GOTO RESTREG ; Yes, ignore MOVF FCHARCNT, W BTFSS STATUS, Z ; Was this the first character? GOTO THRDCHAR ; No, next check MOVF KEYIN, W ; Yes, check this character MOVWF CTEMP MOVLW d'4' BCF STATUS, C SUBWF CTEMP, F BTFSC STATUS, C ; Is first character >3 ? GOTO RESTREG ; Yes, ignore (max freq=39.999999) THRDCHAR MOVF FCHARCNT, W MOVWF CTEMP SUBLW d'2' BTFSS STATUS, Z ; Is this the third input character ? GOTO HANDLECHAR ; No, MOVF T10M, W ; Yes, check first character BTFSS STATUS, Z ; Zero? GOTO HANDLECHAR ; No MOVF T1M, W ; Yes, check second character BTFSS STATUS, Z ; Zero? GOTO HANDLECHAR ; No, MOVF KEYIN, W BTFSC STATUS, Z ; third and current character also zero? GOTO RESTREG ; Yes, ignore HANDLECHAR MOVF CTEMP, W ; Restore fcharcnt MOVWF FCHARCNT MOVF KEYIN, W ; No, MOVWF INDF ; Write this character to pointer location INCF FSR ; Increment pointer CALL LCDPUTASC ; Write character to lcd MOVF FCHARCNT, W MOVWF CTEMP SUBLW d'1' BTFSS STATUS, Z ; Is this the second input character ? GOTO HANR ; No, MOVLW '.' ; Yes, print decimal point CALL LCDPUTCHAR HANR INCF FCHARCNT ; Increment character counter MOVLW FCHARMAX SUBWF FCHARCNT, W ; Have we reached the maximum number of characters? BTFSS STATUS, Z GOTO RESTREG ; No, DECF FCHARCNT ; Yes, decrement character counter, BCF ENTERFREQ, 2 ; and clear enter-frequency flag MOVLW d'0' MOVWF EEADR CALL WRITEPARS ; and store this string in memory 0 GOTO ENDCHAR ENDCHAR CLRF FUNCTIONCODE ; Next time no function !!!! CLRF FCHARCNT CLRF PULSECNT CALL FSTR2WORD CALL CNTRLAD9850 MOVLW b'00000001' CALL LCDPUTCMD ; Clear entire display CALL TSTR2LCD MOVLW d'10' CALL LCDSDDA ; Position cursor after frequency string CALL MHZ BTFSS DISPLAYUPDATE, 1; No display update? GOTO RESTREG MOVLW LCD_LINE1 CALL LCDSDDA ; Position cursor leftmost on first line MOVLW 'N' CALL LCDPUTCHAR MOVLW 'o' CALL LCDPUTCHAR MOVLW ' ' CALL LCDPUTCHAR MOVLW 'U' CALL LCDPUTCHAR MOVLW 'p' CALL LCDPUTCHAR MOVLW 'd' CALL LCDPUTCHAR MOVLW '.' CALL LCDPUTCHAR MOVLW '!' CALL LCDPUTCHAR RESTREG SWAPF _STATUS, W ; Restore registers MOVWF STATUS SWAPF _W, F SWAPF _W, W RETFIE ;***************************************************************************** ; Write "MHz" ;***************************************************************************** MHZ MOVLW d'10' CALL LCDSDDA ; Position cursor after frequency string MOVLW 'M' CALL LCDPUTCHAR MOVLW 'H' CALL LCDPUTCHAR MOVLW 'z' CALL LCDPUTCHAR RETURN ;***************************************************************************** ; Store frequency string in backup location ;***************************************************************************** FBACKUP MOVF T10M, W MOVWF FB1 MOVF T1M, W MOVWF FB2 MOVF T100K, W MOVWF FB3 MOVF T10K, W MOVWF FB4 MOVF T1K, W MOVWF FB5 MOVF T100H, W MOVWF FB6 MOVF T10H, W MOVWF FB7 MOVF T1H, W MOVWF FB8 RETURN ;***************************************************************************** ; Restore frequency from backup location ;***************************************************************************** FRESTORE MOVF FB1, W MOVWF T10M MOVF FB2, W MOVWF T1M MOVF FB3, W MOVWF T100K MOVF FB4, W MOVWF T10K MOVF FB5, W MOVWF T1K MOVF FB6, W MOVWF T100H MOVF FB7, W MOVWF T10H MOVF FB8, W MOVWF T1H RETURN ;***************************************************************************** ; Interrupt on RB0 service routine ;***************************************************************************** RB0INTSERV INCF PULSECNT, F ; Count this pulse BCF INTCON, INTF ; OK, we have serviced this interrupt BCF INTCON, T0IF ; Reset TMR0 interrupt BSF INTCON, T0IE ; Enable interrupt on TMR0 overflow CLRF TMR0 ; TMR0 starts counting now, should take 2 mSec BSF RB0INTFLAG, 3 ; Set flag so we do nothing in main loop SWAPF _STATUS, W ; Restore registers MOVWF STATUS SWAPF _W, F SWAPF _W, W RETFIE ;***************************************************************************** ; LCD Module Subroutines ;***************************************************************************** ;***************************************************************************** ; Clear LCD ;***************************************************************************** LCDCLR MOVLW b'00000001' CALL LCDPUTCMD ; Clear entire display MOVLW LCD_LINE0 CALL LCDSDDA ; Position cursor leftmost on first line RETURN ;***************************************************************************** ; Send decimal to LCD, add factor to get ascii code ;***************************************************************************** LCDPUTASC ADDLW DECAD ; Add facor to get ascii code CALL LCDPUTCHAR RETURN ;============================================================================= ; LCDINIT ; Initialize LCD Module ; Should be modified to your needs (i.e. display type, cursor on/off, etc.) ;============================================================================= LCDINIT ; Busy-flag is not yet valid ;BCF PORTA, LCD_E ;BCF PORTB, LCD_RS ;BCF PORTB, LCD_RW MOVLW 0x01E ; power-up delay CALL X_DELAY500 ; 30 * 0.5mS = 15mS MOVLW 0x03 ; 8-bit-interface MOVWF PORTA CALL LCD_ENABLE MOVLW 0x01E CALL X_DELAY500 ; 30 * 0.5mS = 15mS MOVLW 0x02 ; 4-bit-interface MOVWF PORTA CALL LCD_ENABLE MOVLW 0x01E CALL X_DELAY500 ; 30 * 0.5mS = 15mS MOVLW 0x028 ; 4-bit-interface, two line ; Busy Flag should be valid from here CALL LCDPUTCMD MOVLW 0X00C ; Display on, CALL LCDPUTCMD MOVLW 0X001 ; Clear display CALL LCDPUTCMD MOVLW 0X006 ; Incremental entry CALL LCDPUTCMD RETURN ;============================================================================= ; LCD_ENABLE ; Pulses LCD enable pin ; OK ;============================================================================= LCD_ENABLE BSF PORTB, LCD_E ; LCD E-line High BCF PORTB, LCD_E ; LCD E-line Low RETURN ;============================================================================= ; LCDBUSY ; Returns when LCD busy-flag is inactive ; OK ;============================================================================= LCDBUSY BSF STATUS,RP0 ; Select Register page 1 MOVLW B'00001111' ; Set RA3,2,1,0 to input, RA4 to output MOVWF TRISA BCF STATUS, RP0 ; Select Register page 0 BCF PORTB, LCD_RS ; Set LCD for command mode BSF PORTB, LCD_RW ; Setup to read busy flag BSF PORTB, LCD_E ; LCD E-line High SWAPF PORTA, W ; Read busy flag + DDram address BCF PORTB, LCD_E ; LCD E-line Low ANDLW 0xF0 ; Mask out low nibble MOVWF WTEMP BSF PORTB, LCD_E ; LCD E-line High MOVF PORTA, W ; Read lower nibble DDRam address BCF PORTB, LCD_E ; LCD E-line Low ANDLW 0x0F ; Mask out upper nibble IORWF WTEMP, W ; Combine nibbles BTFSC WTEMP, 7 ; Check busy flag, high=busy GOTO LCDBUSY LCDNOTBUSY BCF PORTB, LCD_RW ; Set LCD in write mode BSF STATUS, RP0 ; Select Register page 1 MOVLW B'00000000' ; Set PORTA to output MOVWF TRISA ; BCF STATUS, RP0 ; Select Register page 0 RETURN ;============================================================================= ; LCDSDDA ; Sets the Display-Data-RAM address. DDRAM data is read/written after ; this setting. ; Required DDRAM address must be set in W ; b0-6 : required DDRAM address ; b7 : don't care ; OK ;============================================================================= LCDSDDA IORLW 0x080 ; Function set CALL LCDPUTCMD RETURN ;============================================================================= ; LCDPUTCHAR ; Sends character to LCD ; Required character must be in W ; OK ;============================================================================= LCDPUTCHAR MOVWF LCD_TEMP ; Character to be sent is in W CALL LCDBUSY ; Wait for LCD to be ready SWAPF LCD_TEMP, W ANDLW 0x0F MOVWF PORTA ; Put upper nibble of LCD_TEMP in PORTA BCF PORTB, LCD_RW ; Set LCD in read mode BSF PORTB, LCD_RS ; Set LCD in data mode CALL LCD_ENABLE MOVF LCD_TEMP, W ; ANDLW 0x0F ; MOVWF PORTA ; Put lower nibble of LCD_TEMP in PORTA CALL LCD_ENABLE RETURN ;============================================================================= ; LCDPUTCMD ; Sends command to LCD ; Required command must be in W ; OK ;============================================================================= LCDPUTCMD MOVWF LCD_TEMP ; Command to be sent is in W CALL LCDBUSY ; Wait for LCD to be ready MOVF LCD_TEMP, W SWAPF LCD_TEMP, W ANDLW 0x0F MOVWF PORTA ; Put upper nibble of LCD_TEMP in PORTA BCF PORTB, LCD_RW ; Set LCD in read mode BCF PORTB, LCD_RS ; Set LCD in command mode CALL LCD_ENABLE MOVF LCD_TEMP, W ANDLW 0x0F MOVWF PORTA ; Put lower nibble of LCD_TEMP in PORTA CALL LCD_ENABLE RETURN ;***************************************************************************** ; Delay_time = ((DELAY_value * 3) + 4) * Cycle_time ; DELAY_value = (Delay_time - (4 * Cycle_time)) / (3 * Cycle_time) ; ; i.e. (@ 4MHz crystal) ; Delay_time = ((32 * 3) + 4) * 1uSec ; = 100uSec ; DELAY_value = (500uSec - 4) / 3 ; = 165.33 ; = 165 ;***************************************************************************** DELAY500 MOVLW D'165' ; +1 1 cycle MOVWF DELAY ; +2 1 cycle DELAY500_LOOP DECFSZ DELAY, F ; step 1 1 cycle GOTO DELAY500_LOOP ; step 2 2 cycles DELAY500_END RETURN ; +3 2 cycles ; ; X_DELAY500 MOVWF X_DELAY ; +1 1 cycle X_DELAY500_LOOP CALL DELAY500 ; step1 wait 500uSec DECFSZ X_DELAY, F ; step2 1 cycle GOTO X_DELAY500_LOOP ; step3 2 cycles X_DELAY500_END RETURN ; +2 2 cycles ;***************************************************************************** SECWAIT MOVLW D'50' ; 100 times 15 = 1500 msec MOVWF COUNT SECLOOP MOVLW 0x01E ; 15 msec CALL X_DELAY500 DECFSZ COUNT, F GOTO SECLOOP SECLOOPEND RETURN ;***************************************************************************** ;Routines end here. ;***************************************************************************** ;***************************************************************************** ;Eeprom contents follows. ;***************************************************************************** ; eeprom contents: 3 frequencies in the form of ; 3 strings of 8 characters ; ; eeprom is pre-filled with three preset ; frequency, rest is for a step-prompt string org 0x2100 data d'1' ; location 00 ;memory 0: 10MHz data d'0' data d'0' data d'0' data d'0' data d'0' data d'0' data d'0' data d'2' ; location 08 ;memory 1: 20 MHz data d'0' data d'0' data d'0' data d'0' data d'0' data d'0' data d'0' data d'3' ; location 16 ;memory 2: 30 MHz data d'0' data d'0' data d'0' data d'0' data d'0' data d'0' data d'0' data '1' ; location 24 ;stepsize prompt line0 data ' ' data '1' data '0' data ' ' data '1' data '0' data '0' data ' ' data '1' data ' ' data '1' data '0' data 'k' data 0 data '0' ; location 39 ;stepsize prompt line1 data ' ' data '1' data ' ' data ' ' data '2' data ' ' data ' ' data ' ' data '3' data ' ' data '4' data 0 data '0' ; location 52 ;display update prompt line0 data '=' data 'y' data ' ' data '1' data '=' data 'n' data ' ' data 'd' data 'u' data 'p' data 0 ; location 63 ;***************************************************************************** ;End of eeprom contents ;***************************************************************************** END