;***************************************************************************************** ; register ;***************************************************************************************** W EQU 0 F EQU 1 INDF SET 0X00 TMR0 SET 0X01 PCL SET 0X02 STATUS SET 0X03 FSR SET 0X04 PORTA SET 0X05 PORTB SET 0X06 EEDATA SET 0X08 EEADR SET 0X09 INTCON SET 0X0B OPTION_REG SET 0X01 EECON1 SET 0X08 EECON2 SET 0X09 #DEFINE CARRY STATUS,0 #DEFINE ZERO STATUS,2 #DEFINE RP0 STATUS,5 #DEFINE T0IF INTCON,2 #DEFINE RD EECON1,0 #DEFINE WR EECON1,1 #DEFINE WREN EECON1,2 #DEFINE WRERR EECON1,3 #DEFINE EEIF EECON1,4 ;***************************************************************************************** ; CONFIGURATION BITS ;***************************************************************************************** _CP_ON EQU H'3FEF' _CP_OFF EQU H'3FFF' _PWRTE_ON EQU H'3FFF' _PWRTE_OFF EQU H'3FF7' _WDT_OFF EQU H'3FFB' _RC_OSC EQU H'3FFF' _HS_OSC EQU 0x3FFE PROCESSOR 16F84 ;select pic and assembler options LIST F=INHX8M,N=0 RADIX DEC __CONFIG _HS_OSC & _WDT_OFF ;XTal oscillator + watchdog off __MAXRAM H'CF' __BADRAM H'07', H'50'-H'7F', H'87' ;***************************************************************************************** ; general ;***************************************************************************************** #DEFINE SDA PORTA,0 ; I2C data #DEFINE SCL PORTA,1 ; I2C clock #DEFINE PIN_AUX1 PORTA,2 ; AUX2 button #DEFINE PIN_PLUS PORTA,3 ; freq+ input #DEFINE PIN_MINUS PORTA,4 ; freq- input #DEFINE PIN_FUNC PORTB,0 ; function button #DEFINE PIN_AUX2 PORTB,1 ; AUX2 button #DEFINE E PORTB,2 ; LCD enable 0=ON 1=OFF #DEFINE RS PORTB,3 ; LCD register Select 0=CMD 1=DATA #DEFINE D4 PORTB,4 ; LCD data #DEFINE D5 PORTB,5 ; LCD data #DEFINE D6 PORTB,6 ; LCD data #DEFINE D7 PORTB,7 ; LCD Data ; PORTB,4-7 ; LCD 4 bit datawires #DEFINE LEAD_Z FLAGS,0 ; leading zero flag #DEFINE NEGATIVE FLAGS,1 ;NUMBER TO DISPLAY IS NEGATIVE. #DEFINE BUTTON_VALID FLAGS,2 ;RESULT FLAG FROM BUTTON BUTTON_VALID CALL. #DEFINE PLL_DIV_OK FLAGS,3 ;PLL DIVIDER NUMBER IS VALID. #DEFINE MIN_MAX_CHANGE FLAGS,4 ;SET IF MAXIMUM OR MINIMUM CHANGED #DEFINE TIMEOUT FLAGS,5 ;IF DISP TIMEOUT SET, GO TO MAIN DISPLAY. #DEFINE EEPROM_UPDATE FLAGS,6 ;IF SET, UPDATE THE EEPROM. ;****************************** *********************************************************** ; GENERAL EQUATES ;***************************************************************************************** RESETVECTOR EQU H'00' ;PIC16F84 RESET VECTOR. INT_POINTER EQU H'04' ;PIC16F84 INTERUPT VECTOR. TRUE EQU H'FF' FALSE EQU H'00' DP EQU H'A5' ;LCD DECIMAL POINT. REPEAT EQU 30 ;REPEAT PERIOD. (30 x 9mS) TIMEOUT_NUM EQU 1100 ;DISPLAY TIMEOUT. (1100 x 9mS) LOCK_TM EQU 110 ;TIME BETWEEN STATUS CHECKS. (110 x 9mS) ;255 = NO CHECKS ONCE IN LOCK. PLL_ADDRESS EQU B'11000010' ;PLL CHIP ADDRESS. ;PLL_ADDRESS EQU B'01000000' ;BUS EXPANDER CHIP ADDRESS. STEP_SIZE EQU 125 ;PLL FREQUENCY STEPS = 50KHz MAX_OFFSET EQU 50000 ;PLL MAXIMUM TX OR RX OFFSET = 500MHz PLL_MIN_FREQ EQU 2500000 ;PLL MINIMUM FREQUENCY = 50MHz PLL_MAX_FREQ EQU 2625000 ;PLL MAXIMUM FREQUENCY = 1400MHz TIMEOUT_NUM_X EQU 0 - TIMEOUT_NUM TIMEOUT_NUM_H EQU HIGH ( H'FFFF' & TIMEOUT_NUM_X ) TIMEOUT_NUM_L EQU LOW ( H'FFFF' & TIMEOUT_NUM_X ) PLL_SPAN EQU ( PLL_MAX_FREQ - PLL_MIN_FREQ )/ STEP_SIZE PLL_SPAN_H EQU HIGH PLL_SPAN PLL_SPAN_L EQU LOW PLL_SPAN OFFSET_MAX EQU MAX_OFFSET / STEP_SIZE ;MAXIMUM TX OR RX OFFSET = 500MHz OFFSET_MAX_H EQU HIGH OFFSET_MAX OFFSET_MAX_L EQU LOW OFFSET_MAX OFFSET_MIN EQU 0 - (MAX_OFFSET / STEP_SIZE) ;MINIMUM TX OR RX OFFSET = -500MHz OFFSET_MIN_H EQU HIGH ( H'FFFF' & OFFSET_MIN) OFFSET_MIN_L EQU LOW OFFSET_MIN PLL_DIV_MAX EQU PLL_MAX_FREQ / STEP_SIZE ;DIVIDER NUM IS INVALID IF GREATER PLL_DIV_MAX_H EQU HIGH PLL_DIV_MAX ;THAN 1400MHz. PLL_DIV_MAX_L EQU LOW PLL_DIV_MAX PLL_DIV_MIN EQU PLL_MIN_FREQ / STEP_SIZE ;DIVIDER NUM IS INVALID IF LESS PLL_DIV_MIN_H EQU HIGH PLL_DIV_MIN ;THAN 50MHz. PLL_DIV_MIN_L EQU LOW PLL_DIV_MIN DISP_MAX EQU (PLL_MAX_FREQ / STEP_SIZE) + OFFSET_MAX DISP_MAX_H EQU HIGH DISP_MAX DISP_MAX_L EQU LOW DISP_MAX ;MAXIMUM TX OR RX DISP = 1900MHz. ;***************************************************************************************** ORG H'2100' INCLUDE "3cm.DAT" ;FILE TO SET THE INITIAL PLL & DISPLAY ; FREQ RANGE INTO EEPROM. ;***************************************************************************************** ;***************************************************************************************** ; RAM VARIABLES 68 BYTES MAX ;***************************************************************************************** CBLOCK H'0C' ;RAM STARTS AT H'0C' COUNT ;GENERAL COUNTER VARIABLES. COUNT1 COUNT2 SAVE_STATUS ;FOR INTERUPT SERVIVE ROUTINE. SAVE_W_REG ; " BUT_P_CNT ;BUTTON PRESSED TIME COUNT. (x 9mS) BUT_N_CNT ; " BUT_S_CNT ; " BUT_P_OLD ;STATE OF OLD BUTTON COUNT. BUT_N_OLD ; " BUT_S_OLD ; " S_TIMER ;TIMER FOR DOUBLE PRESS OF SHIFT BUTTON. LOCK_TIMER ;TIMER FOR CHECKING PLL STATUS. RESULT ;RESULT OF A BUTTON CHECK CALL. TIMEOUT_H ;16 BIT DISPLAY TIMEOUT DOWN COUNTER, TIMEOUT_L ;RETURN TO MAIN DISPLAY WHEN = 0. EEPROM_WRITE ;EEPROM WRITE UPDATE DOWN COUNTER. FLAGS ;8 MISC FLAGS. PLL_STATUS ;STATUS BYTE FROM PLL READ. TEMP ;TEMPORARY STORAGE. TEMP_H ; " TEMP_L ; " MULT_NUM ;COPY OF CURRENT SETUP DATA FROM EEPROM. DISP_FREQ:2 ; " MIN_DISP_FREQ:2 ; " MAX_DISP_FREQ:2 ; " VCO_OFFSET:2 ; " PLL_OLD:2 ;PREVIOUS PLL DIVIDER NUMBER. ARG ;8 BIT BINARY BUFFER (MATHS). ARG_H ;16 BIT BINARY BUFFER (MATHS). ARG_L ; " ARG2_H ;16 BIT BINARY BUFFER (MATHS). ARG2_L ; " ARG3_H ;16 BIT BINARY BUFFER (MATHS). ARG3_L ; " RESULT_H ;24 BIT BINARY BUFFER (MATHS). RESULT_M ; " RESULT_L ; " NEG_POSITION ;LOCATION OF THE - SIGN IN THE DEC BUFFER. DEC_0 ;8 DIGIT DECIMAL BUFFER. MSD DEC_1 ; " DEC_2 ; " DEC_3 ; " DEC_4 ; " DECIMAL_POINT ; " DECIMAL POINT. DEC_5 ; " DEC_6 ; " DEC_7 ; " LSD MULT MULT_TMP ENDC ;***************************************************************************************** ; ; INITIALISE THE HARDWARE. ; ;***************************************************************************************** ORG RESETVECTOR CALL LONG_DELAY ;WAIT UNTIL LCD AND PLL HAVE INITIALISED. MOVLW H'0D' ;POINT TO START OF RAM. (JUST PAST COUNT) MOVWF FSR GOTO CONTINUE ;JUMP OVER INTERUPT ROUTINES. ;***************************************************************************************** ; INTERRUPT SERVICE ROUTINE ; ; SERVICE THE TMR0 INTERUPT (EVERY 9mS) ; ; INCREMENT THE BUTTON PRESSED COUNTERS IF THE CORROSPONDING BUTTON ; IS PRESSED & SET THE DISPLAY TIMEOUT & EEPROM WRITE DOWN COUNTER. ; ELSE SET THE BUTTON COUNTER TO 0. ; ; DEC THE 8 BIT EEPROM WRITE, DOWN COUNTER. WHEN IT REACHES 0, SET THE ; EEPROM WRITE FLAG. (INDICATES WHEN TO UPDATE THE EEPROM, IE 2 SECONDS ; AFTER RELEASING THE FREQ + OR - BUTTON WRITE ANY CHANGES TO EEPROM) ; ; DECREMENT THE 16 BIT DISPLAY DOWN COUNTER. WHEN IT REACHES 0, SET THE ; TIMEOUT FLAG. (IF NO BUTTONS HAVE BEEN PRESSED FOR A WHILE. INDICATES ; WHEN TO RETURN TO THE MAIN DISPLAY) ; ; DEC THE 8 BIT SHIFT BUTTON DOUBLE PRESS, DOWN COUNTER. WONT DEC PAST 0. ; (THE FIRST PRESS SETS THE COUNTER. A DOUBLE PRESS IS VALID IF THE SECOND ; PRESS OCCURS WHILE THE COUNTER IS NON ZERO) ; ; DEC THE 8 BIT LOCK TIMER, DOWN COUNTER. WONT DEC PAST 0. ; WHEN EQUAL TO 0 ITS TIME TO CHECK IF THE PLL IS LOCKED. ;***************************************************************************************** ORG INT_POINTER BTFSS T0IF ; WAS THE INTERUPT CAUSED BY TMR0 ? RETFIE ; N. JUST RETURN & RE-ENABLE INTERUPTS. MOVWF SAVE_W_REG ; Y. SAVE WREG & STATUS REGS. SWAPF STATUS,W MOVWF SAVE_STATUS BCF RP0 ; ADDRESSING BANK 0. ;----------------------------------------------------------------------------------------- IMPULS_N: BTFSS PIN_PLUS ; IS FREQ + D? GOTO NOW_P_CNT CLRF BUT_P_CNT ;N. CLEAR THE COUNT. GOTO IMPULS_P NOW_P_CNT: INCFSZ BUT_P_CNT,W ;Y. INC THE COUNT. MOVWF BUT_P_CNT ; BUT DONT INC PAST 255. CALL SET_TIMEOUT ; SET THE DISPLAY TIMEOUT DOWN COUNTER. MOVLW H'FF' ; SET THE EEPROM WRITE DOWN COUNTER. MOVWF EEPROM_WRITE ;----------------------------------------------------------------------------------------- IMPULS_P: BTFSS PIN_MINUS ;IS FREQ - BUTTON PRESSED? GOTO NOW_N_CNT CLRF BUT_N_CNT ;N. CLEAR THE COUNT. GOTO IMPULS_S NOW_N_CNT: INCFSZ BUT_N_CNT,W ;Y. INC THE COUNT. MOVWF BUT_N_CNT ; BUT DONT INC PAST 255. CALL SET_TIMEOUT ; SET THE DISPLAY TIMEOUT DOWN COUNTER. MOVLW H'FF' ; SET THE EEPROM WRITE DOWN COUNTER. MOVWF EEPROM_WRITE ;----------------------------------------------------------------------------------------- IMPULS_S: BTFSS PIN_FUNC ;IS SHIFT BUTTON PRESSED? GOTO INC_S_CNT CLRF BUT_S_CNT ;N. CLEAR THE COUNT. GOTO CHK_TIMEOUT INC_S_CNT: BTFSS PIN_FUNC INCFSZ BUT_S_CNT,W ;Y. INC THE COUNT. MOVWF BUT_S_CNT ; BUT DONT INC PAST 255. CALL SET_TIMEOUT ; SET THE DISPLAY TIMEOUT DOWN COUNTER. ;----------------------------------------------------------------------------------------- CHK_TIMEOUT: MOVF TIMEOUT_H,W ;GET THE DISPLAY TIMEOUT. IORWF TIMEOUT_L,W BTFSC ZERO ;IS IT = 0? GOTO T_DONE ;Y. DONT DO ANYTHING. INCFSZ TIMEOUT_L,F ;INC LOW BYTE. IS IT = 0 ? GOTO T_DONE ;N. ALL DONE. INCFSZ TIMEOUT_H,F ;Y. INC THE HIGH BYTE. IS IT ALSO = 0 ? GOTO T_DONE ; N. ALL DONE. BSF TIMEOUT ; Y. SET THE TIMEOUT FLAG. T_DONE: ;----------------------------------------------------------------------------------------- MOVF S_TIMER,W ;GET THE DOUBLE PRESSED SHIFT COUNTER. BTFSS ZERO ;IS IT = 0? DECF S_TIMER,F ;N. DEC THE COUNTER. ;----------------------------------------------------------------------------------------- INCF LOCK_TIMER,W ;GET THE LOCK TIME COUNTER. BTFSC ZERO ;IS IT = 255? GOTO NO_LOCK_TM_DEC MOVF LOCK_TIMER,W ;N. GET THE LOCK TIME COUNTER. BTFSS ZERO ; IS IT = 0? DECF LOCK_TIMER,F ; N. DEC THE COUNTER. NO_LOCK_TM_DEC: ;Y. DONT DEC THE COUNTER. ;----------------------------------------------------------------------------------------- MOVF EEPROM_WRITE,W ;GET THE EEPROM WRITE TIMEOUT COUNTER. BTFSC ZERO ;IS IT = 0? GOTO EEPROM_WR_DONE ;Y. DONT DO ANYTHING. DECFSZ EEPROM_WRITE,F ;N. DEC THE COUNTER. COUNT = 0? GOTO EEPROM_WR_DONE ; N. ALL DONE. BSF EEPROM_UPDATE ; Y. SET THE FLAG. (UPDATE THE EEPROM) EEPROM_WR_DONE: ;----------------------------------------------------------------------------------------- RS_INT_STATUS: SWAPF SAVE_STATUS,W MOVWF STATUS ;RESTORE STATUS REG. SWAPF SAVE_W_REG,F ;SAVE WREG. SWAPF SAVE_W_REG,W ;RESTORE WREG. BCF T0IF ;CLEAR TMR0 INTERUPT FLAG. RETFIE ;----------------------------------------------------------------------------------------- SET_TIMEOUT: MOVLW TIMEOUT_NUM_H ;SET THE TIMEOUT COUNTER. MOVWF TIMEOUT_H MOVLW TIMEOUT_NUM_L MOVWF TIMEOUT_L RETURN ;----------------------------------------------------------------------------------------- ;***************************************************************************************** ; TEXT TABLE (RETLW 'X') ; ; PLACED IN PAGE 0, SO WE DONT HAVE TO BOTHER WITH PAGE BITS. ;***************************************************************************************** TABLE: ADDWF PCL,F ;JUMP TO CHAR POINTED TO IN W REG. ST: ;LABEL THE START OF TEXT STRINGS. UN: EQU $ - ST DT "X",0 LOCKED: EQU $ - ST DT "L",0 TWO_SPACES: EQU $ - ST DT " ",0 MHZ: EQU $ - ST DT "MHz",0 TABLE_END: ;***************************************************************************************** ; ; INITIALISE THE HARDWARE. (CONTINUED) ; ;***************************************************************************************** CONTINUE: MOVLW 67 ;67 BYTES OF RAM TO CLEAR. MOVWF COUNT CLEAR_LOOP: CLRF INDF ;CLEAR THE RAM BYTE. INCF FSR,F ;INC THE RAM ADDRESS POINTER. DECFSZ COUNT,F ;DEC THE COUNT. GOTO CLEAR_LOOP ;LOOP UNTIL ALL BYTES DONE. MOVLW 1 MOVWF MULT BSF RP0 ;SELECT PAGE 1 FOR TRIS REG ACCESS. MOVLW B'00011100' MOVWF PORTA ;RA2,RA3,RA4 = INPUTS, RA0,RA1 = OUTPUT. MOVLW B'00000011' MOVWF PORTB ;RB2-RB7 = OUTPUT, RB0,RB1 = INPUT. MOVLW B'00000100' ;SET PRESCALER TO TMR0. MOVWF OPTION_REG ;TMR0 RATE = 1/32 OF INSTRUCTION CLOCK. BCF RP0 ;RETURN TO PAGE 0 FOR PORT ACCESS. CLRF TMR0 ;SETS 1ST INTERUPT TO 9mS. MOVLW B'10100000' ;ENABLE TMR0 OVERFLOW INTERUPT. MOVWF INTCON MOVLW B'11111100' ;SET RB1-7 HIGH, RB0 WILL BE LOW MOVWF PORTB ;WHEN SET AS AN OUTPUT. CALL INIT_LCD ;SETUP THE LCD DISPLAY. CALL GET_SETUP ;GET SETUP INFO FROM EEPROM. ;***************************************************************************************** ; MAIN DISPLAY ;***************************************************************************************** MAIN_DISP: CALL SET_TIMEOUT ;SET THE DISPLAY TIMEOUT DOWN COUNTER. BCF TIMEOUT ;CLEAR THE DISPLAY TIMEOUT FLAG. MOVLW H'8F' ;H'C7' CALL LCD_CMD ;POSITION THE CURSOR, LINE 2 POS 8. MOVLW LOCKED ;DISPLAY 'L'. CALL LCD_TEXT CALL DISP_MHZ ;DISPLAY ' MHz ' ON LINE 2 POS 3. MAIN_LOOP: BTFSC TIMEOUT ;HAS THE DISPLAY TIMEOUT BEEN REACHED? GOTO MAIN_DISP ;Y. REDRAW THE MAIN DISPLAY. BSF EEPROM_UPDATE CALL UPDATE_EEPROM ;SEE IF EEPROM UPDATE IS REQUIRED. MOVLW H'8E' ;H'C6' CALL LCD_CMD ;POSITION THE CURSOR, LINE 2 POS 7. MOVLW UN ;PREPARE TO DISPLAY 'X'. ;BTFSS PLL_DIV_OK ;IS THE PLL DIVIDER SETTING VALID ;GOTO PLL_NOT_LOCKED ;BCF PLL_STATUS,6 BTFSS PLL_STATUS,6 ;AND, IS THE PLL LOCKED? GOTO PLL_NOT_LOCKED MOVLW TWO_SPACES ;Y. DISPLAY ' '. PLL_NOT_LOCKED: CALL LCD_TEXT ;N. DISPLAY 'UN'. MOVLW DISP_FREQ ;OLD PTT IS LOW SO, CALL MOVE_TO_ARG ;PREPARE TO INC/DEC TX FREQ. CALL UP_DOWN ;CHECK UP DOWN BUTTONS FOR INC/DEC. MOVLW MIN_DISP_FREQ ;MAKE SURE WE DONT GO BELOW THE MINIMUM CALL MOVE_TO_ARG2 ;SET BY MIN_DISP_FREQ. CALL MAXIMUM MOVLW MAX_DISP_FREQ ;MAKE SURE WE DONT GO ABOVE THE MAXIMUM CALL MOVE_TO_ARG2 ;SET BY MAX_DISP_FREQ. CALL MINIMUM MOVLW DISP_FREQ ;SAVE THE TX FREQ. CALL COPY_FROM_ARG SKIP_BUTTONS: CALL UPDATE_PLL ;UPDATE PLL AND RETURN THE DISPLAY FREQ. CALL DISPLAY_FREQ ;DISPLAY THE VARIABLE. GOTO MAIN_LOOP ; ;***************************************************************************************** ; MISC ROUTINES USED BY THE DISPLAY ROUTINES. ; ; DISP_MHZ DISPLAY ' MHz ' ON LINE 2 POS 11. ;. ; DISPLAY_FREQ DISPLAY A NUMBER ON LINE 2 OF LCD. ; NUM x 5 x DISP_MULT. ; ; UP_DOWN_OFFSET INC/DEC THE RX/TX VCO OFFSET, ; AND MAKES SURE THE OFFSET IS NOT TO BIG. ; ; UP_DOWN_MIN USED BY MIN TX & RX MENU DISPLAYS. ; ; MAX_CHECK USED BY MAX TX & RX MENU DISPLAYS. ; ; UPDATE_PLL CHECK THE STATE OF PTT, SELECT RX/TX FREQ, ; ADD ANY OFFSET & SET THE PLL DIVIDER. ; ALSO CHECKS PLL STATUS. ;***************************************************************************************** DISP_MHZ: MOVLW H'8A' ;H'C2' CALL LCD_CMD ;POSITION THE CURSOR, LINE 2 POS 11. MOVLW MHZ CALL LCD_TEXT ;DISPLAY ' MHz'. RETURN ;----------------------------------------------------------------------------------------- MAX_CHECK: CALL MOVE_TO_ARG2 ;GET MIN_RX_DISP_FR OR MIN_DISP_FREQ. GOTO U_D_MIN ;MAKE SURE THE RESULT IS NOT TO LARGE. ;----------------------------------------------------------------------------------------- UP_DOWN_MIN: CALL MOVE_TO_ARG CALL UP_DOWN ;CHECK UP DOWN BUTTONS FOR INC/DEC. CLRF ARG2_H ;MAKE SURE THE RESULT IS NOT TO SMALL. CLRF ARG2_L U_D_MIN: CALL MAXIMUM MOVLW DISP_MAX_H ;MAKE SURE THE RESULT IS NOT TO LARGE. MOVWF ARG2_H MOVLW DISP_MAX_L MOVWF ARG2_L CALL MINIMUM RETURN ;----------------------------------------------------------------------------------------- DISPLAY_FREQ: BCF NEGATIVE ;CLEAR THE NEGATIVE FLAG. COMF ARG_H,W ;NUM BETWEEN 49151 AND 65535(C000 - FFFF) ANDLW B'11000000' ;WE CLASS AS A NEGATIVE NUMBER. BTFSS ZERO ;IS IT A NEGATIVE NUMBER? GOTO DISPL_FREQ ;N. JUST CONTINUE. BSF NEGATIVE ;Y. SET THE NEGATIVE FLAG. COMF ARG_H,F ; CONVERT IT TO A + NUMBER. COMF ARG_L,F ; COMPLIMENT ARG, THEN ADD 1. MOVLW 1 ADDWF ARG_L,F BTFSC CARRY INCF ARG_H,F DISPL_FREQ: MOVF MULT_NUM,W ;GET THE DISPLAY MULTIPLIER NUMBER. MOVWF ARG BCF CARRY ;Teiler anpassen auch für 10 GHz RLF ARG_H,F ;Teiler * 2 BCF CARRY ;Multiplikator = 250 !!! RLF ARG_L,F BTFSC CARRY INCF ARG_H,F BCF CARRY ;RLF ARG,F ;Multiplikator für 2,5 GHz =1 !!! ;RLF ARG,F ;SIZE OF 50KHz. (125kHz /25kHz = ;ADDWF ARG,F ;MOVF ARG,W ;MOVWF ARG ;BCF CARRY ;MULTIPLY THE MULTIPLIER BY 5 ;RLF ARG,F ;TO TAKE INTO ACCOUNT THE PLL STEP ;RLF ARG,F ;SIZE OF 50KHz. ;ADDWF ARG,F ;MOVF ARG,W ;MOVWF ARG ;BCF CARRY ;MULTIPLY THE MULTIPLIER BY 5 ;RLF ARG,F ;TO TAKE INTO ACCOUNT THE PLL STEP ;RLF ARG,F ;SIZE OF 50KHz. ;ADDWF ARG,F CALL MULTIPLY ;ARG x 125 x MULT_NUM. CALL BIN_TO_DEC ;CONVERT THE NUMBER TO ASCII DECIMAL. MOVLW H'80' ;POSITION THE CURSOR, LINE 2 POS 2(C1). CALL LCD_CMD MOVLW DEC_0 ;SET THE POINTER TO THE START MOVWF FSR ;OF THE DECIMAL BUFFER. MOVLW 9 ;8 DIGIT + DECIMAL POINT TO DISPLAY. MOVWF COUNT DISP_LOOP: MOVF INDF,W ;GET CHR POINTED TO BY FSR. CALL LCD_CHR ;DISPLAY THE CHR. INCF FSR,F ;INC THE POINTER. DECFSZ COUNT,F ;ALL DONE? GOTO DISP_LOOP ;N. CONTINUE. MOVLW H'79' ;POSITION THE CURSOR, LINE 2 POS 1 (C0) CALL LCD_CMD MOVF INDF,W ;GET letzte Stelle CALL LCD_CHR ;DISPLAY THE CHR. RETURN ;----------------------------------------------------------------------------------------- UP_DOWN_OFFSET: CALL MOVE_TO_ARG MOVLW B'10000000' ;ADD H'8000' TO ARG. MAKES IT EASY TO XORWF ARG_H,F ;DEAL WITH NEGATIVE NUMBERS. CALL UP_DOWN ;CHECK UP DOWN BUTTONS FOR INC/DEC. MOVLW OFFSET_MAX_H ^ H'80' MOVWF ARG2_H ;MAKE SURE THE RESULT IS NOT TO LARGE. MOVLW OFFSET_MAX_L ;ARG2 = +500MHz. (+ H'8000') MOVWF ARG2_L CALL MINIMUM ;RETURN THE MINIMUM OF ARG & ARG2. MOVLW OFFSET_MIN_H ^ H'80' MOVWF ARG2_H ;MAKE SURE THE RESULT IS NOT TO SMALL. MOVLW OFFSET_MIN_L ;ARG2 = -500MHz. (+ H'8000') MOVWF ARG2_L CALL MAXIMUM ;RETURN THE MAXIMUM OF ARG & ARG2. MOVLW B'10000000' ;REMOVE THE H'8000' OFFSET. XORWF ARG_H,F RETURN ;----------------------------------------------------------------------------------------- UPDATE_PLL: CALL GET_PLL_STATUS ;UPDATE THE STATUS BYTE. (PLL LOCKED ?) MOVLW DISP_FREQ ;TX. MOVE TX DISPLAY FREQ TO ARG. CALL MOVE_TO_ARG MOVLW 3,TEMP_H ;TX. SAVE TX DISP FREQ FOR LATER ON. CALL COPY_FROM_ARG MOVLW VCO_OFFSET ;TX. GET THE RX VCO OFFSET. CALL MOVE_TO_ARG2 CALL ADD ;ADD THE VCO OFFSET. CALL SET_PLL ;SEND THE DIVIDER NUMBER TO THE PLL. MOVLW TEMP_H ;RECOVER THE TX/RX DISP FREQ. CALL MOVE_TO_ARG RETURN ;***************************************************************************************** ; LCD ROUTINES. LCD_CHR SEND A CHARACTER TO THE LCD DISPLAY. ; LCD_CMD SEND A COMMAND INSTRUCTION TO THE LCD. ; LCD_TEXT SEND A TEXT STRING TO THE LCD. ; LCD_L1_P2 POSITION CURSOR LINE 1, POS 2. ; LCD_CLEAR CLEAR THE LCD, GOTO THE START OF LINE 1. ; LCD_SPACE DISPLAY A SPACE ON THE LCD. ; LCD_2_SPACES DISPLAY TWO SPACES ON THE LCD. ; LCD_3_SPACES DISPLAY THREE SPACES ON THE LCD. ;***************************************************************************************** LCD_3_SPACES CALL LCD_SPACE LCD_2_SPACES CALL LCD_SPACE LCD_SPACE: MOVLW ' ' LCD_CHR: MOVWF TEMP_H ;SAVE THE BYTE TO SEND TO THE LCD. MOVWF TEMP_L BSF RS ;SELECT DISPLAY DATA REGISTER. GOTO LCD_BYTE ;----------------------------------------------------------------------------------------- LCD_CLEAR: MOVLW H'01' ;CLEAR THE DISPLAY. CALL LCD_CMD MOVLW 24 ;WAIT 20mS. LCD EXECUTION TIME = 5mS. CALL DELAY2 ;(845uS x 24) RETURN LCD_L1_P2: MOVLW H'81' ;POSITION THE CURSOR, LINE 1 POS 2. LCD_CMD: MOVWF TEMP_H ;SAVE THE BYTE TO SEND TO THE LCD. MOVWF TEMP_L BCF RS ;SELECT INSTRUCTION REGISTER. CALL LCD_BYTE ;SEND THE BYTE TO THE LCD. BSF RS ;RESTORE THE RS (SCL)TO ITS NORMAL STATE. RETURN ;----------------------------------------------------------------------------------------- LCD_TEXT: MOVWF TEMP ;TEMP HOLDS TEXT START ADDRESS. CALL TABLE ANDLW H'FF' BTFSC ZERO ;AT END OF MESSAGE? (0 RETURNED AT END) RETURN ;Y. ALL DONE. CALL LCD_CHR ;N. DISPLAY CHARACTER. MOVF TEMP,W ; POINT TO NEXT CHARACTER. ADDLW 1 GOTO LCD_TEXT ;----------------------------------------------------------------------------------------- LCD_BYTE: BSF RP0 ;SELECT PAGE 1 FOR TRIS REG ACCESS. MOVLW B'00000001' MOVWF PORTB ;SET UPPER 7 BITS AS OUTPUTS. BCF RP0 ;RETURN TO PAGE 0 FOR PORT ACCESS. BSF E ;SET THE LCD CLOCK. MOVLW B'11110000' ANDWF TEMP_H,F ;STRIP LOW NIBBLE FROM THE BYTE TO SEND. MOVF PORTB,W ;GET CURRENT PORT SETINGS. ANDLW B'00001110' ;KEEP THE LOW NIBBLE UNCHANGED. IORWF TEMP_H,W ;COMBINE THE TWO NIBBLES. MOVWF PORTB ;SEND NIBBLE TO LCD. BCF E ;CLOCK THE NIBLE INTO THE LCD. BSF E ;SET THE LCD CLOCK. SWAPF TEMP_L,F ;SWAP THE UPPER AND LOWER NIBBLES. MOVLW B'11110000' ANDWF TEMP_L,F ;STRIP LOW NIBBLE FROM THE BYTE TO SEND. MOVF PORTB,W ;GET CURRENT PORT SETINGS. ANDLW B'00001110' ;KEEP THE LOW NIBBLE UNCHANGED. IORWF TEMP_L,W ;COMBINE THE TWO NIBBLES. MOVWF PORTB ;SEND NIBBLE TO LCD. BCF E ;CLOCK THE NIBLE INTO THE LCD. MOVLW 75 ;WAIT 250uS. LCD EXECUTION TIME = 120uS. CALL DELAY ;(3.3uS x 75) RETURN ;----------------------------------------------------------------------------------------- ; INITIALISE THE LCD IN 4 BIT MODE. ;----------------------------------------------------------------------------------------- INIT_LCD: CLRF PORTB ;SET RS,RW,E & SDA LOW. CALL LCD_RESET ;RESET THE LCD. CALL LCD_RESET ;RESET THE LCD. CALL LCD_RESET ;RESET THE LCD. MOVLW B'00101000' ;LCD 4 BIT MODE COMMAND. MOVWF PORTB ;ALSO E HIGH. BCF E CALL LONG_DELAY MOVLW B'00101000' ;SET LCD TO 2 LINE, 5x7 DOT. CALL LCD_CMD MOVLW B'00001000' ;TURN DISPLAY OFF. CALL LCD_CMD CALL LCD_CLEAR ;CLEAR DISPLAY. MOVLW B'00000110' ;CURSOR INCREMENTS, NO DISPLAY SHIFT. CALL LCD_CMD MOVLW B'00001100' ;TURN LCD ON. GOTO LCD_CMD ;RETURN VIA LCD_CMD. ;----------------------------------------------------------------------------------------- LCD_RESET: CALL LONG_DELAY MOVLW B'00111000' ;LCD RESET COMMAND. MOVWF PORTB ;ALSO E HIGH. BCF E RETURN ;***************************************************************************************** ; I2C ROUTINES. SET_PLL GIVEN THE DIVIDER NUMBER IN ARG, CHECKS ; THAT THE NUMBER IS VALID THEN SENDS IT ; TO THE PLL. ; GET_PLL_STATUS GET THE STATUS BYTE FROM THE PLL, ; AND SETS THE TX_EN LEAD. ; I2C_START SEND AN I2C START SIGNAL ON THE BUS. ; I2C_TX_BYTE SEND THE BYTE IN W TO THE BUS. ; I2C_STOP SEND AN I2C STOP SIGNAL ON THE BUS. ;***************************************************************************************** SET_PLL: BCF MIN_MAX_CHANGE ;CLEAR THE ARG CHANGED FLAG. BSF PLL_DIV_OK ;SET THE VALID FLAG. CALL TRIM_NEG ;IF DIVIDER NUMBER IS NEGATIVE, MAKE IT 0. MOVLW PLL_DIV_MIN_H MOVWF ARG2_H ;MAKE SURE THE DIVIDER NUMBER IS NOT MOVLW PLL_DIV_MIN_L ;BELOW 50MHz. MOVWF ARG2_L CALL MAXIMUM MOVLW PLL_DIV_MAX_H MOVWF ARG2_H ;MAKE SURE THE DIVIDER NUMBER IS NOT MOVLW PLL_DIV_MAX_L ;ABOVE 1400MHz. MOVWF ARG2_L CALL MINIMUM MOVLW PLL_OLD ;GET THE OLD PLL DIVIDER NUMBER. CALL MOVE_TO_ARG2 CALL CMP ;SAME AS THE OLD DIVIDER NUMBER? BTFSC ZERO GOTO DONT_SEND ;Y. NO NEED TO RE-SEND THE NUMBER. MOVLW PLL_OLD ;N. SAVE THE NEW DIVIDER NUMBER. CALL COPY_FROM_ARG ; TO PLL_OLD. CALL I2C_START MOVLW PLL_ADDRESS ; SEND THE PLL ADDRESS. CALL I2C_TX_BYTE MOVF ARG_H,W ; SEND MSD BYTE OF THE PLL DIVIDER. CALL I2C_TX_BYTE MOVF ARG_L,W ; SEND LSB BYTE OF THE PLL DIVIDER. CALL I2C_TX_BYTE MOVLW B'10001110' ; SET CHARGE PUMP CURRENT TO 50uA CALL I2C_TX_BYTE ; P6=REF, P7=F/DIV. MOVLW B'00000000' ; OUTPUT PINS ACTIVE. CALL I2C_TX_BYTE CALL I2C_STOP ; SEND THE STOP COMMAND. BCF PLL_STATUS,6 ; THE PLL IS NOT LOCKED NOW. DONT_SEND: BTFSC MIN_MAX_CHANGE ;DID MIN OR MAX CHANGE THE DIVIDER NUM? BCF PLL_DIV_OK ;Y. CLEAR THE VALID FLAG. (INVALID) RETURN ;N. THE DIVIDER NUMBER WAS VALID. ;----------------------------------------------------------------------------------------- GET_PLL_STATUS: BTFSS PLL_STATUS,6 ;WAS PLL LOCKED WHEN LAST CHECKED? GOTO GET_STATUS ;N. GET THE CURRENT STATUS. MOVF LOCK_TIMER,W ;GET THE CURRENT PLL LOCKED TIMER. CALL RS_LOCKED_TMR ;Y. RESET THE LOCKED TIMER. GET_STATUS: CALL I2C_START ;SEND AN I2C START SIGNAL. MOVLW PLL_ADDRESS + 1 ;I2C ADDRESS & READ BIT. CALL I2C_TX_BYTE ;SEND THE ADDRESS BYTE TO THE PLL. MOVLW 8 MOVWF COUNT ;SET THE NUMBER OF BITS TO RECEIVE. RX_BIT_LOOP: CALL I2C_DELAY BSF SCL CALL I2C_DELAY RRF PORTA,W ;MOVE THE SDA (BIT 0) INTO THE CARRY BIT. RLF PLL_STATUS,F ;SAVE THE REVEIVED BIT. BCF SCL DECFSZ COUNT,F GOTO RX_BIT_LOOP ;LOOP UNTIL 8 BITS RECEIVED. CALL LET_SDA_HIGH ;SEND AN I2C NEVATIVE ACKNOWLEDGE. CALL I2C_CLOCK ;(SDA HIGH) CALL I2C_STOP ;SEND AN I2C STOP SIGNAL. BTFSC PLL_STATUS,6 ;IS PLL LOCKED NOW? CALL RS_LOCKED_TMR ;Y. RESET THE LOCKED TIMER. RS_LOCKED_TMR: MOVLW LOCK_TM ;RESET THE PLL LOCKED TIMER. MOVWF LOCK_TIMER RETURN ;----------------------------------------------------------------------------------------- I2C_TX_BYTE: MOVWF TEMP ;SAVE THE BYTE TO TX IN TEMP. MOVLW 8 ;SET THE NUMBER OF BITS TO TRANSMIT. MOVWF COUNT TX_BIT_LOOP: RLF TEMP,F ;MOVE THE MSB INTO THE CARRY. BTFSC CARRY CALL LET_SDA_HIGH ;IF CARRY IS SET, SET THE SDA. BTFSS CARRY CALL PULL_SDA_LOW ;IF CARRY IS CLEAR, CLEAR THE SDA. CALL I2C_CLOCK ;LATCH THE DATA INTO THE PLL. DECFSZ COUNT,F GOTO TX_BIT_LOOP ;LOOP UNTIL ALL BITS ARE SENT. CALL LET_SDA_HIGH ;LET THE SDA FLOAT HIGH. CALL I2C_CLOCK ;SEND AN I2C ACKNOWLEGE SIGNAL. RETURN ;----------------------------------------------------------------------------------------- I2C_START: BSF SCL ;SEND AN I2C START SIGNAL. CALL LET_SDA_HIGH CALL I2C_DELAY CALL PULL_SDA_LOW GOTO I2C_CLOCK2 ;----------------------------------------------------------------------------------------- I2C_STOP: CALL PULL_SDA_LOW ;SEND AN I2C STOP SIGNAL. CALL I2C_DELAY BSF SCL CALL I2C_DELAY CALL LET_SDA_HIGH CALL I2C_DELAY RETURN ;----------------------------------------------------------------------------------------- I2C_CLOCK: CALL I2C_DELAY BSF SCL ;PULSE THE SCL LINE I2C_CLOCK2: CALL I2C_DELAY BCF SCL ; " RETURN ;----------------------------------------------------------------------------------------- PULL_SDA_LOW: BCF SDA ;SDA WILL BE LOW WHEN SET AS O/P. BSF RP0 ;SELECT PAGE 1 FOR TRIS REG ACCESS. BCF SDA ;SET SDA AS AN OUTPUT. BCF RP0 ;RETURN TO PAGE 0 FOR PORT ACCESS. RETURN ;----------------------------------------------------------------------------------------- LET_SDA_HIGH: BSF RP0 ;SELECT PAGE 1 FOR TRIS REG ACCESS. BSF SDA ;SET SDA AS AN INPUT. BCF RP0 ;RETURN TO PAGE 0 FOR PORT ACCESS. RETURN ;----------------------------------------------------------------------------------------- I2C_DELAY MOVLW 15 DELAY: MOVWF COUNT1 ; 15 LOOPS (3CLOCKS) = 50 uS. I2C_LOOP: DECFSZ COUNT1,F GOTO I2C_LOOP RETURN ;***************************************************************************************** ; BIN_TO_DEC CONVERT A 24 BIT BINARY NUMBER TO A 8 DIGIT ASCII DECIMAL NUMBER. ; ; FIRST THE 24 BIT BINARY NUMBER IS CONVERTED TO 8 DIGIT BCD, TWO DIGITS PER BYTE IN ; EACH OF DEC_1, DEC_3, DEC_5 AND DEC_7. ; THE BCD IS THEN UNPACKED TO ONE DIGIT PER BYTE IN DEC_0 TO DEC_7. ; IT IS THEN CONVERTED TO ASCII, INCLUDING NEGATIVE SIGN, DECIMAL POINT AND LEADING ; ZERO BLANKING, READY FOR DISPLAY ON THE LCD. ; ; THE 24 BIT BINARY NUMBER IS INPUT IN LOCATIONS RESULT_H, RESULT_M AND ; RESULT_L WITH THE HIGH BYTE IN RESULT_H. ; THE 8 DIGIT DECIMAL NUMBER IS RETURNED IN DEC_0 - DEC_7 WITH DEC_0 ; CONTAINING THE MSD. ;***************************************************************************************** BIN_TO_DEC: BCF CARRY ;CLEAR THE CARRY BIT. MOVLW 24 MOVWF COUNT ;24 BITS TO PROCESS. CLRF DEC_1 ;BCD MSD DIGITS. CLRF DEC_3 CLRF DEC_5 CLRF DEC_7 ;BCD LSD DIGITS. LOOP24: RLF RESULT_L, F ;SHIFT 24 BIT NUMBER LEFT BY ONE BIT RLF RESULT_M, F ;INTO BCD. RLF RESULT_H, F RLF DEC_7, F RLF DEC_5, F RLF DEC_3, F RLF DEC_1, F DECFSZ COUNT, F GOTO ADJ_DEC ;ADJUST BCD DIGITS AND LOOP TO LOOP24. ;----------------------------------------------------------------------------------------- SWAPF DEC_7,W ;BINARY TO BCD CONVERSION DONE. MOVWF DEC_6 ;UNPACK THE BCD TO ONE CHR PER BYTE. SWAPF DEC_5,W MOVWF DEC_4 SWAPF DEC_3,W MOVWF DEC_2 SWAPF DEC_1,W MOVWF DEC_0 BCF LEAD_Z ;BLANK LEADING ZERO,S UNTIL THE FLAG IS MOVLW DEC_0 ;SET BY A NON ZERO NUMBER. CALL ADJ_ASCII MOVLW DEC_1 CALL ADJ_ASCII MOVLW DEC_2 CALL ADJ_ASCII MOVLW DEC_3 CALL ADJ_ASCII MOVLW DEC_4 CALL ADJ_ASCII BSF LEAD_Z ;ALWAYS DISPLAY CHR BEFORE DECIMAL POINT. MOVLW DEC_5 CALL ADJ_ASCII MOVLW DP MOVWF DECIMAL_POINT ;INSERT A DECIMAL POINT. MOVLW DEC_6 CALL ADJ_ASCII MOVLW DEC_7 CALL ADJ_ASCII BTFSS NEGATIVE ;WAS THIS A NEGATIVE NUMBER? RETURN ;N. JUST RETURN. MOVF NEG_POSITION,W ;Y. GET POSITION OF LAST BLANK. MOVWF FSR MOVLW '-' ; PLACE A - SIGN IN FRONT OF THE NUMBER. MOVWF INDF RETURN ;----------------------------------------------------------------------------------------- ADJ_DEC: MOVLW DEC_7 ;CALL ADJ_BCD TO ADJUST EACH OF CALL ADJ_BCD ;THE 4 BCD DIGITS. MOVLW DEC_5 CALL ADJ_BCD MOVLW DEC_3 CALL ADJ_BCD MOVLW DEC_1 CALL ADJ_BCD GOTO LOOP24 ;----------------------------------------------------------------------------------------- ADJ_BCD: MOVWF FSR ;MAKE SURE THE BCD DIGITS ARE VALID. MOVLW 3 ;CHECK LOW NIBBLE (LSD). ADDWF INDF,W ;IF LSD + 3 > 7 THEN LSD = LSD + 3. MOVWF TEMP ;ADD 3 TO LSD. BTFSC TEMP,3 ;IS RESULT > 7 ? MOVWF INDF ;Y. LSD = LSD + 3. MOVLW H'30' ;CHECK HIGH NIBBLE (MSD). ADDWF INDF,W ;IF MSD + 3 > 7 THEN MSD = MSD + 3. MOVWF TEMP ;ADD 3 TO MSD. BTFSC TEMP,7 ;IS RESULT > 7 ? MOVWF INDF ;Y. MSD = MSD + 3. RETURN ;----------------------------------------------------------------------------------------- ADJ_ASCII: MOVWF FSR MOVLW B'00001111' ;CLEAR THE HIGH NIBBLE. ANDWF INDF,W BTFSC ZERO GOTO BLANK NO_BLANK ADDLW H'30' ;CONVERT TO ASCII. MOVWF INDF BSF LEAD_Z RETURN BLANK: BTFSC LEAD_Z ;IF FLAG IS SET, DONT BLANK ZERO'S. GOTO NO_BLANK MOVLW ' ' ;IF FLAG IS NOT SET, BLANK ZERO'S. MOVWF INDF MOVF FSR,W ;SAVE THE LOCATION OF THE LAST BLANK MOVWF NEG_POSITION ;SO THAT A NEGATIVE SIGN CAN BE INSERTED. RETURN ;***************************************************************************************** ; ; MULTIPLY 16x8 BIT UNSIGNED FIXED POINT MULTIPLY 16x8 -> 24 ; ; Input: 16 BIT UNSIGNED FIXED POINT MULTIPLICAND IN ARG_H, ARG_L ; 8 BIT UNSIGNED FIXED POINT MULTIPLIER IN ARG ; ; Output: 24 BIT UNSIGNED FIXED POINT PRODUCT IN RESULT_H-M-L ; ;***************************************************************************************** MULTIPLY: CLRF RESULT_L ; CLEAR PARTIAL PRODUCT. MOVF ARG_H,W MOVWF RESULT_H MOVF ARG_L,W MOVWF RESULT_M MOVLW 8 MOVWF COUNT ;8 BITS TO PROCESS. MULT_LOOP1: RRF ARG, F ;SHIFT THE 8 BIT ARG RIGHT. LSD TO CARRY. BTFSC CARRY ;IS THE CARRY BIT = 1? GOTO MULT_1 DECFSZ COUNT, F GOTO MULT_LOOP1 CLRF RESULT_H CLRF RESULT_M RETURN MULT_1: BCF CARRY GOTO MULT_2 MULT_LOOP2: RRF ARG, F BTFSS CARRY GOTO MULT_2 MOVF ARG_L,W ;Y. ADD MULTIPLICAND TO HIGH ORDER ADDWF RESULT_M, F ; PARTIAL PRODUCT. MOVF ARG_H,W BTFSC CARRY INCFSZ ARG_H,W ADDWF RESULT_H, F MULT_2: RRF RESULT_H, F ;RIGHT SHIFT PARTIAL PRODUCT. RRF RESULT_M, F RRF RESULT_L, F DECFSZ COUNT, F GOTO MULT_LOOP2 RETURN ;***************************************************************************************** ; ; ADD 16 BIT ADDITION. ARG + ARG2 = ARG (ARG 2 NOT CHANGED) ; ; INPUT: 16 BIT ARGMENT 1 IN ARG_H, ARG_L. ; 16 BIT ARGMENT 2 IN ARG2_H, ARG2_L. ; ; OUTPUT: 16 BIT RESULT IN ARG_H, ARG_L. ; CARRY FLAG SET IF RESULT OVERFLOWED. ; ;***************************************************************************************** ADD: MOVF ARG2_L,W ADDWF ARG_L,F ;ADD THE LOW BYTES. MOVF ARG2_H,W BTFSC CARRY ;WAS THERE WAS A CARRY FROM THE LOW BYTE? INCFSZ ARG2_H,W ;Y. INC THE HIGH BYTE. ADDWF ARG_H,F ;ADD THE HIGH BYTES. RETURN ;***************************************************************************************** ; ; SUB 16 BIT SUBTRACTION. ARG - ARG2 = ARG (ARG 2 NOT CHANGED) ; ; INPUT: 16 BIT ARGMENT 1 IN ARG_H, ARG_L. ; 16 BIT ARGMENT 2 IN ARG2_H, ARG2_L. ; ; OUTPUT: 16 BIT RESULT IN ARG_H, ARG_L. ; (CARRY FLAG CLEAR (BORROW) IF RESULT WAS NEGATIVE.) ; ;***************************************************************************************** SUB: MOVF ARG2_L,W SUBWF ARG_L,F ;SUB THE LOW BYTES. MOVF ARG2_H,W BTFSS CARRY ;WAS THERE WAS A BORROW FROM THE LOW BYTE? INCFSZ ARG2_H,W ;Y. INC THE HIGH BYTE OF ARG 2. SUBWF ARG_H,F ;SUB THE HIGH BYTES. RETURN ;***************************************************************************************** ; ; CMP 16 BIT COMPARE. ARG - ARG2 (ARG & ARG 2 NOT CHANGED) ; ; INPUT: 16 BIT ARGMENT 1 IN ARG_H, ARG_L. ; 16 BIT ARGMENT 2 IN ARG2_H, ARG2_L. ; ; OUTPUT: CARRY FLAG CLEAR (BORROW) IF RESULT WAS NEGATIVE. ; ZERO FLAG SET IF RESULT IS ZERO. ; ;***************************************************************************************** CMP: MOVF ARG2_L,W SUBWF ARG_L,W ;SUB THE LOW BYTES. MOVWF TEMP ;SAVE THE LOW BYTE FOR ZERO CHECK. MOVF ARG2_H,W BTFSS CARRY ;WAS THERE WAS A BORROW FROM THE LOW BYTE? INCF ARG2_H,W ;Y. INC THE HIGH BYTE OF ARG 2. SUBWF ARG_H,W ;SUB THE HIGH BYTES. IORWF TEMP,W ;CHECK FOR ZERO RESULT. RETURN ;***************************************************************************************** ; ; MINIMUM 16 BIT UNSIGNED MIN. RETURN THE SMALLEST OF TWO ARGMENTS. ; ; INPUT: 16 BIT ARGMENT 1 IN ARG_H, ARG_L. ; 16 BIT ARGMENT 2 IN ARG2_H, ARG2_L. ; ; OUTPUT: THE SMALLEST ARGMENT IS RETURNED IN ARG_H, ARG_L. ; ;***************************************************************************************** MINIMUM: MOVF ARG2_H,W ;SAVE ARG 2. MOVWF ARG3_H MOVF ARG2_L,W MOVWF ARG3_L MOVLW 1 ;INC THE ARG2 BY 1. ADDWF ARG2_L,F BTFSC CARRY INCF ARG2_H,F CALL CMP BTFSS CARRY ;IS ARG 1 > ARG 2 ? RETURN ;N. JUST RETURN. MOVLW ARG3_H ;Y. SET ARG 1 THE SAME AS ARG 2. GOTO RETURN_ARG ; INDICATE THAT ARG HAS BEEN CHANGED. ;***************************************************************************************** ; ; MAXIMUM 16 BIT UNSIGNED MAX. RETURN THE LARGEST OF TWO ARGMENTS. ; ; INPUT: 16 BIT ARGMENT 1 IN ARG_H, ARG_L. ; 16 BIT ARGMENT 2 IN ARG2_H, ARG2_L. ; ; OUTPUT: THE LARGEST ARGMENT IS RETURNED IN ARG_H, ARG_L. ; ;***************************************************************************************** MAXIMUM: CALL CMP BTFSC CARRY ;IS ARG 1 > ARG 2 ? RETURN ;Y. NO CHANGE REQUIRED. MOVLW ARG2_H ;N. SET ARG 1 THE SAME AS ARG 2. RETURN_ARG: CALL MOVE_TO_ARG BSF MIN_MAX_CHANGE ; INDICATE THAT ARG HAS BEEN CHANGED. RETURN ;***************************************************************************************** ; MISC ROUTINES. MOVE_TO_ARG MOVE THE DOUBLE BYTE POINTED TO BY INDF ; REGISTER TO THE DOUBLE BYTE ARG VARIABLE. ; MOVE_TO_ARG2 MOVE THE DOUBLE BYTE POINTED TO BY INDF ; REGISTER TO THE DOUBLE BYTE ARG2 VARIABLE. ; COPY_FROM_ARG MOVE THE DOUBLE BYTE ARG VARIABLE TO THE ; ADDRESS POINTED TO BY INDF REGISTER. ; LONG_DELAY WAIT 100mS. ;***************************************************************************************** MOVE_TO_ARG: MOVWF FSR MOVF INDF,W MOVWF ARG_H INCF FSR,F MOVF INDF,W MOVWF ARG_L RETURN ;----------------------------------------------------------------------------------------- COPY_FROM_ARG: MOVWF FSR MOVF ARG_H,W MOVWF INDF INCF FSR,F MOVF ARG_L,W MOVWF INDF RETURN ;----------------------------------------------------------------------------------------- MOVE_TO_ARG2: MOVWF FSR MOVF INDF,W MOVWF ARG2_H INCF FSR,F MOVF INDF,W MOVWF ARG2_L RETURN ;----------------------------------------------------------------------------------------- LONG_DELAY: MOVLW 118 DELAY2: MOVWF COUNT1 ; 118 LOOPS OF 845 uS = 100 mS. CLRF COUNT2 ; 256 LOOPS (3CLOCKS) x 1.1uS = 845 uS. LD_LOOP: DECFSZ COUNT2,F GOTO LD_LOOP DECFSZ COUNT1,F GOTO LD_LOOP RETURN ;***************************************************************************************** ; UP_DOWN INC OR DEC THE VARIABLE IN ARG. (ARG_H, ARG_L) ; ; BY 1 WITH A QUICK PRESS OF FREQ + OR -. (SHIFT NOT PRESSED) ; BY MULTIPLE 2'S WITH A LONG PRESS OF FREQ + OR -. (SHIFT NOT PRESSED) ; BY 20 WITH A QUICK PRESS OF FREQ + OR -. (SHIFT PRESSED) ; BY MULTIPLE 200'S WITH A LONG PRESS OF FREQ + OR -. (SHIFT PRESSED) ;***************************************************************************************** UP_DOWN: CLRF ARG2_H CALL CHK_S_BRIEF BTFSC BUTTON_VALID ;IF FREQ + PRESSED CALL Faktor MOVFW MULT MOVWF MULT_TMP DECFSZ MULT_TMP,F GOTO NEXT1 GOTO Faktor1 NEXT1 DECFSZ MULT_TMP,F GOTO NEXT2 GOTO Faktor2 NEXT2 GOTO Faktor3 Faktor1 MOVLW 1 GOTO Übertrage Faktor2 MOVLW 80 GOTO Übertrage Faktor3 MOVLW 8 GOTO Übertrage Übertrage MOVWF ARG2_L CALL CHK_P_BRIEF BTFSC BUTTON_VALID ;IF FREQ + PRESSED CALL ADD ;INC BY 1 OR 20. CALL CHK_N_BRIEF BTFSC BUTTON_VALID ;IF FREQ - PRESSED CALL SUB ;DEC BY 1 OR 20. TRIM_NEG: COMF ARG_H,W ;ANY NUMBER BETWEEN 49151 AND 65535. ANDLW B'11000000' ;(C000 - FFFF) BTFSS ZERO ;ARE INVALID SO SET ARG TO 0. RETURN CLRF ARG_H CLRF ARG_L RETURN ;***************************************************************************************** ; EEPROM ROUTINES. GET_SETUP MOVE THE 9 BYTES OF SETUP INFO ; FROM EEPROM TO RAM. ; UPDATE_EEPROM IF THE EEPROM WRITE UPDATE FLAG IS SET, ; PROGRAM ANY SETUP BYTES THAT HAVE CHANGED. ; READ_EEPROM READ A BYTE FROM EEPROM. ASSUMES THE ; EEPROM ADDRESS HAS BEEN PLACED IN EEADR. ; WRITE_EEPROM WRITE THE BYTE IN W TO EEPROM. ASSUMES THE ; EEPROM ADDRESS HAS BEEN PLACED IN EEADR. ;***************************************************************************************** GET_SETUP: CLRF EEADR ;POINT TO THE FIRST BYTE IN EEPROM. MOVLW MULT_NUM ;GET BASE ADDRESS OF RAM BUFFER. MOVWF FSR ;PLACE IT IN THE INDIRECT REGISTER. MOVLW 9 MOVWF COUNT ;9 BYTES TO READ. R_EEPROM_LOOP: CALL READ_EEPROM ;GET A BYTE FROM EEPROM. MOVWF INDF ;PLACE IT IN RAM. INCF EEADR,F ;PREPARE TO READ THE NEXT BYTE. INCF FSR,F DECFSZ COUNT,F GOTO R_EEPROM_LOOP ;LOOP UNTIL ALL BYTES READ. RETURN ;----------------------------------------------------------------------------------------- UPDATE_EEPROM: BTFSS EEPROM_UPDATE ;IS THE UPDATE REQUIRED FLAG SET? RETURN ;N. ALL DONE. BCF EEPROM_UPDATE ;CLEAR THE FLAG. CLRF EEADR ;POINT TO THE FIRST BYTE IN EEPROM. MOVLW MULT_NUM ;GET BASE ADDRESS OF RAM BUFFER. MOVWF FSR ;PLACE IT IN THE INDIRECT REGISTER. MOVLW 9 MOVWF COUNT ;9 BYTES TO PROGRAM. W_EEPROM_LOOP: CALL READ_EEPROM ;GET A BYTE FROM EEPROM. SUBWF INDF,W BTFSC ZERO ;IS IT THE SAME AS IT IS IN RAM. GOTO NO_CHANGE ;Y. NO NEED TO UPDATE THIS BYTE. MOVF INDF,W ;N. COPY THE BYTE FROM RAM TO EEPROM. CALL WRITE_EEPROM NO_CHANGE: INCF EEADR,F ;PREPARE TO READ THE NEXT BYTE. INCF FSR,F DECFSZ COUNT,F GOTO W_EEPROM_LOOP ;LOOP UNTIL ALL BYTES UPDATED. RETURN ;----------------------------------------------------------------------------------------- READ_EEPROM: BSF RP0 ;SELECT PAGE 1 FOR TRIS REG ACCESS. BSF RD ;PERFORM AN EEPROM READ. BCF RP0 ;RETURN TO PAGE 0 FOR PORT ACCESS. MOVF EEDATA,W ;GET THE READ BYTE. RETURN ;----------------------------------------------------------------------------------------- WRITE_EEPROM: MOVWF EEDATA ;PUT DATA TO BE WRITEN IN THE BUFFER. BSF RP0 ;SELECT PAGE 1 FOR TRIS REG ACCESS. BCF EEIF ;CLEAR THE EEPROM WRITE DONE FLAG. BSF WREN ;ENABLE EEPROM WRITE. MOVLW H'55' ;PERFORM REQUIRED SAFETY STEPS. MOVWF EECON2 MOVLW H'AA' MOVWF EECON2 BSF WR ;BEGIN THE WRITE. WRITE_LOOP: BTFSS EEIF ;LOOP UNTIL THE WRITE IS COMPLETED. GOTO WRITE_LOOP BCF RP0 ;RETURN TO PAGE 0 FOR PORT ACCESS. RETURN ;***************************************************************************************** ; BUTTON ROUTINES. CHK_S_BRIEF RETURN A TRUE FLAG IN RESULT, IF THE ; CHK_P_BRIEF BUTTON WAS PRESSED BRIEFLY. ; CHK_N_BRIEF (SHIFT, + FREQ OR - FREQ) ; ;***************************************************************************************** CHK_S_BRIEF: MOVF BUT_S_OLD,W ;GET THE OLD BUTTON STATE. SUBWF BUT_S_CNT,W ;COMPARE CURRENT AND SAVED BUTTON STATE. BTFSC CARRY GOTO ClearSCount BSF BUTTON_VALID GOTO SRaus ClearSCount: BCF BUTTON_VALID SRaus MOVF BUT_S_CNT,W MOVWF BUT_S_OLD RETURN ;----------------------------------------------------------------------------------------- CHK_P_BRIEF: MOVF BUT_P_OLD,W ;GET THE OLD BUTTON STATE. SUBWF BUT_P_CNT,W ;COMPARE CURRENT AND SAVED BUTTON STATE. BTFSC CARRY GOTO ClearPCount BSF BUTTON_VALID GOTO PRaus ClearPCount: BCF BUTTON_VALID PRaus MOVF BUT_P_CNT,W MOVWF BUT_P_OLD RETURN ;----------------------------------------------------------------------------------------- CHK_N_BRIEF: MOVF BUT_N_OLD,W ;GET THE OLD BUTTON STATE. SUBWF BUT_N_CNT,W ;COMPARE CURRENT AND SAVED BUTTON STATE. BTFSC CARRY GOTO ClearNCount BSF BUTTON_VALID GOTO NRaus ClearNCount: BCF BUTTON_VALID NRaus MOVF BUT_N_CNT,W MOVWF BUT_N_OLD RETURN ;----------------------------------------------------------------------------------------- Faktor DECFSZ MULT,F Return MOVLW 3 MOVWF MULT RETURN ;----------------------------------------------------------------------------------------- END