; ------------------------------------------------------------------------ ; FILE : LCD4DIEP.ASM - variation with 4 bite LCD communication * ; (4-bites, high nibble, RB4..RB7 data, RA0..RA2 control) * ; CONTENTS : Simple low-cost 7-digit digital scale using a PIC16F84 * ; COPYRIGHT: Peter Halicky OM3CPH, OH6CJ * ; AUTHOR : Peter Halicky OM3CPH & Peter Halicky Jr., OM2PH ex OM2APH * ; PCB : Tibor Madarasz OM2ATM, modified Osmo OH6CJ August 2001 * ;-------------------------------------------------------------------------- ; Osmo OH6CJ: 08.03.2001 Modifications for 4000 kHz crystal: ; Added: RF offset1 when RB1 = 0 and RF offset2 when RB1 = 1. ; EEPROM routine to select either 1x16 or 2x20 LCD control. ; EEPROM routine to select either 6 or 7 digits to be displayed. ; When RB2=1, direct frequency is displayed (no add or sub RF). ; RB3 to control decimal point location with additional 10 divider. ; Added calibration parameters for time window (EEPROM 07h,08h). ; Osmo OH6CJ: 17.03.2001 ; Modified EEPROM TEXTS "ADDR" and "MODE" instead of A: ; Added sw version number 1.0 for EEPROM TEXT display ; Osmo OH6CJ: 31.03.2001 ; Added Busy checkings after the clear display and cursor ; positioning instructions because problems observed with certain ; 1x16 LCDs types (slow display updating, flashing or freezing). ; Changed E Data R/W start pulse bit set and clear procedure. ; First digit on left (10 MHz) is not displayed if zero. ; Osmo OH6CJ: 27.04.2001 ; Added default values writing to EEPROM during first power-on. ; Added EEPROM address 06h to select direct freq as a default. ; Changed sw version to 1.2 in EEPROM MODE window. ; Osmo OH6CJ: 20.09.2001 ; Added frequency lock function to control external HW-integrator ; to keep VFO frequency stable. There is a subtruction between ; the measured frequency and freq reference. Frequency actual is ; set to reference after the out of lock situation when the new freq ; has been stabilised (nobody touch for VFO knob). As a result ; RB0 is controlled as digital output to indicate the need of ; frequency correction upward and RB3 downward. ; Function is enabled by EEPROM 0Bh. ; Changed sw version to 1.3 in EEPROM MODE window. "EE-INIT" text ; removed to save memory. ; Modified Sub24bit and Add24bit routines as subcalls to save memory ; New parameters are 0B..0Eh. ; Unnecessary Clear STATUS,C command rows deleted. ; Osmo OH6CJ: 17.10.2001 ; Changed 0Dh and 0Eh default values and freq. check windows. ; Osmo OH6CJ: 09.11.2001 ; Returned back swap function with sub display offset function, if ; subtracted value is bigger than subtracter. ; Osmo OH6CJ: 03.12.2001 ; Added Freq Lock pass mode by RB2.Frequency samples must be within the ; 20 Hz window before they are accepted to freq reference. ;-------------------------------------------------------------------------- ; The EEPROM MODE is activated when RB0 = 1 and power is ; connected. ;-------------------------------------------------------------------------- ; The used EEPROM addresses are: ; 00 = MFt1_HigB = High Byte of RF offset1 (def. 0D) 9001.50 kHz = 0DBC36 ; 01 = MFt1_MidB = Mid Byte of RF offset1 (def. BC) ; 02 = MFt1_LowB = Low Byte of RF offset1 (def. 36) ; 03 = MFt2_HigB = High Byte of RF offset2 (def. 0D) 8998.50 khz = 0DBB0A ; 04 = MFt2_MidB = Mid Byte of RF offset2 (def. BB) ; 05 = MFt2_LowB = Low Byte of RF offset2 (def. 0A) ; 06 = Dir_freq = Direct frequency without sub or add functions = 0 def. ; 07 = EE_Fine1 = Counter value for calibration 1 == 3*4/fx= 3us (def. 15) ; 08 = EE_Fine2 = Counter value for calibration 1 == 4*4/fx= 4us (def. 01) ; 09 = 1x16_Disp = LCD display type: 0 = 1x16 LCD, 1 = 2x20 LCD (def. 01) ; 0A = Digits = Number of displayed digits: 0 = 7 digits, 1 = 6 (def. 1) ; 0B = Freq_lock = RB0 is output indicating need to increase and RB3 to ; decrease frequency compared to frequency reference. ; If freq is out of the window +/- 110 Hz 20 samples, both ; outputs are cleared. When the frequency is within ; +/- 20 Hz from reference, only short pulse is ; controlled. If over then long pulse is controlled. ; 00h = Function enabled with LCD indication "L" = locked ; 01h...FFh = Function disabled ; 0C = Ten_div = Ten_divider function is activated in Freq_lock mode ; because of RB3 is not available now. ; 00h = Enabled, 01..FFh = Disabled (def. FF) ; 0D = Delay = Delay time before frequency lock procedure starts after ; out of lock situation. 1 == 10 Hz (def. 028h == 4 s.) ; 0E = Sampling = Sampling time with reference and lock checking. ; 1h == 1 sample (def. = 0Ah) ; 0F = Defaults = Default values are restored to EEPROM if set to >00h. ;-------------------------------------------------------------------------- ; E-Mail: peter@halicky=.sk ; ; Bratislava, Slovakia, December 1998, revised & debugged February, 2000 ; ; Further modified 2001 by oh6cj@sral.fi ;-------------------------------------------------------------------------- ; This is 7-digit frequency meter counting up to 35 MHz. The decimal point ; is after MHz digit, but can be at any position. ; ; It adds or substracts RF according signal level at RA2: ; +5V - adds RF (offset2) ; disconnected - substracts RF (offset1) ; ; Hardware is very simple: ; ; It contains : PIC 16F84 ; 1 NPN low power HF Si transistor, ; 16 character (2x8) in 1 Line LCD display, ; Xtal 1..10 MHz, ; some resistors, capacitors and 2 Si switching diodes... ; (see schematic) ; Note: ; LCD display is 16 character in 1 line LCD display PVC160101PTN which ; seems to be compatible with TWO LINES HITACHI LCD display, except ; that that one has only 8 characters in 1 line. ; See EEPROM parameter 09h to select either 1x16 or 2x20 ; ; The counter uses internal prescaler of PIC as low byte of counter, ; TMR0 as middle byte and some register as high byte of counter. ; ; Some ideas were taken from "Simple low-cost digital frequency meter ; using a PIC 16C54" (frqmeter.asm) ; written by James Hutchby, MadLab Ltd. 1996 ; ; LCD interfacing was completly taken from Norm Cramer's LCD.ASM ; ------------------------------------------------------------------------ ; ; This software is free for private usage. It was created for HAM radio ; community members. Commercial exploatation is allowed only with permission ; of authors. ; ; ------------------------------------------------------------------------ ; ; The measuring period is 100 000 us. ; Procesor cycle is T = 4/Fx [us,MHz], Fx is Xtal frequency ; ; Number of processor cycles per measuring period: ; ; N = 100 000/T processor cycles ; N = Fx * 100 000/4 = 25 000 x Fx ; ; The main steps of measuring period: ; ; 1. decode 3-byte value into 7 decimal numbers, ; 2. decode decimal value of digit to chars, ; 3. set decimal point if needed, ; 4. output to PORTB (LCD) either 6 or 7 digits, ; 5. start measurement, ; 6. test TMR0 overflow bite, if YES increase TimerH, ; 7. goto 5 until measuring period is done, ; 8. stop measurement, ; 9. shift out precounter content, ; 10. Add/substract RF according signal from optocoupler, ; 11. goto 1 ; ; ------------------------------------------------------------------------ ; Total timing formula: N = 25 000 * Fx = ((9*T1+4)*T2+4)*T3+5+9*T4+Z ; ; N = 25 000 * Fx [MHz] ; ; Example: Fx = 4 MHz ; ; N = 25 000 * 4 = 100 000 ; N = 25 000 * Fx = ((9*T1+4)*T2+4)*T3+5+9*T4+Z ; ; SW Tuning ; ----------- ; The calibration tuning is possible by EEPROM parameters 07h and ; 08h. The minimum chnage step for timing is 1 us based on the 4 MHz ; crystal. Relation is 1 us/100000 us. == 0.00001. ; A bit smaller value for T4 is used than calculated above to get area ; for final correction +/- by EE_fine1 and EE_fine2. The correct ; calibration value is found by means of the combination of EE_fine1&2 ; and comparing to reference source. ; E.g. the freq. of calibrated reference source is 10.00000 MHz and ; counter shows 9.99980 MHz. EE_fine1 = 14 and EE_fine2 = 1 ; EE_fine1 & 2 delay = 14*3 us + 1*4 us = 46 us. ; The counting window is too short. Let's count the absolute influence ; value on 10 MHz: 0.00001 * 10 MHz = 100 Hz. Now we can calculate that ; we must increase value by 20 Hz == 2 us. ; The results are EE_fine1 =12 and EE_fine2 =3 (12*3us + 3*4us) = 48 us ; The most accurate tuning is made by adjusting one of the capacitor in ; the crystal circuit. ; ------------------------------------------------------------------------ include ; ------------------------------------------------------------------------ Index equ 0Ch ; dummy register Count equ 0Dh ; inkremental register Help equ 0Eh ; dummy register LED0 equ 0Fh LED1 equ 010h LED2 equ 011h LED3 equ 012h LED4 equ 013h LED5 equ 014h LED6 equ 015h CHAR equ 016h ; LCD subroutines internal use TimerH equ 017h ; the highest byte of SW counter LowB equ 018h ; low byte of resulted frequency MidB equ 019h ; middle byte of resulted frequency HigB equ 01Ah ; high byte of resulted frequency TEMP equ 01Bh ; temporary register HIndex equ 01Ch ; index register LEDIndex equ 01Dh ; LED pointer R1 equ 01Eh ; Timing counters R2 equ 01Fh R3 equ 020h USER_EEADR equ 021h ; EEPROM address USER_EEDATA equ 022h ; EEPROM data EE_ALR_READ equ 023h ; EEPROM address already read EE_Fine1 equ 024h ; EEPROM calibration parameter 1 EE_Fine2 equ 025h ; EEPROM calibration parameter 2 Help2 equ 026h ; temporary register LowB_ref equ 027h ; LowB value for frequency reference MidB_ref equ 028h ; MidB value for frequency reference HigB_ref equ 029h ; HighB value for frequency reference Status_word equ 02Ah ; Frequency lock status word Delay_counter equ 02Bh ; Frequency lock delay counter Sample_counter equ 02Ch ; Sample counter for frequency lock ; ------------------------------------------------------------------------ ; LCD variables ; ------------------------------------------------------------------------ ;Xtal equ 4 ; MHz DELAY15 equ .21 ; 1+15000*Xtal/4/770 DELAY4100 equ .7 ; 1+4100*Xtal/4/770 DELAY100 equ 1 ; 1+100*Xtal/4/770 LINE0 equ 0 LINE1 equ 040h E equ 2 ; LCD Enable control line RA2 R_W equ 1 ; LCD Read/Write control line RA1 RS equ 0 ; LCD Register-Select control line RA0 ; PORTB bits ; LCD Data are sent through RB4 - RB7 ; ------------------------------------------------------------------------ ; timing loop values ; must be from 1 to 255!!! T1 equ .199 ; first timing loop T2 equ .11 ; second timing loop T3 equ .5 ; third timing loop T4 equ .130 ; last timing loop ; ------------------------------------------------------------------------ org 0 Start clrf STATUS ; Do initialization, Select bank 0 clrf INTCON ; Clear int-flags, Disable interrupts clrf PCLATH ; Keep in lower 2KByte clrf PORTA ; ALL PORT output should output Low. clrf PORTB clrf Index clrf LEDIndex clrf LED0 clrf LED1 clrf LED2 clrf LED3 clrf LED4 clrf LED5 clrf LED6 clrf LowB clrf MidB clrf HigB clrf Delay_counter ; For Frequency lock function clrf Sample_counter ; For Frequency lock function clrf Status_word ; For Frequency lock function bsf STATUS,RP0 movlw b'00010000' ; RA0..RA3 outputs movwf TRISA ; RA4 input movlw 0xFF ; RB0..RB7 inputs movwf TRISB bsf OPTION_REG,NOT_RBPU ; Disable PORTB pull-ups clrwdt movlw b'10100111' ; Prescaler -> TMR0, movwf OPTION_REG ; 1:256, rising edge bcf STATUS,RP0 ; ; Initilize LC-Display Module ; Busy-flag is not yet valid clrf PORTA ; ALL PORT output should output Low. ; Initilize the LCD Display Module clrf PORTB ; ALL PORT output should output Low bcf PORTA,E ; Clear all controll lines bcf PORTA,RS bcf PORTA,R_W movlw DELAY15 ; Wait for 15ms for LCD to get powered up movwf R1 clrf R2 LCycle decfsz R2,F goto LCycle ; 3*256 decfsz R1,F ; 3*256+1 goto LCycle ;(3*256+2)*R1=770*R1 in procesor cycles ;****************************************************************************** ; Initialization of LCD display ;****************************************************************************** movlw 0x0F andwf PORTB,F ; Clear the upper nibble movlw 0x030 ; Command for 4-bit interface high nibble iorwf PORTB ; Send data to LCD bsf STATUS,RP0 ; Select Register page 1 movlw 0x0F andwf TRISB,W movwf TRISB ; Set Port for output bcf STATUS,RP0 ; Select Register page 0 bsf PORTA,E ; Clock the initalize command to LCD module bcf PORTA,E movlw DELAY4100 ; Delay for at least 4.1ms before continuing movwf R1 clrf R2 LCycle2 decfsz R2,F goto LCycle2 ; 3*256 decfsz R1,F ; 3*256+1 goto LCycle2 ;(3*256+2)*R1=770*R1 in procesor cycles bsf PORTA,E ; Clock the initalize command to LCD module bcf PORTA,E movlw DELAY100 ; Wait for 100 us movwf R1 clrf R2 LCycle3 decfsz R2,F goto LCycle3 ; 3*256 decfsz R1,F ; 3*256+1 goto LCycle3 ;(3*256+2)*R1=770*R1 in procesor cycles movlw 0x0F andwf PORTB,F ; Clear the upper nibble movlw 020h ; Command for 4-bit interface high nibble iorwf PORTB ; Send data to LCD bsf PORTA,E ; Clock the initalize command to LCD module bcf PORTA,E movlw 0x028 ; 4 bits, 2 lines, 5x7 Font call PutCMD movlw B'00001000'; disp.off, curs.off, no-blink call PutCMD movlw 1 ; LCD clear call PutCMD movlw B'00001100'; disp.on, curs.off call PutCMD movlw B'00000110'; auto-inc (shift-cursor) call PutCMD ;------------------------------------------------------------------------ movlw 7 ; Read calibration values from EEPROM movwf USER_EEADR call EE_read movwf EE_Fine1 movlw 8 ; Read calibration values from EEPROM movwf USER_EEADR call EE_read movwf EE_Fine2 ;------------------------------------------------------------------------ movlw 0Bh ; Read Freq lock function status movwf USER_EEADR call EE_read btfsc STATUS,Z ; If 0 then enabled -> set bit 2 SW bsf Status_word,2 ;------------------------------------------------------------------------ ; This checks the first power-on. If true then save initial values to ; EEPROM memory. Finger print of this procedure is in EE address 00Fh ;------------------------------------------------------------------------ EEPROM_init_check movlw 00Fh ; EE address 00Fh movwf USER_EEADR call EE_read ; Read EEPROM address 0Fh btfsc STATUS,Z ; then skip to Mode_test goto Mode_test ; movlw 'E' ; call PutCHAR ; Display character ; movlw 'E' ; call PutCHAR ; Display character ; movlw '-' ; call PutCHAR ; Display character ; movlw 'I' ; call PutCHAR ; Display character ; movlw 'N' ; call PutCHAR ; Display character ; movlw 'I' ; call PutCHAR ; Display character ; movlw 'T' ; call PutCHAR ; Display character ; movlw ':' ; call PutCHAR ; Display character call Delay_200ms movlw 0 ; Start saving of default data movwf USER_EEADR ; from EE address 0h Next_Data_to_EE movf USER_EEADR,W movwf EEADR ; Save address for EE writing routine call EE_Table ; W contains address of EE_table movwf EEDATA ; Save data to EE writing routine call EE_write ; Writing to EEPROM subroutine movlw LINE1 ; continue at right half of the display iorlw 080h ; Function set call PutCMD ; set cursor leftmost at the first line call Busy ; Wait until positioned (takes 40 us) movf USER_EEADR,W call CharTable ; Pick up char to be displayed. call PutCHAR ; Display EEADR as ASCII character call Delay_200ms ; Delay is needed to get PIC ready ; for next EEPROM save function! ; Otherwise this loop doesn't work! movf USER_EEADR,W sublw 00Fh ; Loop test for addresses 00h...0Fh btfss STATUS,C ; if C = 0 --> negative result goto Mode_test ; Address 0F completed -> exit this incf USER_EEADR,F ; increment USER_EEADR goto Next_Data_to_EE ; ;------------------------------------------------------------------------ ; This checks the normal counter mode or EEPROM SETTINGS mode acc. RB0 ;------------------------------------------------------------------------ Mode_test movlw 1 ; LCD clear call PutCMD btfss PORTB,0 goto Entry ; to line 509 goto EE_Routines ; if RB0 = 1 then to EE settings ;------------------------------------------------------------------------ ; Tables for 3 byte constants ;------------------------------------------------------------------------ ; Table of decades ;------------------------------------------------------------------------ DecTable addwf PCL,F ; W + PCL -> PCL retlw 0 ; 10 retlw 0 ; retlw 0Ah ; retlw 0 ; 100 retlw 0 ; retlw 064h ; retlw 0 ; 1 000 retlw 03h ; retlw 0E8h ; retlw 0 ; 10 000 retlw 027h ; retlw 010h ; retlw 01h ; 100 000 retlw 086h ; retlw 0A0h ; retlw 0Fh ; 1 000 000 retlw 042h ; retlw 040h ; CharTable addwf PCL,F ; W + PCL -> PCL retlw '0' ; retlw '1' ; retlw '2' ; retlw '3' ; retlw '4' ; retlw '5' ; retlw '6' ; retlw '7' ; retlw '8' ; retlw '9' ; retlw 'A' ; retlw 'B' ; retlw 'C' ; retlw 'D' ; retlw 'E' ; retlw 'F' ; ;-------------------------------------------------------------------------- ; The used EEPROM addresses and default values: ; 00 = MFt1_HigB = High Byte of RF offset1 (def. 0D) 9001.50 kHz = 0DBC36 ; 01 = MFt1_MidB = Mid Byte of RF offset1 (def. BC) ; 02 = MFt1_LowB = Low Byte of RF offset1 (def. 36) ; 03 = MFt2_HigB = High Byte of RF offset2 (def. 0D) 8998.50 khz = 0DBB0A ; 04 = MFt2_MidB = Mid Byte of RF offset2 (def. BB) ; 05 = MFt2_LowB = Low Byte of RF offset2 (def. 0A) ; 06 = Dir_freq = Direct frequency without sub or add functions = 0 def. ; 07 = EE_Fine1 = Counter value for calibration 1 == 3*4/fx= 3us (def. 15) ; 08 = EE_Fine2 = Counter value for calibration 1 == 4*4/fx= 4us (def. 01) ; 09 = 1x16_Disp = LCD display type: 0 = 1x16 LCD, 1 = 2x20 LCD (def. 00) ; 0A = Digits = Number of displayed digits: 0 = 7 digits, 1 = 6 (def. 0) ; 0B = Freq_lock = Frequency lock func. indicating freq difference. ; 00h = Enabled, 01...FF = Disabled, (def. FF) ; 0C = Ten_div = Ten_divider activated in Freq-lock mode ; 00h = Enabled, 01..FFh = Disabled (def. FF) ; 0D = Delay = Delay time before frequency lock procedure starts after ; out of lock situation. 1 == 10 Hz (def. 032h == 5 s.) ; 0E = Sampling = Number of samples with reference and lock check ; 1h == 1 sample (def. = 05h) ; 0F = Defaults = Default values are restored to EEPROM if set to >00h. ;-------------------------------------------------------------------------- ; Default data table for EEPROM addresses 00h...0Fh ;-------------------------------------------------------------------------- EE_Table addwf PCL,F ; W + PCL -> PCL retlw 00Dh ; 00h retlw 0BCh ; 01h retlw 036h ; 02h retlw 00Dh ; 03h retlw 0BBh ; 04h retlw 00Ah ; 05h retlw 000h ; 06h retlw 014h ; 07h retlw 001h ; 08h retlw 000h ; 09h retlw 000h ; 0A retlw 0FFh ; 0B retlw 0FFh ; 0C retlw 032h ; 0D retlw 005h ; 0E retlw 000h ; 0F ; This is used as finger print ; to do this subroutine only once. ;************************************************************************* ; LCD Module Subroutines ;======================================================================== ; Busy: Returns when LCD busy-flag is inactive ; PORTA returns as RA0..RA2 output, RA3,RA4 input ;************************************************************************ Busy bsf STATUS,RP0 ; Select Register page 1 movlw 0xF0 ; Set port to input iorwf TRISB,W ; Only set upper half of port movwf TRISB movlw b'00011000' ; PORTA should be set RA0..RA2 output movwf TRISA ; RA3,RA4 input bcf STATUS,RP0 ; Select Register page 0 bcf PORTA,RS ; Set LCD for Command mode bsf PORTA,R_W ; Setup to read busy flag bsf PORTA,E ; Set E high movf PORTB,W ; Read upper nibble busy flag, DDRam address andlw 0xF0 ; Mask out lower nibble movwf TEMP bcf PORTA,E ; Set E low nop nop bsf PORTA,E ; Toggle E to get lower nibble bcf PORTA,E swapf PORTB,W ; Read lower nibble busy flag, DDRam address andlw 0x0F ; Mask out upper nibble iorwf TEMP,W ; Combine nibbles btfsc TEMP,7 ; Check busy flag, high = busy goto Busy ; If busy, check again bcf PORTA,R_W bsf STATUS,RP0 ; Select Register page 1 movlw 0x0F andwf TRISB,W movwf TRISB ; Set Port for output bcf STATUS,RP0 ; Select Register page 0 return ;======================================================================== ; PUTCHAR Sends character to LCD, Required character must be in W ;======================================================================== PutCHAR movwf CHAR ; Character to be sent is from W saved call Busy ; Wait for LCD to be ready ; Busy routine sets PORTB adequately movlw 0x0F andwf PORTB,F ; Clear the upper nibble movf CHAR,W andlw 0xF0 ; Get upper nibble iorwf PORTB,F ; Send data to LCD bcf PORTA,R_W ; Set LCD to write bsf PORTA,RS ; Set LCD to data mode bsf PORTA,E ; toggle E for LCD bcf PORTA,E movlw 0x0F andwf PORTB,F ; Clear the upper nibble swapf CHAR,W andlw 0xF0 ; Get lower nibble iorwf PORTB,F ; Send data to LCD bsf PORTA,E ; toggle E for LCD bcf PORTA,E return ;======================================================================== ; PutCMD Sends command to LCD, Required command must be in W ;======================================================================== PutCMD movwf CHAR ; Command to be sent is from W saved call Busy ; Wait for LCD to be ready movlw 0x0F andwf PORTB,F ; Clear the upper nibble movf CHAR,W andlw 0xF0 ; Get upper nibble iorwf PORTB,F ; Send data to LCD bcf PORTA,R_W ; Set LCD to write bcf PORTA,RS ; Set LCD to command mode bsf PORTA,E ; toggle E for LCD bcf PORTA,E movlw 0x0F andwf PORTB,F ; Clear the upper nibble swapf CHAR,W andlw 0xF0 ; Get lower nibble iorwf PORTB,F ; Send data to LCD bsf PORTA,E ; toggle E for LCD bcf PORTA,E return ;************************************************************************ ; End of LCD Module Subroutines ;************************************************************************ ;************************************************************************ ; Delay Routines ;************************************************************************ Delay_200ms movlw 0FFh ; Wait for 200ms for LCD to get powered up movwf R1 clrf R2 LCycle4 decfsz R2,F goto LCycle4 ; 3*256 decfsz R1,F ; 3*256+1 goto LCycle4 ;(3*256+2)*R1=770*R1 in processor cycles return ;************************************************************************ ; EEPROM READ ROUTINE ; ; Input: read address in USER_EEADR also in w ; Output: data in USER_EEDATA also in w ;************************************************************************ EE_read bcf STATUS,RP0 ; Bank 0 movf USER_EEADR,w; EE address movwf EEADR ; Address to read bsf STATUS,RP0 ; Bank 1 bsf EECON1,RD ; EE Read bcf STATUS,RP0 ; Bank 0 movf EEDATA,w ; w = EEDATA movwf USER_EEDATA ; Data return ;************************************************************************ ; EEPROM WRITE ROUTINE ; ; Input: write address in USER_EEADR also in w ; data in USER_EEDATA also in w ; Output: - ;************************************************************************ EE_write bsf STATUS,RP0 ; Bank 1 bcf INTCON,GIE ; INTs disabled bsf EECON1,WREN ; Enable write ;-------------------------------------------------------- ; Magic macro with EEPROM save (see 16C84 manual) ;-------------------------------------------------------- movlw 55h movwf EECON2 movlw 0AAh movwf EECON2 bsf EECON1,WR ee_wr1 btfsc EECON1,WR ; is the write completed? goto ee_wr1 ; loop until completed bsf INTCON,GIE ; Enable INTs return ;************************************************************************ ; 24 bit subtract routine 010809 -pn- ; ; 3 byte substraction of the frequency reference. Carry is set if ; result is negative. Temporary nonused registers LED0..LED6 are used. ;************************************************************************ ; Inputs: LED4 - LED0 (used for LowB) ; LED5 - LED1 (used for MidB) ; LED6 - LED2 (used for HigB) ;------------------------------------------------------------------------ ; Outputs: The result of 24 bit Subtraction is saved to ; LED4 (LowB) ; LED5 (MidB) ; LED6 (HigB) ; Register W contain the result for STATUS checking. ;************************************************************************ Sub24bit bcf Status_word,4 ; Clear carry status bit movf LED0,W ; sub LowB subwf LED4,F ; from LED4 btfsc STATUS,C ; underflow? goto sb0 ; no underflow decf LED5,F ; check 00 -> ff incf LED5,F ; ff?, Z then 1, LED5+1 btfss STATUS,Z ; ... but if wasn't ff goto notFF decf LED6,F ; dec also LED6 notFF decf LED5,F ; correct LED5+1 -> MidB sb0 movf LED1,W ; middle byte subwf LED5,F ; subtract btfsc STATUS,C ; if underflow to MSbyte goto sb1 ; no underflow decf LED6,F ; check 00 -> ff sb1 movf LED2,W ; MSByte subwf LED6,F ; sub it btfsc STATUS,C bsf Status_word,4 ; Set if Carry = 1 return ;************************************************************************ ; 24 bit Addition routine ; ; 3 byte addition. Carry is set if result is negative. ; Temporary nonused registers LED0..LED6 are used. ;************************************************************************ ; Inputs: LED4 + LED0 (used for LowB) ; LED5 + LED1 (used for MidB) ; LED6 + LED2 (used for HigB) ;------------------------------------------------------------------------ ; Outputs: The result of 24 bit Addition is saved to ; LED4 (LowB) ; LED5 (MidB) ; LED6 (HigB) ; Register W contain the result for STATUS checking. ;************************************************************************ Add24bit bcf Status_word,4 ; Clear carry status bit movf LED0,W addwf LED4,F btfss STATUS,C goto Addsb2 incfsz LED5,F goto Addsb2 movlw 1 addwf LED6,F btfsc STATUS,C bsf Status_word,4 ; Set if Carry = 1 Addsb2 movf LED1,W addwf LED5,F btfss STATUS,C goto Addsb3 incf LED6,F Addsb3 movf LED2,W addwf LED6,F btfsc STATUS,C bsf Status_word,4 ; Set if Carry = 1 return ;*********************************************************************** ; Preparation subcall for subtraction Freq_act - Freq_ref 24 bit ;*********************************************************************** Preparation movf LowB_ref,W ; Preparation for sub call movwf LED0 movf MidB_ref,W movwf LED1 movf HigB_ref,W movwf LED2 return ;*********************************************************************** ; Zero result check of subtraction ;*********************************************************************** Zero_check bcf Status_word,6 movlw 1 subwf LED4,W ; = LowB of subtraction result btfsc STATUS,C ; if negative -> LED4 is zero goto Not_zero1 movlw 1 subwf LED5,W ; = MidB of subtraction result btfsc STATUS,C ; if negative -> LED5 is zero goto Not_zero1 bsf Status_word,6 ; zero result Not_zero1 return ;*********************************************************************** ; Display Offset Checking either Display Offset 1 or 2. Load offsets. ;*********************************************************************** Offset_check movlw 3 btfss PORTB,1 ; True? Then Mft2 movlw 0 ; Mft1 selected ;----------------------------------------------------------------------- ; Display Offset read from EEPROM to registers LED4...6 ;----------------------------------------------------------------------- movwf USER_EEADR call EE_read movwf LED6 ; Offset1 HigB --> LED6 incf USER_EEADR,F call EE_read movwf LED5 ; Offset1 MidB --> LED5 incf USER_EEADR,F call EE_read movwf LED4 ; Offset1 LowB --> LED4 return EE_Routines ;*********************************************************************** ; EEPROM MODE TEXTS ;*********************************************************************** movlw LINE0 iorlw 080h ; set cursor leftmost at the first line call PutCMD call Busy ; Wait until positioned (takes 40 us) movlw 'E' call PutCHAR ; Display character movlw 'E' call PutCHAR ; Display character ; movlw 'P' ; call PutCHAR ; Display character ; movlw 'R' ; call PutCHAR ; Display character ; movlw 'O' ; call PutCHAR ; Display character ; movlw 'M' ; call PutCHAR ; Display character movlw ' ' call PutCHAR ; Display character ; movlw LINE1 ; continue at right half of the display ; iorlw 080h ; Function set ; call PutCMD ; set cursor leftmost at the first line ; call Busy ; Wait until positioned (takes 40 us) movlw 'M' call PutCHAR ; Display character movlw 'O' call PutCHAR ; Display character movlw 'D' call PutCHAR ; Display character movlw 'E' call PutCHAR ; Display character movlw '-' call PutCHAR ; Display character movlw '1' call PutCHAR ; Display character movlw '.' call PutCHAR ; Display character movlw '4' call PutCHAR ; Display character call Delay_200ms ; Show the text call Delay_200ms ; at least 3x200ms... call Delay_200ms ; movfw PORTB ; ...until RB0...RB3 are zero andlw 00Fh ; btfss STATUS,Z ; RB0...RB3 false? goto EE_Routines ; No movlw 001h ; Clear display call PutCMD call Busy ; Wait until cleared (takes 1.6 ms) clrf USER_EEADR clrf USER_EEDATA clrf EE_ALR_READ ;*********************************************************************** ; Switch routines ;*********************************************************************** Io_test Check_RB0 btfss PORTB,0 goto Check_RB1 incf USER_EEADR,1 ; USER_EEADR = USER_EEADR + 1 movf USER_EEADR,0 ; w = USER_EEADR sublw 00Fh ; EE Address range 0...F btfss STATUS,C ; if C = 0 --> negative result clrf USER_EEADR call Delay_200ms bcf EE_ALR_READ,0 ; reset if address is changed Check_RB1 btfss PORTB,1 goto Check_RB2 incf USER_EEDATA,1 call Delay_200ms Check_RB2 btfss PORTB,2 goto Check_RB3 decf USER_EEDATA,1 call Delay_200ms Check_RB3 btfss PORTB,3 goto Continue call Delay_200ms movf USER_EEADR,0 movwf EEADR movf USER_EEDATA,0 movwf EEDATA call EE_write ;-------------------------------------------------------- movlw 001h ; Clear display call PutCMD call Busy ; Wait until cleared (takes 1.6 ms) movlw '*' call PutCHAR ; Display character movlw 'S' call PutCHAR ; Display character movlw 'A' call PutCHAR ; Display character movlw 'V' call PutCHAR ; Display character movlw 'E' call PutCHAR ; Display character movlw 'D' call PutCHAR ; Display character movlw '*' call PutCHAR ; Display character call Delay_200ms call Delay_200ms call Delay_200ms call Delay_200ms movlw 001h ; Clear display call PutCMD ; It takes about 1.6 ms call Busy ; Wait until cleared clrf EE_ALR_READ ;-------------------------------------------------------- Continue movlw 'A' call PutCHAR ; Display character movlw 'D' call PutCHAR ; Display character movlw 'D' call PutCHAR ; Display character movlw 'R' call PutCHAR ; Display character movlw ':' call PutCHAR ; Display character btfsc EE_ALR_READ,0 ; Data read, value not changed goto Display_EE call EE_read bsf EE_ALR_READ,0 ; Same data is read only once ;------------------------------------------------------------------------ Display_EE movf USER_EEADR,0 ; Display address left digit first andlw 0F0h movwf Help swapf Help,0 call CharTable ; Pick up char to be displayed call PutCHAR ; Display character movf USER_EEADR,0 andlw 00Fh call CharTable ; Pick up char to be displayed call PutCHAR ; Display character ;------------------------------------------------------------------------ movlw LINE1 ; continue at right half of the display iorlw 080h ; Function set call PutCMD ; set cursor leftmost at the first line call Busy ; Wait until positioned (takes 40 us) movlw 'D' call PutCHAR ; Display character movlw 'A' call PutCHAR ; Display character movlw 'T' call PutCHAR ; Display character movlw 'A' call PutCHAR ; Display character movlw ':' call PutCHAR ; Display character ;------------------------------------------------------------------------ movf USER_EEDATA,0 ; Display data left digit first andlw 0F0h movwf Help swapf Help,0 call CharTable ; Pick up char to be displayed call PutCHAR ; Display character movf USER_EEDATA,0 andlw 00Fh call CharTable ; Pick up char to be displayed call PutCHAR ; Display character ;------------------------------------------------------------------------ movlw LINE0 iorlw 080h ; Function set call PutCMD call Busy ; Wait until positioned (takes 40 us) goto Io_test ;************************************************************************ ; End of EEPROM routines ;************************************************************************ ; Numeric routines ;------------------------------------------------------------------------ ; 3 byte substraction of the constant from the table which sets carry if ; result is negative ;------------------------------------------------------------------------ Subc24 clrf TEMP ; it will TEMPorary save C movf Index,W ; pointer to low byte of constant movwf HIndex ; W -> HIndex call DecTable ; W returned with low byte of constant subwf LowB,F ; LowB - W -> LowB ; if underflow -> C=0 btfsc STATUS,C goto Step1 movlw 1 subwf MidB,F ; decrement MidB ; if underflow -> C=0 btfsc STATUS,C goto Step1 movlw 1 subwf HigB,F ; decrement HigB btfsc STATUS,C ; if underflow -> C=0 goto Step1 bsf TEMP,C ; set C Step1 decf HIndex,F movf HIndex,W ; pointer to middle byte of const call DecTable subwf MidB,F ; MidB - W -> MidB btfsc STATUS,C ; if underflow -> C=0 goto Step2 movlw 1 subwf HigB,1 ; decrement HigB btfsc STATUS,C ; if underflow -> C=0 goto Step2 bsf TEMP,C ; set C Step2 decf HIndex,F movf HIndex,W ; pointer to middle byte of constatnt call DecTable subwf HigB,F ; HigB - W -> HigB btfsc STATUS,C ; if underflow -> C=0 goto ClearCF bsf STATUS,C goto SubEnd ClearCF rrf TEMP,C ; C -> STATUS SubEnd retlw 0 ; ------------------------------------------------------------------------ ; 3 byte addition of the constant from the table which sets carry if ; result overflows ; ------------------------------------------------------------------------ Addc24 clrf TEMP ; register for TEMPorary storage of C movf Index,W ; pointer to lower byte of const into W movwf HIndex ; save it into HIndex call DecTable ; W contains low byte of const addwf LowB,1 ; W + LowB -> LowB btfss STATUS,C ; test overflow goto Add2 movlw 1 addwf MidB,F ; increment MidB btfss STATUS,C goto Add2 movlw 1 addwf HigB,F ; increment HigB btfss STATUS,C ; test overflow goto Add2 bsf TEMP,C ; store C Add2 decf HIndex,F ; pointer to middle byte into W movf HIndex,W call DecTable addwf MidB,1 ; W + MidB -> MidB btfss STATUS,C goto Add3 movlw 1 addwf HigB,1 ; increment HigB btfss STATUS,C goto Add3 bsf TEMP,C Add3 decf HIndex,F ; pointer to higher byte into W movf HIndex,W call DecTable addwf HigB,F ; W + HigB -> HigB, btfss STATUS,C goto ClarCF bsf STATUS,C goto AddEnd ClarCF rrf TEMP,C ; C -> STATUS AddEnd retlw 0 ;************************************************************************ ; Entry point for main cycle ;------------------------------------------------------------------------ ; Routine for the conversion of 3 byte number into 7 decimal numbers ;************************************************************************ Entry movlw 6*3-1 ; pointer to dec. table movwf Index ; 6*3-1 -> Index movlw 9 ; maximum of substractions movwf Count ; 9 -> Count clrf Help movlw 6 movwf LEDIndex Divide call Subc24 ; substract untill result is negative, btfsc STATUS,C ; add last substracted number goto Add24 ; next digit incf Help,F decf Count,F btfss STATUS,Z goto Divide movlw 3 subwf Index,F goto Next Add24 call Addc24 movlw 03h subwf Index,F Next movlw 9 movwf Count movlw LED1 ; LED1 -> W addwf LEDIndex,W ; LED1 + LEDIndex -> W movwf TEMP decf TEMP,F ; LEDIndex+LED1-1 -> TEMP movf TEMP,W movwf FSR ; W -> FSR movf Help,W ; Help -> W clrf Help ; save result at LEDx movwf INDF ; W -> LED(6..1) decf LEDIndex,F movlw 1 addwf Index,W btfss STATUS,Z goto Divide movf LowB,W movwf LED0 ; the rest -> LED0 ;------------------------------------------------------------------------- btfss Status_word,5 ; Frequency is within +/- 20 Hz goto Ready_to_display bcf PORTB,0 ; Clear outputs to get short pulse bcf PORTB,3 ; for fine frequency correction. Ready_to_display ;------------------------------------------------------------------------- ; registers LED0..LED6 are filled with values - ready to be displayed ;------------------------------------------------------------------------- movlw 6 movwf LEDIndex ;-------------------------------------------------------------------------- ; Next clears DDRAM position 07h if 10 divider and normal mode is switched. ; Othervise it causes incorrect frequency reading because of decimal point ; location change. 14.500.1 MHz --> 8th character must be cleared! ; With 10 divider: 145.001 MHz (incorrectly 145.0011) ; Also address 0Bh must be cleared to prevent text MHzz ;-------------------------------------------------------------------------- movf USER_EEADR,0 ; Do it only if bit 3 state has been andwf PORTB,0 ; changed compared to the previous movwf USER_EEDATA ; value. btfsc USER_EEDATA,3 ; Is RB3 state changed? goto cursor_cntr ; No, pass next! movlw 7 ; locate cursor to address 07h (8th ch) iorlw 080h ; Function set call PutCMD ; Position cursor leftmost on second row call Busy ; Wait until positioned (takes 40 us) movlw ' ' ; Clear previous character call PutCHAR ; Display "empty" character movlw 00Bh ; locate cursor to address 00Bh (12th ch) iorlw 080h ; Function set call PutCMD ; Position cursor leftmost on second row call Busy ; Wait until positioned (takes 40 us) movlw ' ' ; Clear previous character call PutCHAR ; Display "empty" character ;-------------------------------------------------------------------------- cursor_cntr movlw LINE0 iorlw 080h ; Position cursor leftmost on first line call PutCMD call Busy ; Wait until positioned (takes 40 us) movf PORTB movwf USER_EEADR ; This flag is used as temporary variable ; for checking the same address read only ; once, if no changes for address. LEDCycle movlw LED0 ; LED0 -> W addwf LEDIndex,W ; LED1 + LEDIndex -> W movwf FSR ; W -> FSR movf INDF,W ; LED(0..6) -> W ;--------------------------------------------------------------------------- ; Following tests the 10 MHz digit value. If zero then not displayed. ; E.g. 0 3.6 9 4.0 0 MHz --> 3.6 9 4.0 0 MHz ; LEDIndex 6 5 4 3 2 1 0 value according to digit ;--------------------------------------------------------------------------- btfsc STATUS,Z goto Clear_zero iorlw 030h call PutCHAR ; Display character goto Next_test Clear_zero movlw 6 ; Is the LEDIndex value 6? subwf LEDIndex,W btfss STATUS,Z ; If ZERO is set, it is 6 goto Zero_ok movlw ' ' ; This is instead of '0' call PutCHAR ; Display character goto Next_test Zero_ok movlw '0' ; call PutCHAR ; Display character '0' Next_test ;-------------------------------------------------------------------- ; If frequency lock function has been activated by 00Bh parameter, ; decimal point movement is controlled only by EE 00Ch, not with RB3. ;-------------------------------------------------------------------- btfss Status_word,2 ; Freq lock function enabled = 1 goto No_freq_lock movlw 00Ch ; Test the 10 divider movwf USER_EEADR call EE_read btfss STATUS,Z ; If zero flag=1 then 10 divider goto Two_to_w bsf Status_word,7 ; Ten divider sel. by parameter goto Ten_divider No_freq_lock ;-------------------------------------------------------------------- ; This tests the additional 10 divider and therefore controls the ; position of decimal point according to RB3 selection. ; E.g. f=145.500.0 / 10 = 14.550.00 --> decimal point move 145.500.0 ;-------------------------------------------------------------------- btfsc PORTB,3 ; If 0 then no 10 divider goto Ten_divider ; Two_to_w bcf Status_word,7 ; No ten divider sel. by parameter movlw 2 ; test for decimal point movwf Help2 goto Dec_point Ten_divider movlw 1 ; test for decimal point movwf Help2 ;-------------------------------------------------------------------- ; Test for combination of 6 digits and 10 divider -> no need to ; display second decimal point --> skip to Second_dot_test. ; (e.g. 145.150. MHz -> 145.150 MHz ) ;-------------------------------------------------------------------- ;-------------------------------------------------------------------------- ; This tests the 10Hz or 100 Hz to be displayed as a last digit ;-------------------------------------------------------------------------- movlw 00Ah ; Test the number of digits (6 or 7) movwf USER_EEADR call EE_read btfss STATUS,Z ; If 1 then 7 digits goto Second_dot_test ; Skip second decimal point print ;-------------------------------------------------------------------------- Dec_point movf Help2,0 ; Help2 --> w subwf LEDIndex,W btfss STATUS,Z goto Second_dot_test movlw '.' ; this can be ' ' or ',' ...... call PutCHAR ; Display character Second_dot_test ;-------------------------------------------------------------------- ; **** 10 Divider test **** ; This tests first the additional 10 divider HW and therefore ; controls the position of decimal point according to RB3 selection. ; E.g. f=145.500.0 / 10 = 14.550.00 --> decimal point move 145.500.0 ; ; f = 1 4 5.5 0 0.0 MHz ; LEDIndex = 6 5 4 3 2 1 0 value in digit ;-------------------------------------------------------------------- btfss Status_word,2 ; Freq lock function enabled = 1 goto RB3_test btfsc Status_word,7 ;1=Ten divider sel. by parameter goto Ten_divider2 goto Five_to_w RB3_test btfsc PORTB,3 ; If 0 then no 10 divider goto Ten_divider2 ; Five_to_w movlw 5 ; test for decimal point goto Dec_point2 Ten_divider2 movlw 4 ; test for decimal point ;-------------------------------------------------------------------- Dec_point2 subwf LEDIndex,W btfss STATUS,Z goto sixth_mark movlw '.' ; this can be ' ' or ',' ...... call PutCHAR ; Display character sixth_mark movlw 9 ; Test the display type 1 x 16 LCD movwf USER_EEADR call EE_read btfss STATUS,Z ; If 0 then 1x16 LCD goto NoDot ; other type than 1x16 LCD ;------------------------------------------------------------------------- ; 1x16 LCD 9th character control. This is passed with other LCD types ;------------------------------------------------------------------------- movlw 1 ; 1x16 LCD subwf LEDIndex,W btfss STATUS,Z goto NoDot ; According to 1x16 LCD the 9th character address is 040h (LINE1 = 040h) movlw LINE1 ; continue at right half of display iorlw 080h ; Function set call PutCMD ; Position cursor leftmost on first line call Busy ; Wait until positioned (takes 40 us) ;-------------------------------------------------------------------------- NoDot decfsz LEDIndex,F goto LEDCycle ; continue with next number ;-------------------------------------------------------------------------- ; This tests the 10Hz or 100 Hz to be displayed as a last digit ; f = 1 4 5.5 0 0.0 MHz ; LEDIndex = 6 5 4 3 2 1 0 ;-------------------------------------------------------------------------- movlw 00Ah ; Test the number of digits (6 or 7) movwf USER_EEADR ; Read it from EEPROM address 0Ah. call EE_read btfss STATUS,Z ; If 1 then 7 digits goto MHz_text ; If 6 digits. LEDIndex 0 not displayed. ;-------------------------------------------------------------------------- movlw LED0 ; LED0 -> W addwf LEDIndex,W ; LED0 + LEDIndex -> W movwf FSR ; W -> FSR movf INDF,W ; [FSR] -> W iorlw 030h call PutCHAR ; Display character MHz_text movlw ' ' call PutCHAR ; Display character movlw 'M' call PutCHAR ; Display character movlw 'H' call PutCHAR ; Display character movlw 'z' call PutCHAR ; Display character ;------------------------------------------------------------------------- ; Frequency lock control indicates: ; "L" = Locked if Status_word bit 0 is set ; " " = none for out of lock, typically if VFO reference changed ; Function is activated by EEPROM 0Bh = 0 and disabled when >0 ;------------------------------------------------------------------------- btfss Status_word,2 ; If bit set -> freq lock enabled goto Result_end ; No +/- for LCD movlw ' ' ; One space after MHz text call PutCHAR ; Display character btfss Status_word,0 ; Is the Locked bit set? goto Display_unlocked ; btfsc PORTB,2 ; Is RB2 freezing activated? goto Display_F Display_Lock movlw 'L' ; Load letter 'L' call PutCHAR ; Display character goto Result_end Display_F movlw 'F' ; Load letter 'L' call PutCHAR ; Display character goto Result_end Display_unlocked ; Sampling or Unlocked state movlw ' ' ; None indicates unlocked situation call PutCHAR ; Display character Result_end movlw LINE0 iorlw 080h ; Function set call PutCMD ;------------------------------------------------------------------------- ; It is time to prepare new measuring cycle ;------------------------------------------------------------------------- clrf TimerH clrf TMR0 nop ; it is SUGGESTED... nop clrf LEDIndex movlw T1 ; set initial counter values movwf R1 movlw T2 movwf R2 movlw T3 movwf R3 clrf INTCON ; global INT disable, TMR0 INT disable ; clear TMR0 overflow bite ; ------------------------------------------------------------------------ ; Start measurement: RA3 + RA4 set input ; ------------------------------------------------------------------------ movlw b'00010000' ; all ports set L, RA4 set H movwf PORTA bsf STATUS,RP0 movlw b'00011111' ; RA0..RA4 input movwf TRISA bcf STATUS,RP0 ; ------------------------------------------------------------------------- ; It is opened now... ; ------------------------------------------------------------------------- Cycle btfss INTCON,2 ; 1 Test for TMR0 overflow goto Nothing ; 3 incf TimerH,F ; 3 bcf INTCON,2 ; 4 goto Nxt ; 6 Nothing nop ; 4 nop ; 5 nop ; 6 Nxt decfsz R1,F ; 7 goto Cycle ; 9 movlw T1 ; 9*T1 movwf R1 ; 9*T1+1 decfsz R2,F ; 9*T1+2 goto Cycle ; 9*T1+4 movlw T2 ;(9*T1+4)*T2 movwf R2 ;(9*T1+4)*T2+1 decfsz R3,F ;(9*T1+4)*T2+2 goto Cycle ;(9*T1+4)*T2+4 bcf PORTB,0 ; Clear outputs to get long pulse bcf PORTB,3 ; for frequency correction. ; ------------------------------------------------------------------------ ; Final test for TMR0 overflow ; ------------------------------------------------------------------------ movlw T4 ;((9*T1+4)*T2+4)*T3 movwf Help ;((9*T1+4)*T2+4)*T3+1 Cycle2 btfss INTCON,2 ; 1 goto Not2Do ; 3 incf TimerH,F ; 3 bcf INTCON,2 ; 4 goto Nx ; 6 Not2Do nop ; 4 nop ; 5 nop ; 6 Nx decfsz Help,F ; 7 goto Cycle2 ; 9 ; nop ; ((9*T1+4)*T2+4)*T3+1+9*T4+Z ; nop ; Z times fine tuning nops ;------------------------------------------------------------------------- ; Fine tuning loops set by EEPROM parameters ;------------------------------------------------------------------------- movf EE_Fine1,0 movwf Help LCycleFine1 decfsz Help,F ; 1 Fine tuning loop 1 set by EEPROM goto LCycleFine1 ; 3 movf EE_Fine2,0 movwf Help LCycleFine2 nop ; 1 decfsz Help,F ; 2 Fine tuning loop 2 set by EEPROM goto LCycleFine2 ; 4 ; ------------------------------------------------------------------------ ; Stop the measurement ; ------------------------------------------------------------------------ clrw ; 1 movwf PORTB ; 2 movlw b'00010000' ; 3 RA0..RA3 = 0 movwf PORTA ; 4 W -> PORTA ; ((9*T1+4)*T2+4)*T3+1+9*T4+Z+4 bsf STATUS,RP0 ; movlw b'00010111' ; RA3 output Low movwf TRISA ; RA0..RA2,RA4 input bcf STATUS,RP0 ; btfsc INTCON,2 ; really final check incf TimerH,F bcf INTCON,2 ; ------------------------------------------------------------------------ ; Analyse precounter and store counted value in registers ; ------------------------------------------------------------------------ movf TMR0,W movwf MidB ; TMR0 -> MidB movf TimerH,W movwf HigB ; TimerH -> HigB clrf TEMP CountIt incf TEMP,F bsf PORTA,3 ; _| false impulz bcf PORTA,3 ; |_ bcf INTCON,2 movf TMR0,W ; actual TMR0 -> W subwf MidB,W btfsc STATUS,Z goto CountIt incf TEMP,F comf TEMP,F incf TEMP,F incf TEMP,W movwf LowB ; ------------------------------------------------------------------------ ; Frequency shift according value on RA2 pin or direct frequency display ; Both routines are simplified Subc24 and Addc24 routines ; ------------------------------------------------------------------------ movlw b'00010000' movwf PORTA bsf STATUS,RP0 movlw b'00000100' ; set RA2 as input movwf TRISA bcf STATUS,RP0 ; ************************************************************************ ; Frequency lock procedure stars here. ; ************************************************************************ btfss Status_word,2 ; If bit set -> freq lock enabled goto end_of_lock ; otherwise function is skipped ; ------------------------------------------------------------------------ ; Measured frequency is saved for temporary registers for Sub24bit. ; ------------------------------------------------------------------------ btfsc PORTB,2 ; Is bit 2 true? Means passing goto end_of_lock ; Skip the freq lock if RB2 true movf LowB,W movwf LED4 movf MidB,W movwf LED5 movf HigB,W movwf LED6 ;------------------------------------------------------------------------- ; RB0 and RB3 are set to outputs only in the Freq_lock mode ;------------------------------------------------------------------------- bsf STATUS,RP0 movlw b'11110110' ; Set port RB0 and RB3 to output andwf TRISB,W ; Other bits as before movwf TRISB bcf STATUS,RP0 ;------------------------------------------------------------------------- Lock_bit_check btfsc Status_word,0 ; Is Locked bit set? goto Lock_function ; Yes goto lock procedure movlw 00Dh ; Read user's set delay time from movwf USER_EEADR ; EEPROM call EE_read subwf Delay_counter,W btfss STATUS,Z ; Is delay counter zero? goto Inc_delay_counter btfsc Status_word,1 ; Is Sample bit set? goto cont_sample goto Save_sample Inc_delay_counter incf Delay_counter,F goto end_of_lock ; ------------------------------------------------------------------------ ; Save freq act for freq ref ; ------------------------------------------------------------------------ Save_sample movf LowB,W movwf LowB_ref ; Frequency actual to reference movf MidB,W movwf MidB_ref ; Frequency actual to reference movf HigB,W movwf HigB_ref ; Frequency actual to reference bsf Status_word,1 ; Set sample bit cont_sample call Preparation call Sub24bit ; Sub Sample - Freq_ref (24 bit) call Zero_check btfss Status_word,6 ; Is result zero? goto Underflow_check Inc_sample_counter movlw 00Eh ; Read user's set sampling time from movwf USER_EEADR ; EEPROM call EE_read subwf Sample_counter,W btfss STATUS,Z goto Sample1 bsf Status_word,0 ; Set Lock bit bcf Status_word,1 ; Clear sample bit clrf Sample_counter ; Clear sample counter for Lock_func goto end_of_lock Underflow_check movlw 2 ; Preparation for 24 bit add or sub movwf LED0 ; window checking of freq ref sample clrf LED1 ; LED4...6 includes still last sub result clrf LED2 ; 2 == 20Hz btfss Status_word,4 ; Carry status after subtraction goto Neg_val_win Pos_val_win movlw 0FDh ; FFFFFDh movwf LED0 movlw 0FFh movwf LED1 movlw 0FFh movwf LED2 call Add24bit btfsc Status_word,4 ; If overflow -> out of window goto Clear_delay_time_counter goto Inc_sample_counter Neg_val_win call Add24bit btfsc Status_word,4 ; If overflow -> within the window goto Inc_sample_counter Clear_delay_time_counter ; Frequency changed! clrf Delay_counter ; Clear delay counter bcf Status_word,1 ; Clear sample bit goto end_of_lock ; ------------------------------------------------------------------------ ; Freq Lock function routine part starts here. Sampling of reference ; is now over and Freq_ref set. Integrator control is already released ; now. This routine controls the RB0 output: ; 1 == Charging integrator capacitor ; 0 == Discharging - " - ; ------------------------------------------------------------------------ ; Status_word bit 0 = Locked Frequency lock, "L" is displayed ; bit 1 = Sampling Reference is being sampled ; bit 2 = Freq_lock_en Frequency lock function enabled (0Bh) ; bit 3 = - ; bit 4 = Carry Status Carry status after the Sub or Add ; bit 5 = Freq +/-20Hz Frequency actual is within +-20 Hz ; bit 6 = Zero result Result of 24 bit Subtraction is zero ; bit 7 = Ten Divider Ten divider function enabled ; ------------------------------------------------------------------------ Lock_function bcf Status_word,5 ; Clear bit Freq_within +/-20 Hz. call Preparation ; Transfer freq act to LED0...LED2 call Sub24bit ; Freq_sample - Freq_ref (24 bit) call Zero_check ; Zero result checking. btfsc Status_word,6 ; Zero result? goto Lock_state Not_zero movf LED4,W movwf TEMP btfsc Status_word,4 ; C=0 if underflow goto Clear_RB0 ; Bit4 clear --> Positive result Set_RB0 ; Negative subtraction result: act < ref bsf PORTB,0 ; Set RB0 bcf PORTB,3 ; Clear RB3 ; ------------------------------------------------------------------------ incf TEMP,F ; TEMP = LowB + 1 of sub result btfsc STATUS,Z ; Is zero? Means 10 Hz below reference. goto Set_SW_bit7_RB0 incf TEMP,F ; TEMP = LowB + 2 of sub result btfsc STATUS,Z ; Is zero? Means 20 Hz over reference. Set_SW_bit7_RB0 bsf Status_word,5 ; Set bit Freq_within +/- 20 Hz. ; ------------------------------------------------------------------------ clrf LED2 ; Window checking of freq act clrf LED1 ; LED4...6 incl. still latest sub result movlw 00Ah ; 0Ah == 100 Hz for window width movwf LED0 ; Preparation for 24 bit add or sub. ; ------------------------------------------------------------------------ call Add24bit ; Add 00000Ah for (Freq_act - Freq_ref) btfsc Status_word,4 ; Overflow = 1 goto Lock_state ; C = 1 -> overflow,within the window ; ------------------------------------------------------------------------ ; Sample counter checking ; ------------------------------------------------------------------------ Sample_counter_checking ; C = 1 -> Outside of window movlw 00Eh ; Read user's set sampling time from movwf USER_EEADR ; EEPROM call EE_read subwf Sample_counter,W btfsc STATUS,Z goto Set_out_of_lock incf Sample_counter,F ; goto end_of_lock ; ------------------------------------------------------------------------ ; Frequency actual is out of lock situation ; ------------------------------------------------------------------------ Set_out_of_lock bcf Status_word,0 ; Clear Lock bit clrf Sample_counter clrf Delay_counter goto end_of_lock Clear_RB0 ; Positive subtraction result act > ref bcf PORTB,0 ; Clear RB0 bsf PORTB,3 ; Set RB3 ; ------------------------------------------------------------------------ decf TEMP,F ; TEMP = LowB - 1 of sub result btfsc STATUS,Z ; Is zero? Means 10 Hz over reference. goto Set_SW_bit7_RB3 decf TEMP,F ; TEMP = LowB - 2 of sub result btfsc STATUS,Z ; Is zero? Means 20 Hz over reference. Set_SW_bit7_RB3 bsf Status_word,5 ; Set bit Freq_within +/- 20 Hz. ; ------------------------------------------------------------------------ movlw 0F6h ; FFFFF6h movwf LED0 movlw 0FFh movwf LED1 movlw 0FFh movwf LED2 ; ------------------------------------------------------------------------ call Add24bit ; Add FFFFF6h for (Freq_act - Freq_ref) btfsc Status_word,4 ; If overflow then out of window goto Sample_counter_checking ; ------------------------------------------------------------------------ ; Frequency is still in locked state!! Great!!! ; ------------------------------------------------------------------------ Lock_state clrf Sample_counter goto end_of_lock Sample1 incf Sample_counter,F end_of_lock ; ------------------------------------------------------------------------ call Offset_check ; Load selected Display offset values ; ------------------------------------------------------------------------ Test_counter_mode movlw 6 ; Test the direct freq EE-parameter movwf USER_EEADR ; It passes RA2, RB1, RB2 functions call EE_read btfsc STATUS,Z ; If 0 then direct frequency mode goto MFEnd ; EE address 06h data value is zero btfsc Status_word,2 ; If Freq_lock enabled, skip direct ; or Display offset alternative func. goto Preparation_1 ; RB2 works now only with freezing ; function when freq lock enabled. btfsc PORTB,E ; If RB2 = 1 then direct frequency goto MFEnd ; ------------------------------------------------------------------------ ; First preparation of registers LED2...0 for MFAdd or MFSub ; ------------------------------------------------------------------------ Preparation_1 movf HigB,W ; Freq act to LED2, LED1 and LED0 movwf LED2 movf MidB,W movwf LED1 movf LowB,W movwf LED0 ; ------------------------------------------------------------------------ btfsc PORTA,E ; If RA2 = 1 then adds the RF ; If RA2 = 0 then subs the RF goto MFAdd SubMF ; ------------------------------------------------------------------------ ; 24 bit subtraction according to Display offset selection ; ------------------------------------------------------------------------ call Sub24bit ; Do the subtraction! ; ------------------------------------------------------------------------ btfsc Status_word,4 ; Is the carry set? (underflow) ; ------------------------------------------------------------------------ ; If subtracted > subtractor --> result = negative. Therefore they must be ; swapped before subtraction. LED6 <-> LED2, LED5 <-> LED1, LED4 <-> LED0. ; Example: IF = 2050 KHz, Received freq = 3500 kHz, Osc. freq = 5550 kHz ; 2050 kHz - 5550 kHz = - 3500, therefore terms must be swapped, because ; 5550 kHz - 2050 kHz = 3500 kHz ; ------------------------------------------------------------------------ goto Save_results call Offset_check ; Restore original values after first ; subtraction movf LED6,W ; Swap the HighB Freq act and Offset movwf TEMP ; TEMP = LED6 movf LED2,W movwf LED6 movf TEMP,W movwf LED2 ; Move TEMP to LED2 movf LED5,W ; Swap the MidB Freq act and Offset movwf TEMP ; TEMP = LED5 movf LED1,W movwf LED5 movf TEMP,W movwf LED1 movf LED4,W ; Swap the LowB Freq act and Offset movwf TEMP ; TEMP = LED4 movf LED0,W movwf LED4 movf TEMP,W movwf LED0 ; ------------------------------------------------------------------------ call Sub24bit ; Subtract again after swapping!! ; ------------------------------------------------------------------------ goto Save_results MFAdd ; ------------------------------------------------------------------------ ; 24 bit addition function according to Display offset selection ; ------------------------------------------------------------------------ call Add24bit ; Do the addition! ; ------------------------------------------------------------------------ Save_results movf LED6,W ; Save results back to registers movwf HigB movf LED5,W movwf MidB movf LED4,W movwf LowB ; ------------------------------------------------------------------------ MFEnd goto Entry ; start new cycle ; ------------------------------------------------------------------------ end