; ------------------------------------------------------------------------
; FILE     : LCD4DIEC.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                                       *
; AUTHOR   : Peter Halicky  OM3CPH & Peter Halicky Jr., OM2PH ex OM2APH  *
; PCB      : Tibor Madarasz OM2ATM                                       *
;--------------------------------------------------------------------------
; 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.
;--------------------------------------------------------------------------
;       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...0F        = (not in use)
;--------------------------------------------------------------------------
; E-Mail: halicky@minv.sk     or om3cph@oe3xbs.aut.eu
;         peto-h@writeme.com  or om2ph@om0pbm.svk.eu
;         
; 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 step 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 <p16c84.inc>

; ------------------------------------------------------------------------

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       025h         ; EEPROM address 
USER_EEDATA equ       026h         ; EEPROM data
EE_ALR_READ equ       027h         ; EEPROM address already read
EE_Fine1    equ       028h         ; EEPROM calibration parameter 1
EE_Fine2    equ       029h         ; EEPROM calibration parameter 2 
Help2       equ       02Ah         ; temporary register
; ------------------------------------------------------------------------
; 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

            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
;------------------------------------------------------------------------
; 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
;------------------------------------------------------------------------
	    movlw      00Fh        ; EE address 00Fh 
            movwf      USER_EEADR  
            call       EE_read   ; Read EEPROM address 0Fh
	    movwf      TEMP      ; If data in EE address 0Fh is not zero, 
            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. 01)
; 0A = Digits    = Number of displayed digits: 0 = 7 digits, 1 = 6 (def. 1)
; 0B...0F        = (not in use)
;--------------------------------------------------------------------------
; 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      015h        ; 07h
            retlw      001h        ; 08h
            retlw      000h        ; 09h 
            retlw      000h        ; 0A   
            retlw      0FFh        ; 0B
            retlw      0FFh        ; 0C
            retlw      0FFh        ; 0D
            retlw      0FFh        ; 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

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      '2'
        call       PutCHAR	   ; Display character

        call    Delay_200ms	   ; Show the text
        call    Delay_200ms        ; at least 7x200ms...
        call    Delay_200ms        ; 
        call    Delay_200ms
        call    Delay_200ms
        call    Delay_200ms
        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
;	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		
;--------------------------------------------------------
        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
        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
            bsf        STATUS,C   ; set C
            subwf      LowB,F     ; LowB - W -> LowB
                                  ; if underflow -> C=0
            btfsc      STATUS,C
            goto       Step1
            bsf        STATUS,C
            movlw      1
            subwf      MidB,F     ; decrement MidB
                                  ; if underflow -> C=0
            btfsc      STATUS,C
            goto       Step1

            bsf        STATUS,C
            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
            bsf        STATUS,C
            subwf      MidB,F     ; MidB - W -> MidB
            btfsc      STATUS,C   ; if underflow -> C=0
            goto       Step2
            bsf        STATUS,C
            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
            bsf        STATUS,C
            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
            bcf        STATUS,C   ; clear C
            addwf      LowB,1     ; W + LowB -> LowB
            btfss      STATUS,C   ; test overflow
            goto       Add2
            bcf        STATUS,C   ; clear C
            movlw      1
            addwf      MidB,F     ; increment MidB
            btfss      STATUS,C
            goto       Add2
            bcf        STATUS,C
            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
            bcf        STATUS,C
            addwf      MidB,1     ; W + MidB -> MidB
            btfss      STATUS,C
            goto       Add3
            bcf        STATUS,C   ; clear C
            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
            bsf        STATUS,C
            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

;-------------------------------------------------------------------------
; 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?
	    bsf        STATUS,Z
	    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
;--------------------------------------------------------------------
; 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 ; 
            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
            bsf        STATUS,Z
            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
;--------------------------------------------------------------------
	    btfsc      PORTB,3     ; If 0 then no 10 divider
            goto       Ten_divider2 ; 
            movlw      5           ; test for decimal point
            goto       Dec_point2
Ten_divider2
            movlw      4           ; test for decimal point
;--------------------------------------------------------------------
Dec_point2
            bsf        STATUS,Z
            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  
            bsf        STATUS,Z    ; test for 8th character
            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

            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

; ------------------------------------------------------------------------
; 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
            bcf        STATUS,Z
            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

	    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      PORTB,E     ; If RB2 = 1 then direct frequency
            goto       MFEnd
            btfsc      PORTA,E     ; If RA2 = 1 then adds the RF
                                   ; If RA2 = 0 then subs the RF
            goto       MFAdd

; ------------------------------------------------------------------------
; First it must be checked which number is larger, than they are flipped
; if needed, than SUBSTRACT SMALLER from LARGER...
; Temporary nonused registers LED0..LED6 are used.
; ------------------------------------------------------------------------

SubMF       movlw      0
	    btfsc      PORTB,1     ; True? Then Mft2
            movlw      3           ; 003h = Mft2_HigB
            movwf      USER_EEADR 
            call       EE_read

            bsf        STATUS,C    ; set C flag
            bcf        STATUS,Z    ; clear Z flag
            subwf      HigB,W      ; HigB - W -> W
            btfss      STATUS,C    ; if negative result (W>HigB)
            goto       Change      ; flip numbers

            btfss      STATUS,Z    ; if result=0 continue
            goto       SetNmbrs    ; else substract

            movlw      1           ; test next byte
	    btfsc      PORTB,1     ; True? Then Mft2
            movlw      4           ; 004h = Mft2_MidB
            movwf      USER_EEADR 
            call       EE_read

            bcf        STATUS,Z    ; clear Z flag
            bsf        STATUS,C    ; set C flag
            subwf      MidB,W      ; MidB - W -> W
            btfss      STATUS,C    ; if negative result (W>MidB)
            goto       Change      ; flip numbers
            btfss      STATUS,Z    ; if ZERO continue
            goto       SetNmbrs    ; else substract

            movlw      2           ; else continue with next byte
	    btfsc      PORTB,1     ; True? Then Mft2
            movlw      5           ; 005h = Mft2_LowB
            movwf      USER_EEADR 
            call       EE_read

            bsf        STATUS,C
            subwf      LowB,W      ; LowB - W -> W
            btfss      STATUS,C    ; if result is negative(W>LowB)
            goto       Change      ; flip numbers
            goto       SetNmbrs    ; else substract

Change      movlw      0           ; prepare substraction MF - F
	    btfsc      PORTB,1     ; True? Then Mft2
            movlw      3           ; 003h = Mft2_HigB
            movwf      USER_EEADR 
            call       EE_read

            movwf      LED0        ; highest byte MF to LED0
            movf       HigB,W
            movwf      LED4        ; highest freq. byte to LED4

            movlw      1
	    btfsc      PORTB,1     ; True? Then Mft2
            movlw      4           ; 004h = Mft2_MidB
            movwf      USER_EEADR 
            call       EE_read

            movwf      LED1        ; middle to LED1
            movf       MidB,W
            movwf      LED5        ; MidB -> LED5

            movlw      2
	    btfsc      PORTB,1     ; True? Then Mft2
            movlw      5           ; 005h = Mft2_LowB
            movwf      USER_EEADR 
            call       EE_read 

            movwf      LED2        ; LowMF -> LED2
            movf       LowB,W
            movwf      LED6        ; LowB -> LED6
            goto       MFSub

SetNmbrs    movlw      0           ; prepare substraction F - MF
	    btfsc      PORTB,1     ; True? Then Mft2
            movlw      3           ; 003h = Mft2_HigB
            movwf      USER_EEADR 
            call       EE_read

            movwf      LED4        ; HighMF -> LED4
            movf       HigB,W
            movwf      LED0        ; HighB -> LED0

            movlw      1
	    btfsc      PORTB,1     ; True? Then Mft2
            movlw      4           ; 004h = Mft2_MidB
            movwf      USER_EEADR 
            call       EE_read

            movwf      LED5        ; MiddleMF -> LED5
            movf       MidB,W
            movwf      LED1        ; MidB -> LED1

            movlw      2
	    btfsc      PORTB,1     ; True? Then Mft2
            movlw      5           ; 005h = Mft2_LowB
            movwf      USER_EEADR 
            call       EE_read

            movwf      LED6        ; LowMF -> LED6
            movf       LowB,W
            movwf      LED2        ; LowB  -> LED2

; ------------------------------------------------------------------------
; Registers are ready, continue with substraction
; ------------------------------------------------------------------------

MFSub       movf       LED6,W
            bsf        STATUS,C    ; set C
            subwf      LED2,F      ; LED2 - LED6 -> LED2

            btfsc      STATUS,C
            goto       S1
            bsf        STATUS,C
            movlw      1
            subwf      LED1,F

            btfsc      STATUS,C
            goto       S1

            bsf        STATUS,C
            movlw      1
            subwf      LED0,F
            btfsc      STATUS,C
            goto       S1


S1          movf       LED5,W
            bsf        STATUS,C
            subwf      LED1,F      ; LED1 - LED5 -> LED1
            btfsc      STATUS,C
            goto       S2
            bsf        STATUS,C
            movlw      1
            subwf      LED0,F      ; decrement LED0
            btfsc      STATUS,C
            goto       S2

S2          movf       LED4,W
            subwf      LED0,F      ; LED0 - LED4 -> LED0

; ----------------------------------------------------------------------
; Substraction is finished, now store result to frequency registers
; ----------------------------------------------------------------------

            movf       LED0,W
            movwf      HigB
            movf       LED1,W
            movwf      MidB
            movf       LED2,W
            movwf      LowB
            goto       Entry

; ----------------------------------------------------------------------
MFAdd
            movlw      2
	    btfsc      PORTB,1     ; True? Then Mft2
            movlw      5           ; 005h = Mft2_LowB
            movwf      USER_EEADR 
            call       EE_read

            bcf        STATUS,C
            addwf      LowB,F
            btfss      STATUS,C
            goto       AddMF2
            bcf        STATUS,C
            movlw      1
            addwf      MidB,F
            btfss      STATUS,C
            goto       AddMF2
            bcf        STATUS,C
            movlw      1
            addwf      HigB,F
            btfss      STATUS,C
            goto       AddMF2

AddMF2
	    movlw      1           ; 001h = Mft1_MidB
	    btfsc      PORTB,1     ; True? Then Mft2
            movlw      4           ; 004h = Mft2_MidB
            movwf      USER_EEADR 
            call       EE_read     ; read from EEPROM

            bcf        STATUS,C
            addwf      MidB,F
            btfss      STATUS,C
            goto       AddMF3
            bcf        STATUS,C
            movlw      1
            addwf      HigB,F
            btfss      STATUS,C
            goto       AddMF3

AddMF3
	    clrw                   ; 000h = Mft1_HigB
	    btfsc      PORTB,1     ; True? Then Mft2
            movlw      3           ; 003h = Mft2_HigB
            movwf      USER_EEADR 
            call       EE_read
            addwf      HigB,F
MFEnd
            goto       Entry       ;  start new cycle

; ------------------------------------------------------------------------

            end
