;************************************************************************************************************************************ ;FILE NAME: ;STATUS: ;DATE CREATED: ;Date of Last Modification: ; ;PURPOSE: ;PROCESSOR: PIC 12F683 ;CLOCK SOURCE: ;************************************************************************************************************************************ ;************************************************************************************************************************************ ;PROCESSOR DECLARATIONS, INCLUDE FILES, CONFIG WORD SETUP ;************************************************************************************************************************************ list p=12f683 ; list directive to define processor #include ; processor specific variable definitions errorlevel -302 ; suppress message 302 from list file __CONFIG _FCMEN_OFF & _IESO_OFF & _BOD_OFF & _CPD_OFF & _CP_OFF & _MCLRE_OFF & _PWRTE_ON & _WDT_OFF & _HS_OSC ;************************************************************************************************************************************ ;END OF PROCESSOR DECLARATIONS ;************************************************************************************************************************************ ;************************************************************************************************************************************ ;RAM VARIABLES SETUP ;************************************************************************************************************************************ cblock H'020' ;*****Counter variables VAR_COUNT1 VAR_COUNT2 VAR_AVG_CTR ;variable used to count through the number of A/D readings averaged VAR_FLAGS ;Variable containing various flags used in the program ;*****Variables for lookup tables VAR_TEXT_INDEX ;Used to pass the offset to the various lookup tables. This variable is not altered by the lookup routine VAR_TABLE_OFFSET ;Used within the lookup routines to hold the offset ;*****Variables for math operations VAR_1_16BIT_H VAR_1_16BIT_L VAR_2_16BIT_H VAR_2_16BIT_L VAR_TEMP1_H VAR_TEMP1_L VAR_TEMP2_H VAR_TEMP2_L VAR_TEMP3_H VAR_TEMP3_L VAR_MULT_CTR ;Counter varible used in the multiply routine ;*****Variables used in the Goertzel algorithm VAR_Y0_A_H ;These are the values computed during the Goertzel algorithm VAR_Y0_A_L VAR_Y1_A_H VAR_Y1_A_L VAR_Y2_A_H VAR_Y2_A_L VAR_X0_H VAR_X0_L VAR_COS_COEFF ;Stores the cosine coefficient used in the algorithm VAR_SIN_COEFF ;Stores the cosine coefficient used in the algorithm VAR_SAMPLE_CTR ;Used for stepping through the samples in each scan VAR_WINDOW_CTR ;Counter variable used to lookup the correct Hamming window value VAR_REAL_H ;variables used to store the real and imaginary parts of the final result of the VAR_REAL_L ;algorithm. These are then used to determine the magnitude VAR_IMAG_H VAR_IMAG_L VAR_MAGNITUDE_H ;Variables to store the magnitude of the algorithm output VAR_MAGNITUDE_L VAR_FREQ_SETTING_H ;variables to store the freqency select input reading VAR_FREQ_SETTING_L VAR_DETECTION_THRESHOLD_H ;Stores the detection threshold value currently in use. The actual value stored VAR_DETECTION_THRESHOLD_L ;will be equal to either the upper or lower threshold, depending on the previous ;state of the detector output. This is used for the hysteresis VAR_UPPER_THRESHOLD_H ;Stores the upper detection threshold corresponding to the detection threshold input VAR_UPPER_THRESHOLD_L VAR_LOWER_THRESHOLD_H ;Stores the lower detection threshold corresponding to the detection threshold input VAR_LOWER_THRESHOLD_L ;*****Variables for serial transmission VAR_SERIAL_DATA ;Variable used to pass the byte to be transmitted to the serial output routine VAR_SER_DELAY_CTR ;Variable used in the delay used to set the serial output bit timing VAR_SER_BIT_CTR ;Variable used to count through the bits in the byte to be transmitted ;Other variables VAR_FSR_TEMP ;Temporary location for storing the state of the FSR DECIMAL_DIGITS :5 ;First location of a block of 5 bytes used for the 5 decimal digits that result form ;the binary to decimal conversion routine VAL_DECIMAL_CONVERSION_CTR ;Counter variable used for cycling through the decimal digits endc ;************************************************************************************************************************************ ;END OF RAM VARIBLES SETUP ;************************************************************************************************************************************ ;************************************************************************************************************************************ ;EQUATES ;************************************************************************************************************************************ CHAR_CARRIAGE_RETURN EQU H'0A' ;value of carriage return in ASCII CHAR_NEW_LINE EQU H'0D' ;value of new line in ASCII BAUD_RATE_VAL EQU D'48' ;value used in delay to set proper serial bit timing for 9600 baud SAMPLE_DELAY_H EQU H'FE' ;Sample delay values for Timer 1, corresponding to 4400Hz sampl3 rate. SAMPLE_DELAY_L EQU H'46' NUMBER_OF_SAMPLES EQU D'200' ;This is the number of samples taken and processed during the Goertzel algorithm ;**********GPIO Assignments ;GP0=AN0 Analog Input for audio signal ;GP1=AN1 Detection threshold setting analog input ;GP2=Main Output ;GP3=Frequency select enable ;GP4=XTAL ;GP5=XTAL OUTPUT_PIN EQU D'2' ;Output pin that is set high if the programmed sequence is detected FREQ_SELECT_ENABLE EQU D'3' SERIAL_OUT EQU D'5' ;Output for red LED UPPER_THRESHOLD_FACTOR EQU D'72' ;These values correspond to a hysterestis window width of 1/4 of the center value LOWER_THRESHOLD_FACTOR EQU D'56' ;(1/8 of the window above and below the center" DETECTION_THRESHOLD_SCALE_FACTOR EQU D'52' ;This value is used in the process of mapping the 10 bit A/D full scale range to ;The desired full scale range of values producted by the algorithm output DETECT_THRESHOLD_OFFSET_H EQU D'0' ;These values are used to establish the absolute minimum value of the threshold DETECT_THRESHOLD_OFFSET_L EQU D'27' ;It cannot be zero, otherwise the detection will be triggered by noise ;VAR_FLAGS register bits SIGN_VAL_1 EQU D'0' SIGN_VAL_2 EQU D'1' POWER_UP EQU D'2' ;************************************************************************************************************************************ ;END OF EQUATES ;************************************************************************************************************************************ ORG H'000' GOTO PROGRAM_START ORG H'005' PROGRAM_START ;************************************************************************************************************************************ ;CONFIGURATION OF THE PROCESSOR ;************************************************************************************************************************************ BCF STATUS,RP1 BCF STATUS,RP0 ;Change to Bank0 ;Clear the gpio port CLRF GPIO BSF STATUS,RP0 ;Change to Bank1 ;Configure I/O ports as inputs or outputs MOVLW B'00111011' ;Configure GPIO I/O MOVWF TRISIO ;Set A/D conversion clock to Fosc/16, and configure GPIO #0 as an analog input. ;Note: The conversion process takes 11 Tad, and Tad will be 2usec for an 8MHz oscillator and these settings, so the conversion ;time will be 22usec or 44 instruction cycles. MOVLW b'01010011' MOVWF ANSEL BCF STATUS,RP0 ;Change to Bank0 CLRF GPIO ;Configure the A/D converter for right justified results, reference voltage of Vdd (5 volts), ;select ananlog channel 0, and turn the converter ON. MOVLW B'10000001' MOVWF ADCON0 ;Turn off the comparator module BCF STATUS,RP0 MOVLW H'07' MOVWF CMCON0 CLRF VAR_FLAGS ;Clear the VAR_FLAGS variable to begin with ;************************************************************************************************************************************ ;END CONFIGURATION OF THE PROCESSOR ;************************************************************************************************************************************ BSF GPIO,SERIAL_OUT ;Set the serial output pin high (this is the idle state) CALL SUB_DELAY_125MS ;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ;Main Program ;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ CALL SUB_DELAY_500_MICROSEC MOVLW H'78' ;Initialize the detection threshold to begin with MOVWF VAR_DETECTION_THRESHOLD_H MOVLW H'00' MOVWF VAR_DETECTION_THRESHOLD_L BSF VAR_FLAGS,POWER_UP ;This flag is set here, and cleared later. It is used to ensure that the frequency ;select input is always read after power up. After that it is only read if the ;FREQ_SELECT_ENABLE input is LOW CHECK_FREQ_SELECT_ENABLE ;!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ;The following code will be commented out to deactivate it. This portion of the code typically runs each detection loop, to ;read the frequency select input to determine the frequency to test for. Since this version of code uses a fixed 1750 Hz ;frequency, this code is not needed. ;!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ;Is Power up flag set? ; BTFSC VAR_FLAGS,POWER_UP ; GOTO READ_FREQ_SETTING ;Is the frequency select enable input low? ; BTFSC GPIO,FREQ_SELECT_ENABLE ; GOTO SCAN_FOR_FREQ READ_FREQ_SETTING ; BCF VAR_FLAGS,POWER_UP ;Select analog input 1 for reading the target frequency setting ; BCF ADCON0,CHS1 ; BSF ADCON0,CHS0 ; CALL SUB_AVG_ANALOG_READING ; MOVFW VAR_1_16BIT_H ; MOVWF VAR_FREQ_SETTING_H ; MOVFW VAR_1_16BIT_L ; MOVWF VAR_FREQ_SETTING_L ;Rotate the value to the right once to positon the bits for use as an index value for looking up the sin and cos coefficients. ; BCF STATUS,C ; RRF VAR_1_16BIT_H,f ; RRF VAR_1_16BIT_L,f ;Bit 0 of VAR_1_16BIT_H now determines which bank (0 or 1) the values are looked up from ;The bits of VAR_1_16BIT_L are the value used to look up from the tables. ; MOVFW VAR_1_16BIT_L ; MOVWF VAR_TEXT_INDEX ; BTFSC VAR_1_16BIT_H,0 ; GOTO LOOK_UP_USING_1_TABLES ; CALL SUB_SIN_COEFF_0_LOOKUP ;!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ;The coefficents corresponding to 1748 Hz are directly used here. 1748 Hz is the closest value to 1750 Hz that was in the ;lookup table that is used in the standard version of the code MOVLW D'38' ;Sine coefficient for 1760 Hz MOVWF VAR_SIN_COEFF ; CALL SUB_COS_COEFF_0_LOOKUP MOVLW D'180' ;Cosine coefficient for 1760 Hz MOVWF VAR_COS_COEFF ;!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ; GOTO LOOKUP_COMPLETE LOOK_UP_USING_1_TABLES ; CALL SUB_SIN_COEFF_1_LOOKUP ; MOVWF VAR_SIN_COEFF ; CALL SUB_COS_COEFF_1_LOOKUP ; MOVWF VAR_COS_COEFF LOOKUP_COMPLETE SCAN_FOR_FREQ ;***************Determine the Upper and Lower Detection Thresholds ;Select analog input AN1 for reading the detection threshold input BCF ADCON0,CHS1 BSF ADCON0,CHS0 CALL SUB_AVG_ANALOG_READING ;Add the offset, used to establish the minimum allowable value of the detection threshold MOVLW DETECT_THRESHOLD_OFFSET_H MOVWF VAR_2_16BIT_H MOVLW DETECT_THRESHOLD_OFFSET_L MOVWF VAR_2_16BIT_L CALL SUB_MATH_16BIT_ADD ;Multiply by 32 (left shift 5 times) BCF STATUS,C RLF VAR_1_16BIT_L,f RLF VAR_1_16BIT_H,f BCF STATUS,C RLF VAR_1_16BIT_L,f RLF VAR_1_16BIT_H,f BCF STATUS,C RLF VAR_1_16BIT_L,f RLF VAR_1_16BIT_H,f BCF STATUS,C RLF VAR_1_16BIT_L,f RLF VAR_1_16BIT_H,f BCF STATUS,C RLF VAR_1_16BIT_L,f RLF VAR_1_16BIT_H,f ;Multiply the value by a scale factor MOVLW DETECTION_THRESHOLD_SCALE_FACTOR MOVWF VAR_2_16BIT_L CALL SUB_MATH_MULTIPLY ;The value is now equal to the center value of the detection threshold. Store the value MOVFW VAR_1_16BIT_H MOVWF VAR_TEMP2_H MOVFW VAR_1_16BIT_L MOVWF VAR_TEMP2_L ;Determine the upper threshold MOVLW UPPER_THRESHOLD_FACTOR MOVWF VAR_2_16BIT_L CALL SUB_MATH_MULTIPLY ;Store the upper threshold MOVFW VAR_1_16BIT_H MOVWF VAR_UPPER_THRESHOLD_H MOVFW VAR_1_16BIT_L MOVWF VAR_UPPER_THRESHOLD_L ;Determine the lower threshold MOVFW VAR_TEMP2_H MOVWF VAR_1_16BIT_H MOVFW VAR_TEMP2_L MOVWF VAR_1_16BIT_L MOVLW LOWER_THRESHOLD_FACTOR MOVWF VAR_2_16BIT_L CALL SUB_MATH_MULTIPLY ;Store the lower threshold MOVFW VAR_1_16BIT_H MOVWF VAR_LOWER_THRESHOLD_H MOVFW VAR_1_16BIT_L MOVWF VAR_LOWER_THRESHOLD_L ;**********Transmit the settings over serial ;***Transmit the Target frequency ;The value in VAR_FREQ_SETTING is currently just the value read from the frequency select input ;Since this software is configured to detect frequencies from 100Hz to 2148Hz, the value needs ;to be processes first so that it represents the target frequency, in Hz ;Target frequency, in Hz = 2*frequency select reading + 100 ;First, mulitply the value by 2 MOVFW VAR_FREQ_SETTING_H MOVWF VAR_1_16BIT_H MOVFW VAR_FREQ_SETTING_L MOVWF VAR_1_16BIT_L BCF STATUS,C RLF VAR_1_16BIT_L,f RLF VAR_1_16BIT_H,f ;Next, add 100 to the value. CLRF VAR_2_16BIT_H MOVLW D'100' MOVWF VAR_2_16BIT_L CALL SUB_MATH_16BIT_ADD CALL SUB_CONVERT_AND_TRANSMIT ;***Transmit the Upper detection threshold MOVFW VAR_UPPER_THRESHOLD_H MOVWF VAR_1_16BIT_H MOVFW VAR_UPPER_THRESHOLD_L MOVWF VAR_1_16BIT_L CALL SUB_CONVERT_AND_TRANSMIT ;***Transmit the Lower detection threshold MOVFW VAR_LOWER_THRESHOLD_H MOVWF VAR_1_16BIT_H MOVFW VAR_LOWER_THRESHOLD_L MOVWF VAR_1_16BIT_L CALL SUB_CONVERT_AND_TRANSMIT ;***Transmit the Current detection threshold MOVFW VAR_DETECTION_THRESHOLD_H MOVWF VAR_1_16BIT_H MOVFW VAR_DETECTION_THRESHOLD_L MOVWF VAR_1_16BIT_L CALL SUB_CONVERT_AND_TRANSMIT ;**********Run the Goertzel Routine to determine if the target frequency is present CALL SUB_GOERTZEL_SAMPLE ;Load VAR_MAGNITUDE into VAR_1 for comparison to threshold MOVFW VAR_MAGNITUDE_H MOVWF VAR_1_16BIT_H MOVFW VAR_MAGNITUDE_L MOVWF VAR_1_16BIT_L ;Compare magnitude to threshold to decide whether frequency is present MOVFW VAR_DETECTION_THRESHOLD_H MOVWF VAR_2_16BIT_H MOVLW VAR_DETECTION_THRESHOLD_L MOVWF VAR_2_16BIT_L CALL SUB_MATH_16BIT_SUBTRACT MOVLW 'X' MOVWF VAR_SERIAL_DATA CALL SUB_SERIAL_TX BTFSS VAR_1_16BIT_H,7 GOTO FREQ_DETECTED BCF GPIO,OUTPUT_PIN ;Set the output LOW if the frequency is not detected ;If the result is less than the current threshold, set the lower threshold as the current threshold for the next time the algorithm is run ;This is for the hysteresis MOVFW VAR_UPPER_THRESHOLD_H MOVWF VAR_DETECTION_THRESHOLD_H MOVFW VAR_UPPER_THRESHOLD_L MOVWF VAR_DETECTION_THRESHOLD_L ;Transmit a "0" indicating that the frequency has not been detected MOVLW '0' MOVWF VAR_SERIAL_DATA CALL SUB_SERIAL_TX ;Transmit the magnitude of the filter output via serial GOTO TRANSMIT_MAGNITUDE_OVER_SERIAL FREQ_DETECTED BSF GPIO,OUTPUT_PIN ;If the result is greater than the current threshold, set the lower threshold as the current threshold for the next time the algorithm is run ;This is for the hysteresis MOVFW VAR_LOWER_THRESHOLD_H MOVWF VAR_DETECTION_THRESHOLD_H MOVFW VAR_LOWER_THRESHOLD_L MOVWF VAR_DETECTION_THRESHOLD_L ;Transmit a "1" indicating that the frequency has been detected MOVLW '1' MOVWF VAR_SERIAL_DATA CALL SUB_SERIAL_TX TRANSMIT_MAGNITUDE_OVER_SERIAL MOVLW ',' MOVWF VAR_SERIAL_DATA CALL SUB_SERIAL_TX ;Convert the magnitde to decimal and transmit over serial ;Load VAR_MAGNITUDE into VAR_1 for conversion to decimal MOVFW VAR_MAGNITUDE_H MOVWF VAR_1_16BIT_H MOVFW VAR_MAGNITUDE_L MOVWF VAR_1_16BIT_L CALL SUB_CONVERT_AND_TRANSMIT ;Transmit a carriage return and new line MOVLW CHAR_CARRIAGE_RETURN MOVWF VAR_SERIAL_DATA CALL SUB_SERIAL_TX MOVLW CHAR_NEW_LINE MOVWF VAR_SERIAL_DATA CALL SUB_SERIAL_TX GOTO CHECK_FREQ_SELECT_ENABLE ;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ;END of Main Program ;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ;XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX ;BEGINNING OF SUBROUTINE CODE ;XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX ;************************************************************************************************************************************ ; Subroutine SUB_DELAY_500_MICROSEC ;************************************************************************************************************************************ SUB_DELAY_500_MICROSEC movlw D'125' movwf VAR_COUNT1 LOOP1 nop nop nop nop nop decfsz VAR_COUNT1,f goto LOOP1 return ;Return from SUB_DELAY_500_MICROSEC ;************************************************************************************************************************************ ; END of Subroutine SUB_DELAY_500_MICROSEC ;************************************************************************************************************************************ ;************************************************************************************************************************************ ;Subroutine SUB_DELAY_125MS ;************************************************************************************************************************************ SUB_DELAY_125MS movlw D'250' movwf VAR_COUNT2 LOOP2 call SUB_DELAY_500_MICROSEC decfsz VAR_COUNT2,f goto LOOP2 return ;Return from SUB_DELAY_125MS ;************************************************************************************************************************************ ; END of Subroutine SUB_DELAY_125MS ;************************************************************************************************************************************* ;************************************************************************************************************************************ ;Subroutine SUB_MATH_16BIT_ADD ;This subroutine adds two 16 bit numbers. Each number is stored in two 8 bit variables. The result is returned via the ;VAR_1_16BIT variables. ;Total execution time, including call and return = 10 cycles ;************************************************************************************************************************************ SUB_MATH_16BIT_ADD MOVFW VAR_2_16BIT_L ADDWF VAR_1_16BIT_L,F BTFSC STATUS,C INCF VAR_1_16BIT_H,F MOVFW VAR_2_16BIT_H ADDWF VAR_1_16BIT_H,F RETURN ;Return from Subroutine SUB_MATH_16BIT_ADD ;************************************************************************************************************************************ ; END of Subroutine SUB_MATH_16BIT_ADD ;************************************************************************************************************************************ ;************************************************************************************************************************************ ;Subroutine SUB_MATH_16BIT_SUBTRACT ;This subroutine adds two 16 bit numbers. Each number is stored in two 8 bit variables. The result is returned via the ;VAR_1_16BIT variables. The routine subtracts value 2 from value 1. ;\Total execution time, including call and return = 10 instruction cycles ;************************************************************************************************************************************ SUB_MATH_16BIT_SUBTRACT ;Subtract the low bytes MOVFW VAR_2_16BIT_L SUBWF VAR_1_16BIT_L,f BTFSS STATUS,C DECF VAR_1_16BIT_H,f ;Subtract the high bytes MOVFW VAR_2_16BIT_H SUBWF VAR_1_16BIT_H,f RETURN ;Return from Subroutine SUB_MATH_16BIT_SUBTRACT ;************************************************************************************************************************************ ; END of Subroutine SUB_MATH_16BIT_SUBTRACT ;************************************************************************************************************************************ ;********************************************************************************************************************************** ;Subroutine SUB_ABS_VAL ;This subroutine takes the absolute value of the 2's complement number in VAR_1. The result is returned via VAR_1. ;Execution time, including the call and return = 12 instruction cycles, ;********************************************************************************************************************************** SUB_ABS_VAL BTFSS VAR_1_16BIT_H,7 ;Check to see if the most significant bit is a 1, indicating negative value GOTO END_ABS_VAL ;If MSB =0, value is positive, and no further processing is required COMF VAR_1_16BIT_H,F ;If value is negative, convert to postive by taking 2's complement, which COMF VAR_1_16BIT_L,F ;requires inverting all the bits and adding 1 MOVLW D'1' ADDWF VAR_1_16BIT_L,F BTFSC STATUS,C INCF VAR_1_16BIT_H,f END_ABS_VAL RETURN ;Return from SUB_ABS_VAL ;********************************************************************************************************************************** ; END of Subroutine SUB_ABS_VAL ;********************************************************************************************************************************** ;********************************************************************************************************************************** ;Subroutine SUB_MATH_MULTIPLY ;This routine multiplies a 16 bit number (in VAR1) by an 8 bit number (in VAR_2_16BIT_L) ;The 8 bit number is of the form 0X.XXXXXX That is, it can reprsent a decimal number between 0 and 1.984 ;Maximum execution time, including call and return = 2 + 8 + 6*(17) + 16 + 2 = 130 instruction cycles ;That is the maximum execution time. The execution time will vary depending on the numbers to be multiplied ;********************************************************************************************************************************** SUB_MATH_MULTIPLY ;Move the VAR1 variable into temp1 MOVFW VAR_1_16BIT_H MOVWF VAR_TEMP1_H MOVFW VAR_1_16BIT_L MOVWF VAR_TEMP1_L ;Clear out the VAR1 CLRF VAR_1_16BIT_H CLRF VAR_1_16BIT_L MOVLW D'7' MOVWF VAR_MULT_CTR SHIFT_AND_ADD BTFSS VAR_2_16BIT_L,6 GOTO ROTATE_VALS ;There is no value to add if the bit is zero ;Add the shifted value to VAR_1 BCF STATUS,C ;Clear the carry bit MOVFW VAR_TEMP1_L ADDWF VAR_1_16BIT_L,f BTFSS STATUS,C GOTO ADD_HIGH_BYTES_MULTIPLY INCF VAR_1_16BIT_H,f ADD_HIGH_BYTES_MULTIPLY MOVFW VAR_TEMP1_H ADDWF VAR_1_16BIT_H,f ;Rotate values ROTATE_VALS ;Rotate the 16bit value (divide by 2) BCF STATUS,C RRF VAR_TEMP1_H,f RRF VAR_TEMP1_L,f ;Rotate the multiplier left to position the next bit into bit 6 RLF VAR_2_16BIT_L,f DECFSZ VAR_MULT_CTR,f GOTO SHIFT_AND_ADD RETURN ;********************************************************************************************************************************** ; END of Subroutine SUB_MATH_MULTIPLY ;********************************************************************************************************************************** ;************************************************************************************************************************************ ;Subroutine SUB_MATH_MULTIPLY_SIGNED ;This subroutine ;Total execution time, including call and return = 164 instruction cycles ;That is the maximum execution time. The execution time will vary depending on the numbers to be multiplied ;************************************************************************************************************************************ SUB_MATH_MULTIPLY_SIGNED ;Determine the signs of the two values and set the flags accordingly BCF VAR_FLAGS,SIGN_VAL_1 ;Clear these two flags to begin BCF VAR_FLAGS,SIGN_VAL_2 BTFSC VAR_1_16BIT_H,7 BSF VAR_FLAGS,SIGN_VAL_1 ;Set if number is negative BTFSC VAR_2_16BIT_L,7 BSF VAR_FLAGS,SIGN_VAL_2 ;Set if number is negative BTFSS VAR_1_16BIT_H,7 GOTO MULTIPLY_NUMBERS ;Multiply Y1 by -1 (two's complement) if it is a negative value COMF VAR_1_16BIT_H,F ;If value is negative, convert to postive by taking 2's complement, which COMF VAR_1_16BIT_L,F ;requires inverting all the bits and adding 1 MOVLW D'1' ADDWF VAR_1_16BIT_L,f BTFSC STATUS,C INCF VAR_1_16BIT_H,f ;Multiply the two numbers MULTIPLY_NUMBERS CALL SUB_MATH_MULTIPLY ;This routine takes 130 instruction cycles max ;Determine if the result should be positive or negative. If one or the other but not both of the ;two numbers multiplied are negative, then the result is negative and the value must be multiplied ;by -1. (two's complement) MOVFW VAR_FLAGS ANDLW b'00000011' XORLW b'00000011' BTFSC STATUS,Z GOTO END_OF_SIGNED_MULTIPLY MOVFW VAR_FLAGS ANDLW b'00000011' XORLW b'00000000' BTFSC STATUS,Z GOTO END_OF_SIGNED_MULTIPLY ;Multiply by negative 1 otherwise COMF VAR_1_16BIT_H,F ;If value is negative, convert to postive by taking 2's complement, which COMF VAR_1_16BIT_L,F ;requires inverting all the bits and adding 1 MOVLW D'1' ADDWF VAR_1_16BIT_L,f BTFSC STATUS,C INCF VAR_1_16BIT_H,f END_OF_SIGNED_MULTIPLY RETURN ;Return from Subroutine SUB_MATH_MULTIPLY_SIGNED ;************************************************************************************************************************************ ; END of Subroutine SUB_MATH_MULTIPLY_SIGNED ;************************************************************************************************************************************ ;********************************************************************************************************************************** ;Subroutine SUB_MATH_16BIT_MAGNITUDE ;This subroutine is used to provide an approximation of the magnitude of a vector. This is the max + 1/4*min version. ;It is used to avoid the more complicated math of the pythagorean therorm to determine the magnitude of a vector. ;It is used in this application to estimate the magnitude of the algorithm output from the real and imaginary parts. ;********************************************************************************************************************************** SUB_MATH_16BIT_MAGNITUDE CALL SUB_ABS_VAL ;take absolute value of VAR_1 MOVFW VAR_1_16BIT_H ;store the absolute value of the first value in TEMP2 MOVWF VAR_TEMP2_H MOVFW VAR_1_16BIT_L MOVWF VAR_TEMP2_L MOVFW VAR_2_16BIT_H ;Move the second value from VAR2 into VAR_1 MOVWF VAR_1_16BIT_H MOVFW VAR_2_16BIT_H MOVWF VAR_1_16BIT_L CALL SUB_ABS_VAL ;take absolute value of VAR_1 MOVFW VAR_1_16BIT_H ;store the absolute value of the second value in TEMP3 MOVWF VAR_TEMP3_H MOVFW VAR_1_16BIT_L MOVWF VAR_TEMP3_L ;Subtract the two values to determine which is the min and which is the max MOVFW VAR_TEMP2_H MOVWF VAR_1_16BIT_H MOVFW VAR_TEMP2_L MOVWF VAR_1_16BIT_L MOVFW VAR_TEMP3_H MOVWF VAR_2_16BIT_H MOVFW VAR_TEMP3_L MOVWF VAR_2_16BIT_L CALL SUB_MATH_16BIT_SUBTRACT BTFSC VAR_1_16BIT_H,7 ;Check bit 7 of VAR_1, and branch depending on which value was largest GOTO VAR2_MAX ;This is needed for the magnitude approximation ;**********VAR1>=VAR2 VAR1_MAX ;The value in TEMP3 is the minimum of the two values MOVFW VAR_TEMP3_H MOVWF VAR_1_16BIT_H MOVFW VAR_TEMP3_L MOVWF VAR_1_16BIT_L ;Divide the minimum value by 4 BCF STATUS,C RRF VAR_1_16BIT_H,F RRF VAR_1_16BIT_L,F BCF STATUS,C RRF VAR_1_16BIT_H,F RRF VAR_1_16BIT_L,F ;Add the max value to 1/4 of the min value (this is the magnitude approximation) MOVFW VAR_TEMP2_H MOVWF VAR_2_16BIT_H MOVFW VAR_TEMP2_L MOVWF VAR_2_16BIT_L CALL SUB_MATH_16BIT_ADD GOTO END_MAGNITUDE ;**********VAR1