#INCLUDE P16F628A.INC __CONFIG _XT_OSC & _WDT_OFF & _LVP_OFF; XTAL OSC,ETC. ERRORLEVEL -302 ;SUPPRESS BANK SELECTION MESSAGES. #DEFINE DATA_PORT PORTB #DEFINE ADDR_PORT PORTA #DEFINE PRECISION 0X04; MAX NUMBER OF BYTES IN EQUATION. #DEFINE ADD_BYTES D'12' ;BYTES USED BY ADDITION ROUTINE. #DEFINE OSC_0 0X00; REF. OSCILLATOR VALUE TO MULTIPLY (was D0) #DEFINE OSC_1 0X3F; REQUIRED FREQUENCY BY, FOR DDS. (was 17) #DEFINE OSC_2 0X5C #DEFINE OSC_3 0X22 ; ;PORT B WILL BE USED AS DATA I/O BUS(8 BITS) CAN'T USE A, AS ;THAT INCLUDES CRYSTAL OSC. ;RA0 LINKS TO RS (PIN 4 ON DISPLAY) - ADDRESS FUNCTION PLUS DISPLAY CONTROL ;RA3 LINKS TO E (PIN 6 ON DISPLAY) - ADDRESS FUNCTION PLUS DISPLAY CONTROL ;RA3 = ENABLE ADDRESS DECODER STROBES. ;RA4 RESERVED FOR AD9850 FQ_LOAD ;NOTE THAT RA4 IS AN OPEN-COLLECTOR DRIVE - REQUIRES EXT. PULL-UP. ;WE WILL USE 8 BIT ADDRESSING, SO 7-14 OF DISPLAY LINK TO PORT B. ; RAMSTA EQU 0X20; START OF G.P. RAM. (BANK 0) RAMEND EQU 0X70 DELTIME EQU 0XFF; DELAY TIME. ; ;DISPLAY COMMAND DEFINES: CLEAR_DISPLAY EQU B'00000001' RETURN_HOME EQU B'00000010' DISPLAY_ON EQU B'00001111' ;(DISPLAY ON, CURSOR ON + BLINK). CURSOR_OFF EQU B'00001100' MODE EQU B'00111000' ;2 LINE DISPLAY, NORMAL CHAR. 8 BITS. ;OTHER DEFINES: ENTER_KEY EQU 0X0A PGM_KEY EQU 0X0C ZERO_KEY EQU 0X0B DDS_CLK EQU 0X00 DDS_DAT EQU 0X01 DDS_LOAD EQU 0X04 ;DISPLAY FLAGS/BIT DESIGNATORS: ADDR_DIS EQU 0X03 RS_BIT EQU 0X00 E_BIT EQU 0X03 ; NOTE THAT RA3 IS SHARED WITH ADDRESS ENABLE AND DISPLAY ENABLE. ; NO CONFLICT, SINCE ADDR. EN. = LOW, DISPLAY ENABLE = HIGH AND THE ; TWO FUNCTIONS ARE EXCLUSIVE. CBLOCK RAMSTA; DATA MEMORY ASSIGNMENT. FLAG_STATUS; RECORD OF A BORROW OR CARRY WHICH IS PASSED FORWARD. BYTE_COUNT; KEEP TRACK OF PAIRS DONE. CHAR_COUNT W_SAVE FSR_SAVE DELAY_COUNT BDELAY_COUNT TEXT_NUMBER CALCS CALC_SAVE KEYVAL ENCVAL MAX_DIGITS LAST_ENCVAL DIR ;ADDITION VARIABLES: ADDA1 ;(LSB) ADDB1 SUM1 ADDA2 ADDB2 SUM2 ADDA3 ADDB3 SUM3 ADDA4 ;(MSB) ADDB4 SUM4 ;FOR DECIMAL - HEX CONVERSION: FC ; TEMP STORAGE FB ;FOR D2HEX (DECIMAL TO HEX) CONVERSION. DI1; LSD DI2 DI3 DI4 DI5 DI6 DI7 DI8 DI9 DI10; MSD DIG_COUNT ITERATIONS; (NUMBER OF TIMES MULTIPLIER IS ADDED.) ;BUFFERS BUF1; LSB (HEX INPUT) BUF2 BUF3 BUF4; MSB ;FOR H2D (BINARY(HEX) TO DECIMAL) D1; LSB (BCD) D2 D3 D4 D5; MSB BCD_TEMP BCD_COUNT ;FOR MULTIPLICATION: TEMP_0 TEMP_1 TEMP_2 TEMP_3 TEMP_4 MULT_COUNT AD_0 AD_1 AD_2 AD_3 AD_4 FREQ_0; BINARY STORAGE OF WORKING FREQUENCY. FREQ_1 FREQ_2 FREQ_3 INC_0; BINARY STORAGE OF INCREMENT. INC_1 INC_2 INC_3 MEM_OVERFLOW; TEST FOR OVER-RUN OF RAM LIMIT. ENDC #DEFINE BUF5 D1; RE-USE RAM. #DEFINE BUF6 D2 #DEFINE BUF7 D3 #DEFINE BUF8 D4 #DEFINE BIT_COUNT BUF1 START ORG 0 GOTO MAIN;SKIP OVER SUBROUTINES. ;********************** PROC. UTILITY ROUTINES ******************* BANK0 BCF STATUS,RP0; SET STATUS BITS TO SELECT ONLY BANK 0. BCF STATUS,RP1 RETURN BANK1 BSF STATUS,RP0; SET STATUS BITS TO SELECT ONLY BANK 1. BCF STATUS,RP1 RETURN WRITE MOVWF W_SAVE CALL BANK1 MOVLW B'00000000';MAKE ALL PORT B LINES OUTPUTS. MOVWF TRISB CALL BANK0 MOVF W_SAVE,W RETURN READ MOVWF W_SAVE CALL BANK1 MOVLW B'11111111';MAKE ALL PORT B LINES INPUTS. MOVWF TRISB CALL BANK0 MOVF W_SAVE,W RETURN BIG_DELAY MOVWF W_SAVE MOVLW 0XFF VAR_BIG MOVWF BDELAY_COUNT MOVF W_SAVE, W NEXT_BIG CALL DELAY DECFSZ BDELAY_COUNT GOTO NEXT_BIG RETURN DELAY MOVWF W_SAVE MOVLW DELTIME MOVWF DELAY_COUNT NEXT_WAIT NOP NOP NOP NOP DECFSZ DELAY_COUNT,F GOTO NEXT_WAIT MOVF W_SAVE,W RETURN ;********************** END PROC. UTILITY ROUTINES ****************** ;********************** DISPLAY UTILLITY ROUTINES ******************* PULSE_ENABLE BSF ADDR_PORT, E_BIT CALL DELAY BCF ADDR_PORT, E_BIT RETURN INIT_DISPLAY CALL WRITE BSF ADDR_PORT,RS_BIT MOVLW DISPLAY_ON MOVWF DATA_PORT BCF ADDR_PORT,RS_BIT CALL PULSE_ENABLE BSF ADDR_PORT,RS_BIT CALL DELAY RETURN ;CLEAR DISPLAY CLR CALL DELAY CALL WRITE MOVLW CLEAR_DISPLAY MOVWF DATA_PORT BCF ADDR_PORT,RS_BIT GOTO COMMON_EXIT LCD_CHAR; OUTPUT CHAR. IN W TO DISPLAY. MOVWF DATA_PORT BSF ADDR_PORT, RS_BIT GOTO COMMON_EXIT CURSOR_HOME; LIKE IT SAYS. W IS PRESERVED. CALL WRITE CLRF ADDR_PORT MOVLW RETURN_HOME MOVWF DATA_PORT GOTO COMMON_EXIT NO_CURSOR CALL WRITE CLRF ADDR_PORT MOVLW CURSOR_OFF MOVWF DATA_PORT GOTO COMMON_EXIT CURSOR_ON CALL WRITE CLRF ADDR_PORT MOVLW DISPLAY_ON MOVWF DATA_PORT GOTO COMMON_EXIT SET_POS; MOVE CURSOR TO DIGIT DEFINED BY VALUE IN W. ; NOTE THAT THERE ARE 4 LINS OF TEXT (16 CHARS. EACH). ; TOP LINE STARTS AT POS. 0 ; SECOND LINE DOWN STARTS AT POS. 40 ; THIRD LINE DOWN STARTS AT POS. 16 ; FOURTH LINE DOWN STARTS AT POS.56 ; WIERD,OR WHAT? MOVWF CHAR_COUNT CALL CURSOR_HOME CLRF ADDR_PORT NEXT_POS MOVLW B'00010100' MOVWF DATA_PORT CALL PULSE_ENABLE DECFSZ CHAR_COUNT,F GOTO NEXT_POS GOTO COMMON_EXIT2 SET_MODE CALL WRITE CLRF ADDR_PORT MOVLW MODE MOVWF DATA_PORT COMMON_EXIT CALL PULSE_ENABLE COMMON_EXIT2 BSF ADDR_PORT, RS_BIT CALL DELAY RETURN ;**********************END DISPLAY UTILLITY ROUTINES***************** TEXT ;DISPLAY ONE OR MORE STRINGS ON DISPLAY. CLRF CHAR_COUNT NEXT_CHAR MOVF CHAR_COUNT,W CALL MESSAGE XORLW 0 BTFSC STATUS,Z ; SKIP IF NON-ZERO (MORE CHARACTERS) RETURN ; RETURN IF ZERO (END OF MESSAGE). CALL LCD_CHAR ; SEND CHAR. TO DISPLAY INCF CHAR_COUNT,F; CHAR_COUNT IS OFFSET POINTER TO MESSAGE. GOTO NEXT_CHAR MESSAGE MOVWF W_SAVE MOVF TEXT_NUMBER,W; SELECT MESSAGE. XORLW 1 BTFSC STATUS,Z ; SKIP IF NON-ZERO AND CHECK NEXT. GOTO M1 MOVF TEXT_NUMBER,W XORLW 2 BTFSC STATUS,Z GOTO M2 MOVF TEXT_NUMBER,W XORLW 3 BTFSC STATUS,Z GOTO M3 MOVF TEXT_NUMBER,W XORLW 4 BTFSC STATUS,Z GOTO M4 MOVF TEXT_NUMBER,W XORLW 5 BTFSC STATUS,Z GOTO M5 MOVF TEXT_NUMBER,W XORLW 6 BTFSC STATUS,Z GOTO M6 MOVF TEXT_NUMBER,W XORLW 7 BTFSC STATUS,Z GOTO M7 CLRF W ; DEFAULT - NOT FOUND RETURN 0. RETURN M1 MOVF W_SAVE,W ADDWF PCL,F DT "SG V1.1 (MW0SEC)",0; (CREATES SERIES OF RETLW COMMANDS). M2 MOVF W_SAVE,W ADDWF PCL,F DT "FREQ: ",0 M3 MOVF W_SAVE,W ADDWF PCL,F DT "Enter Incr(C/S):",0 M4 MOVF W_SAVE,W ADDWF PCL,F DT "WREG value: ",0 M5 MOVF W_SAVE,W ADDWF PCL,F DT "Enter Freq C/S:",0 M6 MOVF W_SAVE,W ADDWF PCL,F DT "Frequency (C/S):",0 M7 MOVF W_SAVE,W ADDWF PCL,F DT "Increment (C/S):",0 ; DISPLAY VALUE IN W (HEX FORMAT). ; NB - THIS ROUTINE IS ONLY USED FOR DIAGNOSTIC REASONS. DISPLAY_W; ; FIRST DO MSD. MOVWF CALC_SAVE MOVWF CALCS RRF CALCS,F; SHIFT NIBBLE DOWN. RRF CALCS,F RRF CALCS,F RRF CALCS,F MOVF CALCS,W ANDLW B'00001111' MOVWF CALCS SUBLW 0X09 BTFSC STATUS,C; IF CARRY SET NO < A. GOTO M_DECIMAL MOVF CALCS,W ADDLW 0X37 GOTO M_HEX M_DECIMAL MOVF CALCS,W ADDLW 0X30 M_HEX CALL LCD_CHAR; DISPLAY MSN. ; NOW DEAL WITH LOWER NIBBLE. MOVF CALC_SAVE,W ANDLW B'00001111'; MASK LOWER NIBBLE. MOVWF CALCS SUBLW 0X09 BTFSC STATUS,C GOTO L_DECIMAL MOVF CALCS,W ADDLW 0X37 GOTO L_HEX L_DECIMAL MOVF CALCS,W ADDLW 0X30; ASCII-ISE. L_HEX CALL LCD_CHAR; DISPLAY LOWER NIBBLE. MOVF CALC_SAVE, W RETURN ;********************************************************************* ; POLL KEYBOARD FOR DIGITS. EXIT WITH DIGIT,0X0A FOR ENTER, 0X0C FOR ; PROGRAMME/RESET IN KEYVAL, ELSE LOOP. ;********************************************************************* PROGRAMME MOVLW D'8'; CLEAR ALL BYTES IN BUFFER, REGARDLESS OF NO. IN USE. MOVWF BYTE_COUNT MOVF FSR,W MOVWF FSR_SAVE MOVLW 0XFF; FILL BUFFER WITH FF'S. DECF FSR NEXT_FILL INCF FSR MOVWF INDF DECFSZ BYTE_COUNT GOTO NEXT_FILL MOVF FSR_SAVE,W MOVWF FSR PROGRAMME2 INCF MAX_DIGITS; COME HERE TO KEEP MAX_DIGITS AT ZERO ONCE SET. GET_DIGIT CALL READ CALL TEST_KEY BTFSC KEYVAL,7 GOTO GET_DIGIT; WAIT FOR KEY. CALL WRITE MOVLW ZERO_KEY XORWF KEYVAL,W BTFSC STATUS,Z GOTO DEAL_WITH_ZERO MOVLW ENTER_KEY XORWF KEYVAL,W BTFSC STATUS,Z RETURN; EXIT FROM FUNCTION KEY. MOVLW PGM_KEY XORWF KEYVAL,W BTFSC STATUS,Z RETURN; EXIT FROM FUNCTION KEY. MOVF KEYVAL,W DEAL_WITH_ZERO DECF MAX_DIGITS BTFSC STATUS,Z ; MAX ENTRY? GOTO PROGRAMME2 MOVWF INDF; STORE THE DIGIT IN RAM AND INCR. POINTER. INCF FSR ADDLW 0X30; ASCII-ISE; DISPLAY CHAR. ON SCREEN. CALL LCD_CHAR WAIT_BOUNCE CALL READ CALL DELAY; DE-BOUNCE KEY. CALL DELAY CALL TEST_KEY BTFSC KEYVAL,7 GOTO GET_DIGIT GOTO WAIT_BOUNCE ; SCAN KEYBOARD TO SEE IF A KEY IS PRESSED. IF SO, RETURN WITH ; KEY IN KEYVAL. NB! ; BEFORE USE, "READ" MUST BE CALLED. ; IF NO KEY, KEYVAL RETURNS WITH BIT 7 SET. ; ELSE, KEY NUMBER 1-12 RETURNED. TEST_KEY MOVLW B'0000001'; INITIALLY STROBE "123" LINE OF KBD. MOVWF ADDR_PORT CLRF KEYVAL NEXT_STROBE ;DO BLOCK (EACH THREE KEYS) FOR STROBE 1,2,3,4 INCF KEYVAL BTFSS DATA_PORT,0; IF SET, THIS KEY IS NOT PRESSED. RETURN; KEY FOUND PRESSED. EXIT WITH KEY VAL. INCF KEYVAL BTFSS DATA_PORT,1 RETURN INCF KEYVAL BTFSS DATA_PORT,2 RETURN BTFSS ADDR_PORT,2; IS STROBE 4 REACHED? GOTO CONT_STROBE BSF KEYVAL,7 RETURN CONT_STROBE INCF ADDR_PORT; NEXT STROBE ADDRESS. GOTO NEXT_STROBE ; SCAN ENCODER TO SEE IF NEW SETTING ASSIGNED. ; BEFORE USE, "READ" MUST BE CALLED. ; RETURN WITH RESULT IN ENCVAL. TEST_ENCODER MOVLW 0X05; STROBE ENCODER. MOVWF ADDR_PORT MOVF DATA_PORT,W MOVWF ENCVAL COMF ENCVAL,F MOVF ENCVAL,W ANDLW B'00000011' MOVWF ENCVAL RETURN ; 0 = INDENT. ;************************ MULTIPLE-PRECISION ADD ROUTINE ********** ; THIS ROUTINE WILL ADD TWO GROUPS OF BYTES TOGETHER TO ANY REQUIRED ; PRECISION TAKING ACCOUNT OF CARRY IN/OUT. ; INPUTS: ; A POINTER TO THE ADDENDS AND SUMS. THEE ARE ARRANGED LSB FIRST, ; IN THE RISING SEQUENCE OF ADDEND 1A, ADDEND 2A, SUM A, ; ADDEND 1B, ADDEND 2B, SUM X.... TO REQUIRED PRECISION. ; BYTE_COUNT IS INITIALISED TO THE REQUIRED PRECISION AND MUST ; MATCH THE NUMBER OF DATA BLOCKS USED FOR EACH BYTE OF THE SUM. ; A CARRY IN MAY BE INCLUDED IN FLAG_STATUS IF REQUIRED, ; OTHERWISE THIS SHOULD BE CLEARED ON ENTRY. ;OUTPUTS: ; THE RESULTS ARE SAVED IN THE SUM BYTES (EVERY TWO BYTES ; AFTER THE FIRST ADDEND. (ADDEND1, ADDEND2, SUM). ; IF THERE WAS A CARRY ON THE LAST OPERATION THIS IS STORED ; IN FLAG_STATUS. ; REGISTERS AFFECTED: W, FSR, STATUS. ;****************************************************************** MPADD MOVLW ADDA1; INITIALISE INDIRECT POINTER. MOVWF FSR MOVLW PRECISION; STATE HOW MANY BYTES TO DEAL WITH. MOVWF BYTE_COUNT NEXT_A_PAIR MOVF INDF,W; GET FIRST ADDEND. INCF FSR; POINT TO SECOND ADDEND. ADDWF FLAG_STATUS,W; ADD IN ANY CARRY FROM PREVIOUS. CLRF FLAG_STATUS; THIS CARRY NOW INCLUDED, SO CLEAR. RLF FLAG_STATUS,F; RECORD ANY NEW CARRY ARISING. ADDWF INDF,W; ADD SECOND ADDEND. INCF FSR; MOVE POINTER TO SUM BYTE. BTFSC STATUS,C; CHECK FOR CARRY. INCF FLAG_STATUS; RECORD CARRY IF IT OCCURRED. MOVWF INDF; MOVE RESULT TO SUM BYTE. INCF FSR; INCREMENT POINTER TO NEXT PAIR. DECFSZ BYTE_COUNT; EXIT IF ALL BYTES DEALT WITH. GOTO NEXT_A_PAIR RETURN COPY_SUM ; COPY THE RESULT OF THE LAST ADDITION TO ADDEND 'A' MOVF SUM1,W MOVWF ADDA1 MOVF SUM2,W MOVWF ADDA2 MOVF SUM3,W MOVWF ADDA3 MOVF SUM4,W MOVWF ADDA4 RETURN CLEAR_MPADD MOVLW ADD_BYTES MOVWF DIG_COUNT MOVLW ADDA1; FIRST CLEAR ADDITION REGISTERS. MOVWF FSR DECF FSR CLEAR_NEXT INCF FSR CLRF INDF; CLEAR BYTE AND POINT TO NEXT. DECFSZ DIG_COUNT GOTO CLEAR_NEXT BCF STATUS,C CLRF FLAG_STATUS RETURN ;************************************************************************* ;THIS ROUTINE CONVERTS A SERIES OF DECIMAL DIGITS HELD AS NON-PACKED ;BYTES INTO A HEX NUMBER. WORKS BY ADDING ASCENDING VALUES OF TEN ;TO THE FINAL SUM. E.G. FOR 300, ADDS 100 THREE TIMES. ;RESULT IS LEFT IN SUM1-4 AFTER FINAL CALL OF MPADD. ;REQUIRES ROUTINES COPY_SUM, CLEAR_MPADD AND MPADD. ;************************************************************************* D2HEX CALL CLEAR_MPADD ; THE FIRST DIGIT WILL NOT REQUIRE CONVERSION, SO JUST PUT IT IN ADDEND A. MOVF DI1,W; UNITS MOVWF ADDA1 CALL MPADD CALL COPY_SUM MOVF DI2,W; (TENS) BTFSC STATUS,Z GOTO NO_TENS MOVWF ITERATIONS ADD_TENS MOVLW D'10' MOVWF ADDB1 CALL MPADD CALL COPY_SUM DECFSZ ITERATIONS GOTO ADD_TENS NO_TENS MOVF DI3,W; (HUNDREDS). BTFSC STATUS,Z GOTO NO_HUNDREDS MOVWF ITERATIONS ADD_HUNDREDS MOVLW D'100' MOVWF ADDB1 CALL MPADD CALL COPY_SUM DECFSZ ITERATIONS GOTO ADD_HUNDREDS NO_HUNDREDS MOVF DI4,W; (THOUSANDS) BTFSC STATUS,Z GOTO NO_THOUSANDS MOVWF ITERATIONS ADD_THOUSANDS MOVLW 0XE8 MOVWF ADDB1 MOVLW 0X03 MOVWF ADDB2 CALL MPADD CALL COPY_SUM DECFSZ ITERATIONS GOTO ADD_THOUSANDS NO_THOUSANDS MOVF DI5,W; (10,000'S). BTFSC STATUS,Z GOTO NO_10000S MOVWF ITERATIONS ADD_TEN_THOUSANDS MOVLW 0X10 MOVWF ADDB1 MOVLW 0X27 MOVWF ADDB2 CALL MPADD CALL COPY_SUM DECFSZ ITERATIONS GOTO ADD_TEN_THOUSANDS NO_10000S MOVF DI6,W; (100,000'S). BTFSC STATUS,Z GOTO NO_100K MOVWF ITERATIONS ADD_100KS MOVLW 0XA0 MOVWF ADDB1 MOVLW 0X86 MOVWF ADDB2 MOVLW 0X01 MOVWF ADDB3 CALL MPADD CALL COPY_SUM DECFSZ ITERATIONS GOTO ADD_100KS NO_100K MOVF DI7,W; (MEGS). BTFSC STATUS,Z GOTO NO_MEGS MOVWF ITERATIONS ADD_MEGS MOVLW 0X40 MOVWF ADDB1 MOVLW 0X42 MOVWF ADDB2 MOVLW 0X0F MOVWF ADDB3 CALL MPADD CALL COPY_SUM DECFSZ ITERATIONS GOTO ADD_MEGS NO_MEGS MOVF DI8,W; (10 MILLIONS). BTFSC STATUS,Z RETURN MOVWF ITERATIONS ADD_10MEGS MOVLW 0X80 MOVWF ADDB1 MOVLW 0X96 MOVWF ADDB2 MOVLW 0X98 MOVWF ADDB3 CALL MPADD CALL COPY_SUM DECFSZ ITERATIONS GOTO ADD_10MEGS RETURN ; PARSE LINE OF ENTERED DIGITS FROM BUF1(MSD)- BUF8 AND ARRANGE THE ; NUMBER IN DI1(LSD) - DI8. PARSE MOVLW 0X08; EIGHT BYTES TO CLEAR. MOVWF BYTE_COUNT MOVLW DI1-1; FIRST CLEAR THE BUFFER. MOVWF FSR NEXT_DI_CLEAR INCF FSR CLRF INDF DECFSZ BYTE_COUNT GOTO NEXT_DI_CLEAR BTFSC BUF1,7 RETURN; NO DIGITS AT ALL. MOVLW DI1 MOVWF FSR BTFSC BUF8,7 GOTO P0 MOVF BUF8,W MOVWF INDF INCF FSR P0 BTFSC BUF7,7 GOTO P1 MOVF BUF7,W MOVWF INDF INCF FSR P1 BTFSC BUF6,7 GOTO P2 MOVF BUF6,W MOVWF INDF INCF FSR P2 BTFSC BUF5,7 GOTO P3 MOVF BUF5,W MOVWF INDF INCF FSR P3 BTFSC BUF4,7 GOTO P4 MOVF BUF4,W MOVWF INDF INCF FSR P4 BTFSC BUF3,7 GOTO P5 MOVF BUF3,W MOVWF INDF INCF FSR P5 BTFSC BUF2,7 GOTO P6 MOVF BUF2,W MOVWF INDF INCF FSR P6 BTFSC BUF1,7 GOTO P7 MOVF BUF1,W MOVWF INDF P7 RETURN ; ***************************************************************************** ; * * ; * PURPOSE: MULTIPLY THE 32 BIT NUMBER FOR OSCILLATOR FREQUENCY TIMES THE * ; * 32 BIT NUMBER FOR THE DISPLAYED FREQUENCY. * ; * * ; * * ; * INPUT: THE REFERENCE OSCILLATOR VALUE DEF. IN OSC_3 ... OSC_0 AND THE * ; * CURRENT FREQUENCY STORED IN FREQ_3 ... FREQ_0. THE REFERENCE * ; * OSCILLATOR VALUE IS TREATED AS A FIXED POINT REAL, WITH A 24 * ; * BIT MANTISSA. * ; * * ; * OUTPUT: THE RESULT IS STORED IN AD_3 ... AD_0. * ; * * ; ***************************************************************************** ; CALC_DDS_WORD CLRF AD_0 ; CLEAR THE AD9850 CONTROL WORD BYTES CLRF AD_1 ; CLRF AD_2 ; CLRF AD_3 ; CLRF AD_4 ; MOVLW 0X20 ; SET COUNT TO 32 (4 OSC BYTES OF 8 BITS) MOVWF MULT_COUNT ; KEEP RUNNING COUNT MOVLW OSC_0 ; MOVE THE FOUR OSC BYTES MOVWF TEMP_0 ; TO TEMPORARY STORAGE FOR THIS MULTIPLY MOVLW OSC_1 ; (DON'T DISTURB ORIGINAL OSC BYTES) MOVWF TEMP_1 ; MOVLW OSC_2 ; MOVWF TEMP_2 ; MOVLW OSC_3 ; MOVWF TEMP_3 ; MULT_LOOP BCF STATUS,C ; START WITH CARRY CLEAR BTFSS TEMP_0,0 ; IS BIT 0 (LEAST SIGNIFICANT BIT) SET? GOTO NOADD ; NO, DON'T NEED TO ADD FREQ TERM TO TOTAL MOVF FREQ_0,W ; GET THE "NORMAL" FREQ_0 TERM ADDWF AD_1,F ; ADD IT IN TO TOTAL BTFSS STATUS,C ; DOES THIS ADDITION RESULT IN A CARRY? GOTO ADD7 ; NO, CONTINUE WITH NEXT FREQ TERM INCFSZ AD_2,F ; YES, ADD ONE AND CHECK FOR ANOTHER CARRY GOTO ADD7 ; NO, CONTINUE WITH NEXT FREQ TERM INCFSZ AD_3,F ; YES, ADD ONE AND CHECK FOR ANOTHER CARRY GOTO ADD7 ; NO, CONTINUE WITH NEXT FREQ TERM INCF AD_4,F ; YES, ADD ONE AND CONTINUE ADD7 MOVF FREQ_1,W ; GET THE "NORMAL" FREQ_0 TERM ADDWF AD_2,F ; ADD FREQ TERM TO TOTAL IN CORRECT POSITION BTFSS STATUS,C ; DOES THIS ADDITION RESULT IN A CARRY? GOTO ADD8 ; NO, CONTINUE WITH NEXT FREQ TERM INCFSZ AD_3,F ; YES, ADD ONE AND CHECK FOR ANOTHER CARRY GOTO ADD8 ; NO, CONTINUE WITH NEXT FREQ TERM INCF AD_4,F ; YES, ADD ONE AND CONTINUE ADD8 MOVF FREQ_2,W ; GET THE "NORMAL" FREQ_2 TERM ADDWF AD_3,F ; ADD FREQ TERM TO TOTAL IN CORRECT POSITION BTFSS STATUS,C ; DOES THIS ADDITION RESULT IN A CARRY? GOTO ADD9 ; NO, CONTINUE WITH NEXT FREQ TERM INCF AD_4,F ; YES, ADD ONE AND CONTINUE ADD9 MOVF FREQ_3,W ; GET THE "NORMAL" FREQ_3 TERM ADDWF AD_4,F ; ADD FREQ TERM TO TOTAL IN CORRECT POSITION NOADD RRF AD_4,F ; SHIFT NEXT MULTIPLIER BIT INTO POSITION RRF AD_3,F ; ROTATE BITS TO RIGHT FROM BYTE TO BYTE RRF AD_2,F ; RRF AD_1,F ; RRF AD_0,F ; RRF TEMP_3,F ; SHIFT NEXT MULTIPLICAND BIT INTO POSITION RRF TEMP_2,F ; ROTATE BITS TO RIGHT FROM BYTE TO BYTE RRF TEMP_1,F ; RRF TEMP_0,F ; DECFSZ MULT_COUNT,F ; ONE MORE BIT HAS BEEN DONE. ARE WE DONE? GOTO MULT_LOOP ; NO, GO BACK TO USE THIS BIT MOVLW 0X00 ; NO CLOCK MULTIPLIER (AD9850) MOVWF AD_4 ; LAST BYTE TO BE SENT ; MULT ANSWER IS IN BYTES _3 .. _0 D RETURN ; DONE. ;***************************************************************************** ; * * ; * PURPOSE: THIS SUBROUTINE CONVERTS A 32 BIT BINARY NUMBER TO A 10 DIGIT * ; * BCD NUMBER. THE INPUT VALUE TAKEN FROM FREQ(0 TO 3) IS * ; * PRESERVED. THE OUTPUT IS IN BCD, EACH BYTE HOLDS => * ; * (HI_DIGIT,LO_DIGIT), MOST SIGNIFICANT DIGITS ARE IN D5. * ; * THIS ROUTINE IS A MODIFIED VERSION OF ONE DESCRIBED IN * ; * MICROCHIP APPLICATION NOTE AN526. ; * CONVERT TO ARRAY CONVERTS FROM PACKED BCD. * ; * * ; * INPUT: THE VALUE IN FREQ_0,3 * ; * * ; * OUTPUT: THE PACKED BCD NUMBER IN D1,D2,D3,D4 ; * SINGLE-BYTE * ; * RESULT PLACED IN DI1-DI10 (ALSO USED IN D2HEX ROUTINE.) * ; ***************************************************************************** ; H2D MOVLW 0X20 ; SET LOOP COUNTER MOVWF BCD_COUNT ; TO 32 CLRF D1 ; CLEAR OUTPUT CLRF D2 ; " " CLRF D3 ; " " CLRF D4 ; " " CLRF D5 ; " " BIN_LOOP BCF STATUS,C ; CLEAR CARRY BIT IN STATUS ; ; ROTATE BITS IN FREQ BYTES. MOVE FROM LS BYTE (FREQ_0) TO NEXT BYTE (FREQ_1). ; LIKEWISE, MOVE FROM FREQ_1 TO FREQ_2 AND FROM FREQ_2 TO FREQ_3. ; RLF FREQ_0,F ; ROTATE LEFT, 0 -> LS BIT, MS BIT -> CARRY RLF FREQ_1,F ; ROTATE LEFT, CARRY->LS BIT, MS BIT->CARRY RLF FREQ_2,F ; ROTATE LEFT, CARRY->LS BIT, MS BIT->CARRY RLF FREQ_3,F ; ROTATE LEFT, CARRY->LS BIT, MS BIT->CARRY BTFSC STATUS,C ; IS CARRY CLEAR? IF SO, SKIP NEXT INSTRUCTION BSF FREQ_0,0 ; CARRY IS SET SO WRAP AND SET BIT 0 IN FREQ_0 ; ; BUILD BCD BYTES. MOVE INTO LS BIT OF BCD BYTES (LS OF D1) FROM MS BIT OF ; D4 VIA THE CARRY BIT. ; RLF D1,F ; ROTATE LEFT, CARRY->LS BIT, MS BIT->CARRY RLF D2,F ; ROTATE LEFT, CARRY->LS BIT, MS BIT->CARRY RLF D3,F ; ROTATE LEFT, CARRY->LS BIT, MS BIT->CARRY RLF D4,F ; ROTATE LEFT, CARRY->LS BIT, MS BIT->CARRY RLF D5,F ; ROTATE LEFT, CARRY->LS BIT, MS BIT->CARRY DECF BCD_COUNT,F ; DECREMENT LOOP COUNT BTFSS STATUS,Z ; IS LOOP COUNT NOW ZERO? GOTO ADJUST ; NO, GO TO ADJUST CALL CONVERT_TO_ARRAY ; UNPACK. RETURN ; YES, EXIT ; ============================================================================ ADJUST ; INTERNAL SUBROUTINE, CALLED BY BIN2BCD MAIN LOOP ONLY ; ; AS BCD BYTES ARE BEING BUILT, MAKE SURE THE NIBBLES DO NOT GROW LARGER THAN 9. ; IF A NIBBLE GETS LARGER THAN 9, INCREMENT TO NEXT HIGHER NIBBLE. ; (IF THE LS NIBBLE OF A BYTE OVERFLOWS, INCREMENT THE MS NIBBLE OF THAT BYTE.) ; (IF THE MS NIBBLE OF A BYTE OVERFLOWS, INCREMENT THE LS NIBBLE OF NEXT BYTE.) ; MOVLW D1 ; GET POINTER TO BCD_0 MOVWF FSR ; PUT POINTER IN FSR FOR INDIRECT ADDRESSING CALL ADJ_BCD ; INCF FSR,F ; MOVE INDIRECT ADDRESSING POINTER TO BCD_1 CALL ADJ_BCD ; INCF FSR,F ; MOVE INDIRECT ADDRESSING POINTER TO BCD_2 CALL ADJ_BCD ; INCF FSR,F ; MOVE INDIRECT ADDRESSING POINTER TO BCD_3 CALL ADJ_BCD ; INCF FSR,F ; MOVE INDIRECT ADDRESSING POINTER TO BCD_4 CALL ADJ_BCD ; GOTO BIN_LOOP ; BACK TO MAIN LOOP. ; ============================================================================ ADJ_BCD ; INTERNAL SUBROUTINE, CALLED BY ADJUST ONLY MOVLW 3 ; ADD 3 ADDWF INDF,W ; TO LS DIGIT MOVWF BCD_TEMP ; SAVE IN TEMP BTFSC BCD_TEMP,3 ; IS LS DIGIT + 3 > 7 (BIT 3 SET) MOVWF INDF ; YES, SAVE INCREMENTED VALUE AS LS DIGIT MOVLW 0X30 ; ADD 3 ADDWF INDF,W ; TO MS DIGIT MOVWF BCD_TEMP ; SAVE AS TEMP BTFSC BCD_TEMP,7 ; IS MS DIGIT + 3 > 7 (BIT 7 SET) MOVWF INDF ; YES, SAVE INCREMENTED VALUE AS MS DIGIT RETURN ; RETURN TO ADJUST SUBROUTINE ; ; ***************************************************************************** CONVERT_TO_ARRAY; (FROM PACKED BCD). MOVLW B'00001111' ANDWF D1,W MOVWF DI1 MOVLW B'11110000' ANDWF D1,W MOVWF DI2 SWAPF DI2 MOVLW B'00001111' ANDWF D2,W MOVWF DI3 MOVLW B'11110000' ANDWF D2,W MOVWF DI4 SWAPF DI4 MOVLW B'00001111' ANDWF D3,W MOVWF DI5 MOVLW B'11110000' ANDWF D3,W MOVWF DI6 SWAPF DI6 MOVLW B'00001111' ANDWF D4,W MOVWF DI7 MOVLW B'11110000' ANDWF D4,W MOVWF DI8 SWAPF DI8 MOVLW B'00001111' ANDWF D5,W MOVWF DI9 MOVLW B'11110000' ANDWF D5,W MOVWF DI10 SWAPF DI10 RETURN NEGATE COMF ADDA1 COMF ADDA2 COMF ADDA3 COMF ADDA4 MOVLW 1 MOVWF FLAG_STATUS RETURN ; ADD/SUBTRACT INCREMENT, UPDATE FREQUENCY AND RE-DISPLAY. INCDECF CLRF FLAG_STATUS MOVF INC_0,W; INCREMENT AS ONE ADDEND. MOVWF ADDA1 MOVF INC_1,W MOVWF ADDA2 MOVF INC_2,W MOVWF ADDA3 MOVF INC_3,W MOVWF ADDA4 MOVF FREQ_0,W; FREQUENCY AS SECOND ADDEND. MOVWF ADDB1 MOVF FREQ_1,W MOVWF ADDB2 MOVF FREQ_2,W MOVWF ADDB3 MOVF FREQ_3,W MOVWF ADDB4 BTFSC DIR,1 CALL NEGATE; FOR SUBTRACTION. CALL MPADD; ADD FREQ + INCR AND RELOAD TO FREQ. MOVF SUM1,W MOVWF FREQ_0 MOVF SUM2,W MOVWF FREQ_1 MOVF SUM3,W MOVWF FREQ_2 MOVF SUM4,W MOVWF FREQ_3 CALL H2D; GET DECIMAL VERSION OF FREQ. RETURN REDISPLAY MOVLW D'40' CALL SET_POS MOVLW DI8 MOVWF FSR MOVLW D'8' MOVWF BYTE_COUNT NEXT_DIG MOVF INDF,W DECF FSR ADDLW 0X30; ASCIISE. CALL LCD_CHAR DECFSZ BYTE_COUNT GOTO NEXT_DIG RETURN SEND_DDS_WORD CALL WRITE CLRF DATA_PORT MOVLW AD_0 ; POINT FSR AT LEAST SIGNIFICANT BYTE MOVWF FSR ; NEXT_BYTE MOVF INDF,W ; MOVWF BYTE_COUNT ; MOVLW 0X08 ; SET COUNTER TO 8 MOVWF BIT_COUNT ; NEXT_BIT RRF BYTE_COUNT,F ; TEST IF NEXT BIT IS 1 OR 0 BTFSS STATUS,C ; WAS IT ZERO? GOTO SEND0 ; YES, SEND ZERO BSF DATA_PORT,DDS_DAT ; NO, SEND ONE BSF DATA_PORT,DDS_CLK ; TOGGLE WRITE CLOCK BCF DATA_PORT,DDS_CLK ; GOTO BREAK ; SEND0 BCF DATA_PORT,DDS_DAT ; SEND ZERO BSF DATA_PORT,DDS_CLK ; TOGGLE WRITE CLOCK BCF DATA_PORT,DDS_CLK ; BREAK DECFSZ BIT_COUNT,F ; HAS THE WHOLE BYTE BEEN SENT? GOTO NEXT_BIT ; NO, KEEP GOING. INCF FSR,F ; START THE NEXT BYTE UNLESS FINISHED MOVLW AD_4+1 ; NEXT BYTE (PAST THE END) SUBWF FSR,W ; BTFSS STATUS,C ; GOTO NEXT_BYTE BSF ADDR_PORT,DDS_LOAD BCF ADDR_PORT,DDS_LOAD RETURN SEND_INITIAL_SETTING CALL WRITE CALL REDISPLAY CALL CALC_DDS_WORD; MULTIPLY FREQUENCY BY CONSTANT. CALL SEND_DDS_WORD; OUTPUT DATA TO DDS CHIP. RETURN MAIN MOVLW MEM_OVERFLOW; XXX ASSEMBLER CHECK ONLY. CALL BANK0 CALL BIG_DELAY; ALLOW DISPLAY SOME SETTLING TIME. CALL BIG_DELAY CALL BIG_DELAY BCF STATUS,IRP; SET IND. ADDRESSING TO BANK 0/1. MOVLW 0X07;TURN COMPARATORS OFF. MOVWF CMCON CALL BANK1; TO ADDRESS PORTA. MOVLW B'00100000';INITIALISE BIT 0-4 AS OUTPUTS. MOVWF TRISA CALL BANK0 CALL READ; TO ENSURE NO DATA CLASH. BSF ADDR_PORT, ADDR_DIS BCF ADDR_PORT, DDS_LOAD INITIALISE CALL INIT_DISPLAY CALL CLR CALL SET_MODE MOVLW 1; NO POS. CALL, STARTS AT TOP LEFT (DEFAULT). MOVWF TEXT_NUMBER; DISPLAY VERSION. CALL TEXT CALL BIG_DELAY CALL BIG_DELAY CALL BIG_DELAY CALL BIG_DELAY REPROG CALL CLR MOVLW 5 MOVWF TEXT_NUMBER CALL TEXT; DISPLAY "Enter freq(C/S):" MOVLW D'40' CALL SET_POS; NEXT LINE DOWN. CALL CURSOR_ON MOVLW D'8' MOVWF MAX_DIGITS MOVLW BUF1 MOVWF FSR; POINT TO DIGITS IN RAM. CALL PROGRAMME; GET FREQUENCY DATA MOVLW PGM_KEY XORWF KEYVAL,W BTFSC STATUS,Z GOTO REPROG; RE-PROGRAMME, ELSE ASSUME ENTER. CALL PARSE; SORT DIGITS IN RIGHT ORDER AND FORMAT. CALL D2HEX; AND CONVERT TO 4-BYTE HEX. MOVF SUM1,W; COPY BINARY RESULT TO NEXT STAGE. MOVWF FREQ_0 MOVF SUM2,W MOVWF FREQ_1 MOVF SUM3,W MOVWF FREQ_2 MOVF SUM4,W MOVWF FREQ_3 CALL SEND_INITIAL_SETTING; DISPLAY THE INITIAL FREQ.ENTRY. CALL DELAY CALL SEND_INITIAL_SETTING; (DDS CHIP SLOW WHEN FIRST POWERED UP). REPROG_INC CLRF INC_0 CLRF INC_1 CLRF INC_2 CLRF INC_3 MOVLW D'16' CALL SET_POS MOVLW 3 MOVWF TEXT_NUMBER CALL TEXT; ENTER INCREMENT. MOVLW D'56' CALL SET_POS MOVLW 0X20 CALL LCD_CHAR CALL LCD_CHAR CALL LCD_CHAR CALL LCD_CHAR CALL LCD_CHAR CALL LCD_CHAR; CLEAR OLD ENTRY ON DISPLAY. MOVLW D'56' CALL SET_POS MOVLW D'6' MOVWF MAX_DIGITS MOVLW BUF1 MOVWF FSR CALL PROGRAMME MOVLW PGM_KEY XORWF KEYVAL,W BTFSC STATUS,Z GOTO REPROG CALL PARSE; GET DIGITS IN RIGHT ORDER. CALL D2HEX MOVF SUM1,W MOVWF INC_0 MOVF SUM2,W MOVWF INC_1 MOVF SUM3,W MOVWF INC_2 MOVF SUM4,W MOVWF INC_3 CALL CURSOR_HOME MOVLW D'6' MOVWF TEXT_NUMBER CALL TEXT MOVLW D'16' CALL SET_POS MOVLW D'7' MOVWF TEXT_NUMBER CALL TEXT; RE-WRITE AFFIRMATIVE DISPLAY. ; AT THIS STAGE, HAVE INITIAL FREQUENCY AND INC. IN THE RIGHT PLACE. ; NOW POLL ENCODER AND KEYBOARD FOR FURTHER ACTION. MAIN_LOOP CALL NO_CURSOR MAIN_LOOP2 CALL READ CALL TEST_KEY MOVLW PGM_KEY; EXIT IS BACK TO PROGRAMME ALL. XORWF KEYVAL,W BTFSC STATUS,Z GOTO REPROG MOVLW ZERO_KEY; BREAK TO RESET INCREMENT. XORWF KEYVAL,W BTFSC STATUS,Z GOTO REPROG_INC ;POLL ENCODER. THE DIRECTION IS INDICATED BY THE VALUE ;STORED IN LAST_ENCVAL WHEN INDENT (ZERO) IS DETECTED. CALL TEST_ENCODER MOVF ENCVAL,W XORWF LAST_ENCVAL,W BTFSS STATUS,Z GOTO CHANGED GOTO MAIN_LOOP2; LOOP BACK UNTIL NEW VALUE. CHANGED MOVF ENCVAL,W zLW 0; DETECT 0. BTFSC STATUS,Z; SKIP IF ZERO NOT FOUND. GOTO ZERO MOVF ENCVAL,W MOVWF LAST_ENCVAL GOTO MAIN_LOOP2 ZERO MOVF LAST_ENCVAL,W XORLW 1 BTFSC STATUS,Z GOTO ONE MOVF LAST_ENCVAL,W XORLW 2 BTFSC STATUS,Z GOTO TWO MOVF ENCVAL,W MOVWF LAST_ENCVAL GOTO MAIN_LOOP2 ONE MOVLW 1 MOVWF DIR GOTO ENC_EXIT TWO MOVLW 2 MOVWF DIR ENC_EXIT MOVF ENCVAL,W MOVWF LAST_ENCVAL CALL INCDECF CALL WRITE CALL REDISPLAY CALL CALC_DDS_WORD; MULTIPLY FREQUENCY BY CONSTANT. CALL SEND_DDS_WORD; OUTPUT DATA TO DDS CHIP. GOTO MAIN_LOOP2 END