;CAPMET790.ASM 09MAY05 - COPYRIGHT JOHN BECKER - EPE IND/CAP/FREQ METER V2
;PIC16F628, 3.2768MHz, WDT OFF, POR ON, XTAL XS
;Config register bits
; CP1 CP0 CP1 CP0 NIL CPD LVP BOR MCL OS2 POR WDT OS1 OS0
;  1   1   1   1   1   1   0   0   1   0   0   0   0   1
;N.B. Logic 1/0 do NOT necessarily mean that the function is On/Off
;respectively - refer to PIC '627/8 data sheet

#DEFINE BANK0 BCF 03H,5
#DEFINE BANK1 BSF 03H,5

        List P=PIC16F628, R=DEC; 
       	#INCLUDE "P16F628.INC"
		__CONFIG   h'3F21'

        CBLOCK		0x0C
REGA0				;lsb
REGA1
REGA2
REGA3				;msb

REGB0				;lsb
REGB1
REGB2
REGB3				;msb

REGC0				;lsb
REGC1
REGC2
REGC3				;msb

DSIGN				;Digit Sign. 0=positive,FF(or non zero)=negative
DIGIT1				;MSD
DIGIT2
DIGIT3
DIGIT4
DIGIT5				;Decimal digits
DIGIT6
DIGIT7
DIGIT8
DIGIT9
DIGIT10				;LSD
MTEMP
MCOUNT
DCOUNT

LOOP
LOOPA
RSLINE
STORE
SLOWIT
POINT
TIMEMSB
OVERFLOW
STORE2
LARGE
NANO
CAPREF3
CAPREF2
CAPREF1
CAPREF0
INDREF3
INDREF2
INDREF1
INDREF0
TIMEOUT
SWITCH
ZERO
INDCORRECT
CAPCORRECT
CORRECTLOC

        ENDC

PROMVAL  EQU 	70H   ; accessed via both BANKS

               ; locations up to $7F are available

; **************

        ORG 	0
        goto 	GIEOFF
        ORG 	4          ; Interrupt vector address
        goto 	GIEOFF
        ORG 	5          ; Start of program memory

GIEOFF: BCF 	INTCON,GIE  ; turn off global interrupts
        BTFSC 	INTCON,GIE
        goto 	GIEOFF
        goto 	START

TABLCD: addwf 	PCL,F     ;LCD initialisation table
        retlw 	B'00110011' ;initialise lcd - first byte
        retlw 	B'00110011' ;2nd byte (repeat of first)
        retlw 	B'00110010' ;set for 4-bit operation
        retlw 	B'00101100' ;set for 2 lines
        retlw 	B'00000110' ;set entry mode to increment each address
        retlw 	B'00001100' ;set display on, cursor off, blink off
        retlw 	B'00000001' ;clear display
        retlw 	B'00000010' ;return home, cursor & RAM to zero
                        ;end inititalisation table

LCDTITLE: addwf PCL,F
        retlw ' '
        retlw 'E'
        retlw 'P'
        retlw 'E'
        retlw ' '
        retlw 'L'
        retlw 'C'
        retlw 'F'
        retlw ' '
        retlw 'M'
        retlw 'E'
        retlw 'T'
        retlw 'E'
        retlw 'R'
        retlw ' '
        retlw ' '
        retlw ' '

TITLEB: addwf PCL,F
        retlw ' '
        retlw 'W'
        retlw 'A'
        retlw 'I'
        retlw 'T'
        retlw 'I'
        retlw 'N'
        retlw 'G'
        retlw ' '
        retlw 'T'
        retlw 'I'
        retlw 'M'
        retlw 'I'
        retlw 'N'
        retlw 'G'
        retlw ' '


OVERFLOWED:  addwf PCL,F
        retlw 'O'
        retlw 'V'
        retlw 'E'
        retlw 'R'
        retlw 'F'
        retlw 'L'
        retlw 'O'
        retlw 'W'

CALIB:  addwf PCL,F
        retlw ' '
        retlw ' '
        retlw ' '
        retlw ' '
        retlw ' '
        retlw ' '
        retlw 'N'
        retlw 'U'
        retlw 'L'
        retlw 'L'
        retlw 'E'
        retlw 'D'
        retlw ' '
        retlw ' '
        retlw ' '
        retlw ' '

TIMEDOUT: addwf PCL,F
        retlw ' '
        retlw ' '
        retlw ' '
        retlw ' '
        retlw 'T'
        retlw 'I'
        retlw 'M'
        retlw 'E'
        retlw ' '
        retlw 'O'
        retlw 'U'
        retlw 'T'
        retlw ' '
        retlw ' '
        retlw ' '
        retlw ' '

CAPTIME: addwf PCL,F
        retlw ' '
        retlw ' '
        retlw ' '
        retlw 'C'
        retlw 'A'
        retlw 'P'
        retlw 'A'
        retlw 'C'
        retlw 'I'
        retlw 'T'
        retlw 'O'
        retlw 'R'
        retlw ' '
        retlw ' '
        retlw ' '
        retlw ' '

INDTIME: addwf PCL,F
        retlw ' '
        retlw ' '
        retlw ' '
        retlw ' '
        retlw 'I'
        retlw 'N'
        retlw 'D'
        retlw 'U'
        retlw 'C'
        retlw 'T'
        retlw 'O'
        retlw 'R'
        retlw ' '
        retlw ' '
        retlw ' '
        retlw ' '


CORRECTMSG: addwf PCL,F
        retlw ' '
        retlw 'C'
        retlw 'O'
        retlw 'R'
        retlw 'R'
        retlw 'E'
        retlw 'C'
        retlw 'T'
        retlw 'I'
        retlw 'O'
        retlw 'N'
        retlw ' '
        retlw ' '
        retlw ' '
        retlw ' '
        retlw ' '


;*******************

START:  clrf 	PORTA
        clrf 	PORTB
        movlw 	07H
        movwf 	CMCON

        BANK1
        movlw 	B'11000000'
        movwf 	TRISB
        movlw 	B'00011100'     ; RA0,RA1 as output
        movwf 	TRISA
        movlw 	B'10000110'     ; timer 1:128, pull-ups off
        movwf 	OPTION_REG
        BANK0

        clrf 	INTCON
        call 	PAUSIT
        call 	LCDSET
        call 	PAUSIT

        movlw 	B'00000000'     ; T1 ext osc disable (bit3=0), T1 stopped (bit0=0), internal clock (bit1=0), bit2 dont care
        movwf 	T1CON

        btfsc 	PORTA,2       ; is S3 (RA2) pressed?
        goto 	CORRECTIT

        call 	LCD1
        bsf 	RSLINE,4

        clrf 	LOOP
TITLE2: movf 	LOOP,W
        call 	LCDTITLE
        call 	LCDOUT
        incf 	LOOP,F
        btfss 	LOOP,4
        goto 	TITLE2

        clrf 	INTCON
        clrf 	POINT
        clrf 	CAPREF3
        clrf 	CAPREF2
        clrf 	CAPREF1
        clrf 	CAPREF0
        clrf 	INDREF3
        clrf 	INDREF2
        clrf 	INDREF1
        clrf 	INDREF0

        movlw 	0
        call 	PRMGET
        movwf 	INDCORRECT
        movlw 	1
        call 	PRMGET
        movwf 	CAPCORRECT

        call 	PAUSIT         ; delay
        call 	PAUSIT         ; delay

        clrf 	INTCON
        movlw 	255
        movwf 	SWITCH

;****************** START OF MAIN

MAIN:   clrf 	TIMEOUT
        movf 	PORTA,W
        andlw 	B'00010000'
        xorwf 	SWITCH,W
        btfsc 	STATUS,Z
        goto 	MAIN2

        movf 	PORTA,W
        andlw 	B'00010000'
        movwf 	SWITCH

        call 	LCD21
        bsf 	RSLINE,4
        clrf 	LOOP
TITLE3: movf 	LOOP,W
        call 	TITLEB
        call 	LCDOUT
        incf 	LOOP,F
        btfss 	LOOP,4
        goto 	TITLE3

        call 	LCD1
        bsf 	RSLINE,4
        clrf 	LOOP
        btfsc 	PORTA,4
        goto 	TIMOUT4

MAIN3:  movf 	LOOP,W
        call 	CAPTIME
        call 	LCDOUT
        incf 	LOOP,F
        btfss 	LOOP,4
        goto 	MAIN3
        goto 	MAIN2

MAIN4:  movf 	LOOP,W
        call 	INDTIME
        call 	LCDOUT
        incf 	LOOP,F
        btfss 	LOOP,4
        goto 	TIMOUT4
        goto 	MAIN4

MAIN2:  btfsc 	SWITCH,4
        goto 	INDUCT
        goto 	CAPACITOR

; *****************

; QBASIC ROUTINE ILLUSTRATING INDUCTANCE FORMULA

;CLS
;DEFDBL A-Z
;PRINT "Formula:  L = ((1000000000 / (2 * PI * F) ^ 2)) / C"
;PRINT

;PI = 22 / 7
;F = 389305: PRINT "Frequency = "; F
;C = 200: C = (C * C) / (C + C): PRINT "Capacitance = "; C

;Process:
;L = F * 44: PRINT L
;L = INT(L / 7): PRINT L
;L = INT(1000000000 / L): PRINT L
;L = L * L: PRINT L
;L = INT(L / 10):
;L = L / 1000
;PRINT "Inductance = "; L; "uH"

; **************

INDUCT: movlw 	B'00000001'     ; set for correct osc
        movwf 	PORTA

        call 	INDTIMER       ; get osc frequency
        call 	COPY_TIME_REGA

        clrf 	POINT
        clrf 	LARGE

        call 	LCD1           ; set address    ; orig ****
        bsf 	RSLINE,4        ; set RS for data send
        call 	BIN2DEC
        call 	SHOWITALL
        movlw 	'H'
        call 	LCDOUT
        movlw 	'z'
        call 	LCDOUT
        movlw 	' '
        call 	LCDOUT
        movlw 	' '
        call 	LCDOUT

        movf 	TMR1H,W
        andlw 	B'11110000'     ; was %11000000 - changed 01MAR04
        iorwf 	TIMEMSB,W     ; is timing value less than 4096 ?

        btfsc 	STATUS,Z
        call 	LARGEVALUE     ; yes

        btfsc 	TIMEOUT,0
        goto 	TIMEEND

        call 	COPY_TIME_REGA

        movlw 	44            ; multiply freq x 44 (22 x 2) (2 x PI = 44/7)
        call 	MULTIPLYSMALL  ; REGA * 44 -> REGA        
        movf 	STATUS,W
        andlw 	1
        movwf 	OVERFLOW

        movlw 	'K'
        movf 	OVERFLOW,F
        btfss 	STATUS,Z
        goto 	SHOWOVERFLOW

        movlw 	7             ; divide by 7
        call 	DIVIDESMALL    ; REGA / 7 -> REGA
        movf 	STATUS,W
        andlw 	1
        movwf 	OVERFLOW

        movlw 	'L'
        movf 	OVERFLOW,F
        btfss 	STATUS,Z
        goto 	SHOWOVERFLOW

        call 	COPY_REGA_REGB ; copy answer into REGB
        call 	DIVIDEBILLION  ; 1,000,000,000 / REGB -> REGA
        movf 	STATUS,W
        andlw 	1
        movwf 	OVERFLOW

        movlw 	'J'
        movf 	OVERFLOW,F
        btfss 	STATUS,Z
        goto 	SHOWOVERFLOW

        call 	COPY_REGA_REGB ; copy answer into REGB
        call 	MULTIPLY       ; REGA * REGB -> REGA (squaring REGA)
        movf 	STATUS,W
        andlw 	1
        movwf 	OVERFLOW

        movlw 	'2'
        movf 	OVERFLOW,F
        btfss 	STATUS,Z
        goto 	SHOWOVERFLOW

        movlw 	100            ; divide by 10   **** 10
        call 	DIVIDESMALL    ; REGA / 100 -> REGA
        movf 	STATUS,W
        andlw 	1
        movwf 	OVERFLOW

        movlw 	'C'
        movf 	OVERFLOW,F
        btfss 	STATUS,Z
        goto 	SHOWOVERFLOW

        movf 	INDCORRECT,W   ; multiply by correction factor
        call 	MULTIPLYSMALL  ; REGA * REGB -> REGA
        movf 	STATUS,W
        andlw 	1
        movwf 	OVERFLOW

        movlw 	'A'
        movf 	OVERFLOW,F
        btfss 	STATUS,Z
        goto 	SHOWOVERFLOW

        movlw 	10            ; divide by 10    ***** 100  01MAR04
        call 	DIVIDESMALL    ; REGA / 100 -> REGA
        movf 	STATUS,W
        andlw 	1
        movwf 	OVERFLOW

        movlw 	'B'
        movf 	OVERFLOW,F
        btfss 	STATUS,Z
        goto 	SHOWOVERFLOW

        btfsc 	PORTA,2       ; is S3 (RA2) pressed?
        call 	CALIBIND

        movf 	LARGE,F
        btfsc 	STATUS,Z
        call 	SUBTRACTINDREF

        movlw 	4
        movwf 	POINT

        call 	LCD21          ; set address
        bsf 	RSLINE,4        ; set RS for data send

        call 	BIN2DEC        ; converts binary in REGA to decimal in DIGIT

        movf 	LARGE,F
        btfsc 	STATUS,Z
        call 	CHECKMILLI

        call 	SHOWITALL

        movf 	LARGE,F
        btfss 	STATUS,Z
        goto 	IND2

        movlw 	'u'
        movf 	NANO,F
        btfss 	STATUS,Z
        movlw 	'm'
        call 	LCDOUT
        goto 	IND3
IND2:   call 	LCD29 
        bsf 	RSLINE,4        ; set RS for data send
IND3:   movlw 	'H'
        call 	LCDOUT
        movlw 	' '
        call 	LCDOUT
        movlw 	' '
        call 	LCDOUT
        movlw 	' '
        call 	LCDOUT
        movlw 	' '
        call 	LCDOUT
        movlw 	' '
        call 	LCDOUT
        movlw 	' '
        call 	LCDOUT

        goto 	MAIN

; ***************

CAPACITOR: movlw B'00000010'  ; set for correct osc
        movwf 	PORTA

        clrf 	TIMEMSB
        call 	INDTIMER

        call 	COPY_TIME_REGA

        clrf 	POINT
        clrf 	LARGE

        movf 	TMR1H,W
        andlw 	B'11111110'
        iorwf 	TIMEMSB,W     ; is timing value less than 512?
        btfsc 	STATUS,Z
        call 	LARGEVALUE     ; yes

        btfsc 	ZERO,0
        goto 	TIMEEND

        call 	LCD1           ; set address
        bsf 	RSLINE,4        ; set RS for data send
        call 	BIN2DEC
        call 	SHOWITALL
        movlw 	'H'
        call 	LCDOUT
        movlw 	'z'
        call 	LCDOUT
        movlw 	' '
        call 	LCDOUT
        movlw 	' '
        call 	LCDOUT

        call 	COPY_TIME_REGA

        movlw 	22             ; multiply freq x PI (R = 1k) (ignoring 3 zeros)
        call 	MULTIPLYSMALL
        movlw 	7
        call 	DIVIDESMALL

        call 	COPY_REGA_REGB ; copy answer into REGB
        call 	DIVIDEBILLION  ; REGA / REGB -> REGA

        movf 	CAPCORRECT,W   ; multiply by correction factor
        call 	MULTIPLYSMALL  ; REGA / REGB -> REGA
        movlw 	100           ; divide by 100
        call 	DIVIDESMALL    ; REGA / 100 -> REGA

        btfsc 	PORTA,2       ; is S3 (RA2) pressed?
        call 	CALIBCAP

        movf 	LARGE,F
        btfsc 	STATUS,Z
        call 	SUBTRACTCAPREF

        call 	LCD21          ; set address
        bsf 	RSLINE,4        ; set RS for data send
        call 	BIN2DEC
        call 	CHECKNANO

        call 	SHOWITALL

        movlw 	'u'
        movf 	LARGE,F
        btfss 	STATUS,Z
        goto 	CAP2

        movlw 	'n'
        movf 	NANO,F
        btfsc 	STATUS,Z
        movlw 	'p'
CAP2:   call 	LCDOUT
        movlw 	'F'
        call 	LCDOUT
        movlw 	' '
        call 	LCDOUT
        movlw 	' '
        call 	LCDOUT
        movlw 	' '
        call 	LCDOUT
        movlw 	' '
        goto 	MAIN

; **************

LARGEVALUE:
        clrf 	TIMEOUT
        incf 	LARGE,F
        movlw 	B'00000000'     ; stop timer 1
        movwf 	T1CON
        clrf 	TMR1L          ; reset timer 1
        clrf 	TMR1H
        bcf 	PIR1,0          ; clear timer rollover flag

        movf 	PORTB,W        ; get current status of RB6
        andlw 	B'01000000'
        movwf 	STORE         ; store it

        clrf 	SLOWIT
        bsf 	T1CON,0         ; start timer 1

WAITB1:
        movf 	PORTA,W
        andlw 	B'00010000'
        xorwf 	SWITCH,W
        btfss 	STATUS,Z
        return

WAITB2: movf 	PORTB,W        ; get current status of RB6
        andlw 	B'01000000'
        movwf 	STORE2        ; temp store it

        xorwf 	STORE,W       ; compare with prev val of RB6
        btfsc 	STATUS,Z      ; is it equal?
        goto 	WAITB1         ; yes
        movf 	STORE2,W       ; no, different, so store val
        movwf 	STORE

        call 	OSCILLATE      ; get timing between two changes of RB6 (1 full cycle)
        btfsc 	TIMEOUT,0
        return

        call 	COPY_TIME_REGA

        movlw 	122
        call 	MULTIPLYSMALL  ; REGA * 122 -> REGA multiply freq x 122 to get time re 3.2768MHz xtal (1000000/819200 =1.22)

        movlw 	100           ; divide by 100
        call 	DIVIDESMALL    ; REGA / 100 -> REGA

        call 	COPY_REGA_REGB ; copy answer into REGB
        call 	DIVIDEBILLION  ; 1,000,000,000 / REGB -> REGA 

        movf 	REGA0,W        ; copy answer back into TIMER
        movwf 	TMR1L
        movf 	REGA1,W
        movwf 	TMR1H
        movf 	REGA2,W
        movwf 	TIMEMSB
        movlw 	4
        movwf 	POINT
        return

; ***********

CHECKNANO: clrf NANO
        movf 	DIGIT1,W
        iorwf 	DIGIT2,W
        iorwf 	DIGIT3,W
        iorwf 	DIGIT4,W
        iorwf 	DIGIT5,W
        iorwf 	DIGIT6,W
        andlw 	B'00001111'
        btfsc 	STATUS,Z
        return
        bsf 	NANO,0
        movlw 	4
        movwf 	POINT
        return

; ***********

CHECKMILLI: clrf NANO
        movf 	DIGIT1,W
        iorwf 	DIGIT2,W
        iorwf 	DIGIT3,W
        iorwf 	DIGIT4,W
        iorwf 	DIGIT5,W
        andlw 	B'00001111'
        btfsc 	STATUS,Z
        return
        bsf 	NANO,0
        movlw 	7
        movwf 	POINT
        return

; *************

CALIBCAP: movf 	REGA0,W
        movwf 	CAPREF0
        movf 	REGA1,W
        movwf 	CAPREF1
        movf 	REGA2,W
        movwf 	CAPREF2
        movf 	REGA3,W
        movwf 	CAPREF3
        call 	SHOWCALIB
        return

CALIBIND: movf 	REGA0,W
        movwf 	INDREF0
        movf 	REGA1,W
        movwf 	INDREF1
        movf 	REGA2,W
        movwf 	INDREF2
        movf 	REGA3,W
        movwf 	INDREF3
        call 	SHOWCALIB
        return

; **************

SHOWCALIB: call LCD1
        bsf 	RSLINE,4

        clrf 	LOOP
CALIB2: movf 	LOOP,W
        call 	CALIB
        call 	LCDOUT
        incf 	LOOP,F
        btfss 	LOOP,4
        goto 	CALIB2
        call 	PAUSIT
        return

; **************

SUBTRACTCAPREF: ; subtract ref from current val
                ; REGA - REGB -> REGA ;Return carry set if overflow
        movf 	CAPREF3,W
        movwf 	REGB3
        movf 	CAPREF2,W
        movwf 	REGB2
        movf 	CAPREF1,W
        movwf 	REGB1
        movf 	CAPREF0,W
        movwf 	REGB0
        call 	SUBTRACT
        movf 	STATUS,W
        andlw 	1
        movwf 	OVERFLOW
        return

SUBTRACTINDREF: ; subtract ref from current val
                ; REGA - REGB -> REGA ;Return carry set if overflow
        movf 	INDREF3,W
        movwf 	REGB3
        movf 	INDREF2,W
        movwf 	REGB2
        movf 	INDREF1,W
        movwf 	REGB1
        movf 	INDREF0,W
        movwf 	REGB0
        call 	SUBTRACT
        movf 	STATUS,W
        andlw 	1
        movwf 	OVERFLOW
        return

; **************

INDTIMER: movlw B'00000110'   ; T1 ext osc sync off (bit 2) timer1 off
        movwf 	T1CON         ; uses T1 ext clock input via RB6 and measures
                            ; number of clock pulses during 25 cycles of TMR0
        BANK1
        movlw 	B'10000110'     ; timer 1:128, pullups off
        movwf 	OPTION_REG
        BANK0

        clrf 	TMR1L          ; reset timer 1
        clrf 	TMR1H
        clrf 	TIMEMSB
        bcf 	PIR1,0          ; clr timer rollover flag

        movlw 	B'00000111'     ; T1 ext osc sync off (bit 2) timer1 on
        movwf 	T1CON

        movlw 	25            
        movwf 	SLOWIT
        clrf 	TMR0
        bcf 	INTCON,2
TIMEIT: btfss 	PIR1,0        ; has timer 1 overflowed?
        goto 	TIMIT2
        bcf 	PIR1,0
        incf 	TIMEMSB,F
TIMIT2: btfss 	INTCON,2      ; has timer 0 overflowed?
        goto 	TIMEIT
        bcf 	INTCON,2
        decfsz 	SLOWIT,F
        goto 	TIMEIT

        movlw 	B'00000000'
        movwf 	T1CON
        return

; ****************

OSCILLATE:   clrf ZERO
        clrf 	T1CON
        clrf 	TMR1H
        clrf 	TMR1L
        bcf 	PIR1,0
        bsf 	T1CON,0         ; start timer 1

        clrf 	TIMEMSB
        bsf 	T1CON,0         ; start timer 1
OSCA1:
        movf 	PORTA,W
        andlw 	B'00010000'
        xorwf 	SWITCH,W
        btfss 	STATUS,Z
        return

        btfsc 	PIR1,0        ; has timer 1 overflowed?
        call 	INCMSB         ; yes

OSCA1A: movf 	PORTB,W        ; is RB6 same as before?
        andlw 	B'01000000'
        movwf 	STORE2
        xorwf 	STORE,W
        btfsc 	STATUS,Z
        goto 	OSCA1          ; yes
        movf 	STORE2,W       ; no, so continue for next cycle
        movwf 	STORE

OSCA2:
        movf 	PORTA,W
        andlw 	B'00010000'
        xorwf 	SWITCH,W
        btfss 	STATUS,Z
        return

        btfsc 	PIR1,0        ; has timer 1 overflowed?
        call 	INCMSB         ; yes

OSCA2A: movf 	PORTB,W        ; is RB6 same as before?
        andlw 	B'01000000'
        movwf 	STORE2
        xorwf 	STORE,W
        btfsc 	STATUS,Z
        goto 	OSCA2          ; yes
        movlw 	B'00000000'     ; no, stop timer 1
        movwf 	T1CON
        return

INCMSB: incf 	TIMEMSB,F
        decf 	SLOWIT,F
        bcf 	PIR1,0
        clrf 	TMR1H
        clrf 	TMR1L
        movf 	SLOWIT,F
        btfsc 	STATUS,Z
        bsf 	ZERO,0
        return

;******** LCD ROUTINES **********

LCD1:   movlw 	B'10000000'
        goto 	LCDLIN
LCD5:   movlw 	B'10000101'
        goto 	LCDLIN
LCD6:   movlw 	B'10000110'
        goto 	LCDLIN
LCD8:   movlw 	B'10001000'
        goto 	LCDLIN
LCD9:   movlw 	B'10001001'
        goto 	LCDLIN
LCD13:  movlw 	B'10001101'
        goto 	LCDLIN
LCD15:  movlw 	B'10001111'
        goto 	LCDLIN

LCD21:  movlw 	B'11000000'
        goto 	LCDLIN
LCD25:  movlw 	B'11000101'
        goto 	LCDLIN
LCD26:  movlw 	B'11000110'
        goto 	LCDLIN
LCD28:  movlw 	B'11001000'
        goto 	LCDLIN
LCD29:  movlw 	B'11001001'

LCDLIN: BCF 	RSLINE,4

LCDOUT: movwf 	STORE
        movlw 	50
        movwf 	LOOPA
DELAYIT: decfsz LOOPA,F
        goto 	DELAYIT
        call 	SENDIT

SENDIT: swapf 	STORE,F
        movf 	STORE,W
        andlw 	15
        iorwf 	RSLINE,W
        movwf 	PORTB
        BSF 	PORTB,5
        nop 
        nop
        BCF 	PORTB,5
        RETURN

; *************

PAUSIT: movlw 	25
        movwf 	SLOWIT
        bcf 	INTCON,2
PAUSE:  btfss 	INTCON,2
        goto 	PAUSE
        bcf 	INTCON,2
        decfsz 	SLOWIT,F
        goto 	PAUSE
        return

PAUSIT2: clrf TMR0
        movlw 10
        movwf SLOWIT
        bcf INTCON,2
PAUSE2: btfss INTCON,2
        goto PAUSE2
        bcf INTCON,2
        decfsz SLOWIT,F
        goto PAUSE2
        return

;..............

LCDSET: clrf LOOP       ;clr LCD set-up loop
        clrf RSLINE     ;clear RS line for instruction send
LCDST2: movf LOOP,W     ;get table address
        call TABLCD     ;get set-up instruction
        call LCDOUT     ;perform it
        incf LOOP,F     ;inc loop
        btfss LOOP,3    ;has last LCD set-up instruction now been done?
        goto LCDST2     ;no
        return


CLRLINE1: call LCD1     ;set address for line 1 cell 1
        bsf RSLINE,4    ;set RS for data send
        clrf LOOP       ;
CLRL1:  movlw ' '       ;clear cell
        call LCDOUT     ;
        incf LOOP,F     ;inc loop
        btfss LOOP,4    ;has last LCD letter been sent?
        goto CLRL1      ;no
        return

CLRLINE2: call LCD21
        bsf RSLINE,4
        movlw 16
        movwf LOOP
CL2:    movlw ' '
        call LCDOUT
        decfsz LOOP,F
        goto CL2
        return

; ***********

SHOWITALL:
        movlw DIGIT1
        movwf FSR
        movlw 10
        movwf LOOP
SHOW2:  movf INDF,W
        call LCDOUT
        movf LOOP,W
        xorwf POINT,W
        btfss STATUS,Z
        goto SHOW3
        movlw '.'
        call LCDOUT
SHOW3:  incf FSR,F
        decfsz LOOP,F
        goto SHOW2
        return

; ***********

COPY_TIME_REGA:
        movf TIMEMSB,W
        movwf REGA2
        movf TMR1H,W
        movwf REGA1
        movf TMR1L,W
        movwf REGA0
        clrf REGA3
        return

; *********

MULTIPLYSMALL:
        movwf REGB0
        clrf REGB1
        clrf REGB2
        clrf REGB3
        call MULTIPLY
        movf STATUS,W
        andlw 1
        movwf OVERFLOW
        return

; *************

DIVIDESMALL:
        movwf REGB0
        clrf REGB1
        clrf REGB2
        clrf REGB3
        call DIVIDE
        movf STATUS,W
        andlw 1
        movwf OVERFLOW
        return

; ***********

DIVIDEBILLION:
        movlw 3BH      ; divide 1,000,000,000 ($3B9ACA00) by the answer
        movwf REGA3
        movlw 9AH
        movwf REGA2
        movlw 0CAH
        movwf REGA1
        movlw 00H
        movwf REGA0
        call DIVIDE
        movf STATUS,W
        andlw 1
        movwf OVERFLOW
        return

; ***********

COPY_REGA_REGB:
        movf REGA0,W    
        movwf REGB0
        movf REGA1,W
        movwf REGB1
        movf REGA2,W
        movwf REGB2
        movf REGA3,W
        movwf REGB3
        return

; *********** PETER HEMSLEY'S 32-BIT MATHS ROUTINES *******

;*** SIGNED MULTIPLY ***
;REGA * REGB -> REGA
;Return carry set if overflow

multiply
	clrf	MTEMP		;Reset sign flag
	call	chksgna		;Make REGA positive
	skpc
	call	chksgnb		;Make REGB positive
	skpnc
	return			;Overflow

	call	movac		;Move REGA to REGC
	call	clra		;Clear product

	movlw	D'31'		;Loop counter
	movwf	MCOUNT

muloop	call	slac		;Shift left product and multiplicand
	
	rlf	REGC3,w		;Test MSB of multiplicand
	skpnc			;If multiplicand bit is a 1 then
	call	addba		;add multiplier to product

	skpc			;Check for overflow
	rlf	REGA3,w
	skpnc
	return

	decfsz	MCOUNT,f	;Next
	goto	muloop

	btfsc	MTEMP,0		;Check result sign
	call	negatea		;Negative



	return


; *************

;*** SIGNED DIVIDE ***
;REGA / REGB -> REGA
;Remainder in REGC
;Return carry set if overflow or division by zero

divide	clrf	MTEMP		;Reset sign flag
	movf	REGB0,w		;Trap division by zero
	iorwf	REGB1,w
	iorwf	REGB2,w
	iorwf	REGB3,w
	sublw	0
	skpc
	call	chksgna		;Make dividend (REGA) positive
	skpc
	call	chksgnb		;Make divisor (REGB) positive
	skpnc
	return			;Overflow

	clrf	REGC0		;Clear remainder
	clrf	REGC1
	clrf	REGC2
	clrf	REGC3

	movlw	D'32'		;Loop counter
	movwf	MCOUNT

dvloop	call	slac		;Shift dividend (REGA) msb into remainder (REGC)

	movf	REGB3,w		;Test if remainder (REGC) >= divisor (REGB)
	subwf	REGC3,w
	skpz
	goto	dtstgt
	movf	REGB2,w
	subwf	REGC2,w
	skpz
	goto	dtstgt
	movf	REGB1,w
	subwf	REGC1,w
	skpz
	goto	dtstgt
	movf	REGB0,w
	subwf	REGC0,w
dtstgt	skpc			;Carry set if remainder >= divisor
	goto	dremlt

	movf	REGB0,w		;Subtract divisor (REGB) from remainder (REGC)
	subwf	REGC0,f
	movf	REGB1,w
	skpc
	incfsz	REGB1,w
	subwf	REGC1,f
	movf	REGB2,w
	skpc
	incfsz	REGB2,w
	subwf	REGC2,f
	movf	REGB3,w
	skpc
	incfsz	REGB3,w
	subwf	REGC3,f
	clrc
	bsf	REGA0,0		;Set quotient bit

dremlt	decfsz	MCOUNT,f	;Next
	goto	dvloop

	btfsc	MTEMP,0		;Check result sign
	call	negatea		;Negative
	return

;*** SQUARE ROOT ***
;sqrt(REGA) -> REGA
;Return carry set if negative

sqrt	rlf	REGA3,w		;Trap negative values
	skpnc
	return

	call	movac		;Move REGA to REGC
	call	clrba		;Clear remainder (REGB) and root (REGA)

	movlw	D'16'		;Loop counter
	movwf	MCOUNT

sqloop	rlf	REGC0,f		;Shift two msb's
	rlf	REGC1,f		;into remainder
	rlf	REGC2,f
	rlf	REGC3,f
	rlf	REGB0,f
	rlf	REGB1,f
	rlf	REGB2,f
	rlf	REGC0,f
	rlf	REGC1,f
	rlf	REGC2,f
	rlf	REGC3,f
	rlf	REGB0,f
	rlf	REGB1,f
	rlf	REGB2,f

	setc			;Add 1 to root
	rlf	REGA0,f		;Align root
	rlf	REGA1,f
	rlf	REGA2,f

	movf	REGA2,w		;Test if remdr (REGB) >= root (REGA)
	subwf	REGB2,w
	skpz
	goto	ststgt
	movf	REGA1,w
	subwf	REGB1,w
	skpz
	goto	ststgt
	movf	REGA0,w
	subwf	REGB0,w
ststgt	skpc			;Carry set if remdr >= root
	goto	sremlt

	movf	REGA0,w		;Subtract root (REGA) from remdr (REGB)
	subwf	REGB0,f
	movf	REGA1,w
	skpc
	incfsz	REGA1,w
	subwf	REGB1,f
	movf	REGA2,w
	skpc
	incfsz	REGA2,w
	subwf	REGB2,f
	bsf	REGA0,1		;Set current root bit

sremlt	bcf	REGA0,0		;Clear test bit
	decfsz	MCOUNT,f	;Next
	goto	sqloop

	clrc
	rrf	REGA2,f		;Adjust root alignment
	rrf	REGA1,f
	rrf	REGA0,f
	return


;*** SIGNED BINARY TO DECIMAL ***
;REGA -> DIGITS 1 (MSD) TO 10 (LSD) & DSIGN
;DSIGN = 0 if REGA is positive, FF if negative
;Return carry set if overflow
;Uses FSR register

bin2dec
        call    clrdig          ;Clear all digits
        clrf    MTEMP           ;Reset sign flag
	call	chksgna		;Make REGA positive
	skpnc
        goto BLANKIT            ;Overflow

	movlw	D'32'		;Loop counter
	movwf	MCOUNT

b2dloop	rlf	REGA0,f		;Shift msb into carry
	rlf	REGA1,f
	rlf	REGA2,f
	rlf	REGA3,f

	movlw	DIGIT10
	movwf	FSR		;Pointer to digits
	movlw	D'10'		;10 digits to do
	movwf	DCOUNT

adjlp	rlf	INDF,f		;Shift digit and carry 1 bit left
        movlw   -D'10'
	addwf	INDF,w		;Check and adjust for decimal overflow
	skpnc
	movwf	INDF

	decf	FSR,f		;Next digit
	decfsz	DCOUNT,f
	goto	adjlp

	decfsz	MCOUNT,f	;Next bit
	goto	b2dloop

	btfsc	MTEMP,0		;Check sign
	comf	DSIGN,f		;Negative
	clrc

BLANKIT: movlw 48
        iorwf DIGIT1,F
        iorwf DIGIT2,F
        iorwf DIGIT3,F
        iorwf DIGIT4,F
        iorwf DIGIT5,F
        iorwf DIGIT6,F
        iorwf DIGIT7,F
        iorwf DIGIT8,F
        iorwf DIGIT9,F
        iorwf DIGIT10,F

        movlw 10          ; blank leading zeros
        movwf LOOP
        movlw DIGIT1
        movwf FSR
BLANK:  movf LOOP,W
        xorwf POINT,W
        btfsc STATUS,Z
        return
        movf INDF,W
        andlw 15
        btfss STATUS,Z
        return
        bcf INDF,4
        incf FSR,F
        decfsz LOOP,F
        goto BLANK
        movlw 48
        iorwf DIGIT10,F
        return

; **************

;Check sign of REGA and convert negative to positive
;Used by multiply, divide, bin2dec

chksgna	rlf	REGA3,w
	skpc
	return			;Positive

;Negate REGA
;Used by chksgna, multiply, divide, mod, bin2dec, dec2bin

negatea	movf	REGA3,w		;Save sign in w
	andlw	0x80

	comf	REGA0,f		;2's complement
	comf	REGA1,f
	comf	REGA2,f
	comf	REGA3,f
	incfsz	REGA0,f
	goto	nega1
	incfsz	REGA1,f
	goto	nega1
	incfsz	REGA2,f
	goto	nega1
	incf	REGA3,f
nega1
	incf	MTEMP,f		;flip sign flag
	addwf	REGA3,w		;Return carry set if -2147483648
	return

;Set all digits to 0
;Used by bin2dec

clrdig	clrf	DSIGN
	clrf	DIGIT1
	clrf	DIGIT2
	clrf	DIGIT3
	clrf	DIGIT4
	clrf	DIGIT5
	clrf	DIGIT6
	clrf	DIGIT7
	clrf	DIGIT8
	clrf	DIGIT9
	clrf	DIGIT10
	return

;Shift left REGA and REGC
;Used by multiply, divide

slac	rlf	REGA0,f
	rlf	REGA1,f
	rlf	REGA2,f
	rlf	REGA3,f
	rlf	REGC0,f
	rlf	REGC1,f
	rlf	REGC2,f
	rlf	REGC3,f
	return

;Check sign of REGB and negative convert to positive
;Used by multiply, divide, mod

chksgnb	rlf	REGB3,w
	skpc
	return			;Positive

;Negate REGB
;Used by chksgnb, subtract, multiply, divide, mod

negateb	movf	REGB3,w		;Save sign in w
	andlw	0x80

	comf	REGB0,f		;2's complement
	comf	REGB1,f
	comf	REGB2,f
	comf	REGB3,f
	incfsz	REGB0,f
	goto	negb1
	incfsz	REGB1,f
	goto	negb1
	incfsz	REGB2,f
	goto	negb1
	incf	REGB3,f
negb1
	incf	MTEMP,f		;flip sign flag
	addwf	REGB3,w		;Return carry set if -2147483648
	return

movac	movf	REGA0,w
	movwf	REGC0
	movf	REGA1,w
	movwf	REGC1
	movf	REGA2,w
	movwf	REGC2
	movf	REGA3,w
	movwf	REGC3
	return

;Clear REGB and REGA
;Used by sqrt

clrba	clrf	REGB0
	clrf	REGB1
	clrf	REGB2
	clrf	REGB3

;Clear REGA
;Used by multiply, sqrt

clra	clrf	REGA0
	clrf	REGA1
	clrf	REGA2
	clrf	REGA3
	return

;Add REGB to REGA (Unsigned)
;Used by add, multiply,

addba	movf	REGB0,w		;Add lo byte
	addwf	REGA0,f

	movf	REGB1,w		;Add mid-lo byte
	skpnc			;No carry_in, so just add
	incfsz	REGB1,w		;Add carry_in to REGB
	addwf	REGA1,f		;Add and propagate carry_out

	movf	REGB2,w		;Add mid-hi byte
	skpnc
	incfsz	REGB2,w
	addwf	REGA2,f

	movf	REGB3,w		;Add hi byte
	skpnc
	incfsz	REGB3,w
	addwf	REGA3,f
	return


;*** SIGNED SUBTRACT ***
;REGA - REGB -> REGA
;Return carry set if overflow

subtract
	call	negateb		;Negate and add
	skpnc
	return			;Overflow

;*** SIGNED ADD ***
;REGA + REGB -> REGA
;Return carry set if overflow

add	movf	REGA3,w		;Compare signs
	xorwf	REGB3,w
	movwf	MTEMP

	call	addba		;Add REGB to REGA

	clrc			;Check signs
	movf	REGB3,w		;If signs are same
	xorwf	REGA3,w		;so must result sign
	btfss	MTEMP,7		;else overflow
	addlw	0x80
	return

; *************

SHOWOVERFLOW: movwf OVERFLOW
        call CLRLINE2
        call LCD21
        bsf RSLINE,4

;        movf INDCORRECT,W      ; author's test section
;        movwf REGA0
;        movf LARGE,W
;        movwf REGA0
;        clrf REGA1
;        clrf REGA2
;        clrf REGA3
;        call BIN2DEC
;        call SHOWITALL

        clrf LOOP
OVER2:  movf LOOP,W
        call OVERFLOWED
        call LCDOUT
        incf LOOP,F
        btfss LOOP,3
        goto OVER2
        movlw ' '
        call LCDOUT
        movf OVERFLOW,W
        call LCDOUT
        goto MAIN

; ***********

CHECKZERO:
        movf TMR1H,W
        iorwf TMR1L,W
        iorwf TIMEMSB,W
        movf STATUS,W
        andlw B'00000100'
        movwf OVERFLOW

TIMEEND: movlw B'00000000'      ; stop timer 1
        movwf T1CON
        clrf TMR1H
        clrf TMR1L
        clrf TIMEMSB
        call LCD21
        bsf RSLINE,4
        clrf LOOP
TIMOUT2: movf LOOP,W
        call TIMEDOUT
        call LCDOUT
        incf LOOP,F
        btfss LOOP,4
        goto TIMOUT2

        call LCD1
        bsf RSLINE,4
        clrf LOOP
        btfsc PORTA,4
        goto TIMOUT4

TIMOUT3: movf LOOP,W
        call CAPTIME
        call LCDOUT
        incf LOOP,F
        btfss LOOP,4
        goto TIMOUT3
        goto MAIN

TIMOUT4: movf LOOP,W
        call INDTIME
        call LCDOUT
        incf LOOP,F
        btfss LOOP,4
        goto TIMOUT4
        goto MAIN


; ******* WRITE DATA TO EEPROM ROUTINE modified for PIC16F62x devices ********
          ;according to data sheet page 93 (is the same as for 16F87x devices
	  ; except that PIR2 of '87x has become PIR1 for '62x and page 2/3 not used)
	
                        ;This routine is entered with W holding
                        ;the eeprom byte address at which data
                        ;is to be stored. The data to be stored
                        ;is held in PROMVAL, which is located in both pages at or above $70
SETPRM: 
        BANK1
        movwf 	EEADR     ;copy W into EEADR to set eeprom address
        movf 	PROMVAL,W  ;get data value from PROMVAL and hold in W
        movwf 	EEDATA    ;copy W into eeprom data byte register
        bsf 	EECON1,WREN ;enable write flag

MANUAL: movlw 	55H       ;these lines cause the action required by
        movwf 	EECON2    ;by the eeprom to store the data in EEDATA
        movlw 	0AAH       ;at the address held by EEADR.
        movwf 	EECON2
        bsf 	EECON1,WR   ;set the ``perform write'' flag
        BANK0

CHKWRT: btfss 	PIR1,EEIF ;wait until bit 4 of PIR2 is set
        goto 	CHKWRT
        bcf 	PIR1,EEIF   ;clear bit 4 of PIR2
        return

;******** READ DATA FROM EEPROM ROUTINE modified for PIC16F62x devices ****
;         the data sheet page 93 is wrong!  This routine here works!

                        ;This routine is entered with W holding
                        ;the eeprom byte address to be read.
PRMGET: BANK1
        movwf 	EEADR     ;copy W into EEADR to set eeprom address
        bsf 	EECON1,RD   ;enable read flag
        movf 	EEDATA,W   ;read eeprom data now in EEDATA into W
        BANK0
        return

; ***********

CORRECTIT:
        call 	LCD1
        bsf 	RSLINE,4
        btfss 	PORTA,4
        goto 	CAPCRT
        
INDCRT: movlw 	'I'
        call 	LCDOUT
        movlw 	'N'
        call 	LCDOUT
        movlw 	'D'
        call 	LCDOUT
        clrf 	CORRECTLOC
        goto 	CORRECT2

CAPCRT: movlw 	'C'
        call 	LCDOUT
        movlw 	'A'
        call 	LCDOUT
        movlw 	'P'
        call 	LCDOUT
        movlw 	1 
        movwf 	CORRECTLOC

CORRECT2: clrf 	LOOP
CORRECT3: movf 	LOOP,W
        call 	CORRECTMSG
        call 	LCDOUT
        incf 	LOOP,F
        btfss 	LOOP,4
        goto 	CORRECT3

COR3:   call 	SHOWCORRECT
    
COR4:   btfsc 	PORTA,2       ; is S3 (RA2) still pressed?
        goto 	COR4           ; yes
        call 	PAUSIT

COR5:   btfss 	PORTA,2       ; is S3 (RA2) pressed?
        goto 	COR5           ; no

        btfsc 	PORTA,4
        goto 	COR7

COR6:   call 	INCIT
        call 	SHOWCORRECT
        call 	PAUSIT2
        call 	PAUSIT2
        goto 	COR5

COR7:   call 	DECIT
        call 	SHOWCORRECT
        call 	PAUSIT2
        call 	PAUSIT2
        goto 	COR5

INCIT:  movf 	CORRECTLOC,W
        call 	PRMGET
        movwf 	PROMVAL
        addlw 	1
        movwf 	PROMVAL
        xorlw 	200
        btfsc 	STATUS,Z
        decf 	PROMVAL,F
        movf 	CORRECTLOC,W
        call 	SETPRM
        return

DECIT:  movf 	CORRECTLOC,W
        call 	PRMGET
        movwf 	PROMVAL
        decf 	PROMVAL,F
        btfsc 	STATUS,Z
        incf 	PROMVAL,F
        movf 	CORRECTLOC,W
        call 	SETPRM
        return

; **********

SHOWCORRECT:
        movf 	CORRECTLOC,W
        call 	PRMGET
        movwf 	REGA0
        clrf 	REGA1
        clrf 	REGA2
        clrf 	REGA3

        call 	LCD21
        bsf 	RSLINE,4

        call 	BIN2DEC

        movf 	DIGIT8,W
        call 	LCDOUT
        movf 	DIGIT9,W
        call 	LCDOUT
        movf 	DIGIT10,W
        call 	LCDOUT
        return

; **************

        org 2100H             ; data eeprom values

        DE 100,100,0,0,0,0


        END
