include LCM.H ;********************************************************************************************** ; Initialize the CPU INIT CLRF PORTB MOVLW H'E1' TRIS PORTB CLRF PORTA MOVLW H'10' TRIS PORTA MOVLW H'38' OPTION CLRF INTCON ;********************************************************************************************** ;initialize display ; ;LCD display routines ; ; The LCD operates in nibble mode ; PORT A is the data bus ; PORT B contains the control lines INITLCD CALL DLY15 ;delay 15ms MOVLW 03 ;output function set MOVWF PORTA BSF _ENB ;send first function set CALL DLY5 ;delay 5ms BCF _ENB BSF _ENB ;send second function set CALL DLY5 ;delay 5ms BCF _ENB BSF _ENB ;send third function set CALL DLY5 ;delay 5ms BCF _ENB MOVLW 02 MOVWF PORTA ;set 4 bit mode CALL SEND MOVLW 28 ;send 4bits, 2 line, 5X7 dots CALL CMDLCD ;send command to LCD MOVLW 0C ;send DISPLAY ON CALL CMDLCD MOVLW 06 ;send ENTRY MODE SET CALL CMDLCD CALL CLRDSP ;clear the display ;********************************************************************************************** ;Test switches to ensure Lx, Cx and Zero are off TESTSW BTFSC _LX ;IF /LX (assumes sw inputs are active high) GOTO ERRORL BTFSC _CX ; AND /CX GOTO ERRORL GOTO WAIT ; WAIT ERRORL CALL DISPSW ;ELSE ERROR LOOP display "SWITCH ERROR" GOTO TESTSW ;ENDIF loop until operator clears switches WAIT CALL CLRDSP ;send DISPLAY CLEAR MOVLW 'W' ;display "WAIT" CALL CHARLCD MOVLW 'A' CALL CHARLCD MOVLW 'I' CALL CHARLCD MOVLW 'T' CALL CHARLCD MOVLW H'19' ;delay 5 seconds MOVWF T2 TD2 MOVLW H'FF' CALL DELAY DECFSZ T2 GOTO TD2 ;********************************************************************************************** ; ; Calibrate ; ; (F is actually COUNT = F*TIME where TIME=.20 seconds) ;Calibration: ;Cs=(f2^2 * 1000/(F1^2-F2^2) pf's ;Ls=1/(4*pi^2*F1^2/TIME^2*Cs) = 1.013212E15/F1^2/Cs uhy's ; CALIB CALL CLRDSP ;clear the display MOVLW 'C' ;display "CALIBRATING" CALL CHARLCD MOVLW 'A' CALL CHARLCD MOVLW 'L' CALL CHARLCD MOVLW 'I' CALL CHARLCD MOVLW 'B' CALL CHARLCD MOVLW 'R' CALL CHARLCD MOVLW 'A' CALL CHARLCD CALL CHAR8 MOVLW 'T' CALL CHARLCD MOVLW 'I' CALL CHARLCD MOVLW 'N' CALL CHARLCD MOVLW 'G' CALL CHARLCD MOVLW H'0C' MOVWF FSR RAMLOOP CLRF INDF 'clear RAM from 0C thru 1F INCF FSR BTFSS FSR,5 GOTO RAMLOOP CALL MEASURE ;measure F1^2 CALL FEQUA ;F=F1^2 BSF _CAL ;switch in calibration capacitor MOVLW H'09' ;delay 2 seconds MOVWF T2 TD1 MOVLW H'FF' CALL DELAY DECFSZ T2 GOTO TD1 CALL MEASURE ;measure F2^2 CALL CEQUA ;C=F2^2 (H'87.08 00 03 = 68) CALL BEQUA ;B=F2^2 BCF _CAL ;switch out calibration capacitor CALL AEQUF ;A= F1^2 CALL SUB ;A=F1^2 - F2^2 CALL BEQUA ;B=F1^2 - F2^2 MOVF CX,W ;A=F2^2 MOVWF AX MOVF C0,W MOVWF A0 MOVF C1,W MOVWF A1 MOVF C2,W MOVWF A2 CALL DIV ;A=F2^2/(F1^2 - F2^2) MOVLW 8A ;B=1000pf (H'8A.7A 00 00) MOVWF BX MOVLW 7A MOVWF B0 CLRF B1 CLRF B2 CALL MPY ;A=F2^2*1000pf/(F1^2 - F2^2)=C CALL CEQUA ;C=A CALL BEQUA ;B=C CALL AEQUF ;A=F1^2 CALL MPY ;A=F1^2*C CALL BEQUA ;B=F1^2*C MOVLW H'B2' ;A=1.013212E15 (H'B2.66 60 B3) MOVWF AX MOVLW H'66' MOVWF A0 MOVLW H'60' MOVWF A1 MOVLW H'B3' MOVWF A2 CALL DIV ;A=1.013212E15/(F1^2*Cs)=L MOVF AX,W ;L=A MOVWF LX MOVF A0,W MOVWF L0 MOVF A1,W MOVWF L1 MOVF A2,W MOVWF L2 ;********************************************************************************************** ; ;MAIN LOOP ; DO1A MOVLW H'81' ;DO CALL CMDLCD ; set DD RAM address=0 IF1A BTFSC _LX ; IF /LX and /CX GOTO ELSEIF1A BTFSC _CX GOTO ELSEIF1A IF6A BTFSC _ZERO ; IF ZERO GOTO CALIB ; CALIBRATE ELSE6A CALL MEASURE ; A=F1^2 ENDIF6A EQU $ IF2A MOVF T0,W ; IF VALID (W=0) BTFSS _Z GOTO ENDIF2A CALL FEQUA ; F=F1^2 CALL CLRDSP ; CLEAR DISPLAY MOVLW 'R' ; "READY" CALL CHARLCD MOVLW 'E' CALL CHARLCD MOVLW 'A' CALL CHARLCD MOVLW 'D' CALL CHARLCD MOVLW 'Y' CALL CHARLCD ENDIF2A GOTO ENDIF1A ; ENDIF ELSEIF1A BTFSS _LX ; ELSEIF LX and CX GOTO ELSE1A BTFSS _CX GOTO ELSE1A CALL DISPSW ; "SWITCH ERROR" GOTO ENDIF1A ELSE1A EQU $ ; ELSE (LX or CX) CALL MEASURE ; A=F2^2 IF3A MOVF T0,W ; IF VALID (W=0) BTFSS _Z GOTO ELSE3A CALL BEQUA ; B=F2^2 CALL AEQUF ; A=F1^2 CALL DIV ; A=F1^2/F2^2 MOVLW H'81' MOVWF BX CLRF B0 CLRF B1 CLRF B2 ; B=1 CALL SUB ; A=F1^2/F2^2-1 MOVF AX,W BTFSS _Z GOTO IF4A ; IF A<0 THEN A=0 CLRF AX CLRF A0 CLRF A1 CLRF A2 IF4A BTFSS _LX ; IF LX GOTO ELSE4A CALL BEQUL ; B=L CALL MPY ; A=(F1^2/F2^2-1)*L MOVF AX,W ; LS=A MOVWF LSX MOVF A0,W MOVWF LS0 MOVF A1,W MOVWF LS1 MOVF A2,W MOVWF LS2 CALL BEQUA ; B=LS MOVLW H'8E' ; A=10^4 MOVWF AX MOVLW H'1C' MOVWF A0 MOVLW H'40' MOVWF A1 CLRF A2 CALL SUB ; A=10^4 - LS IF13A BTFSC A0,7 ; IF RESULT POSITIVE GOTO ELSE13A MOVLW H'6F' ; B = .000007 MOVWF BX MOVLW H'6A' MOVWF B0 MOVLW H'E1' MOVWF B1 MOVLW H'8B' MOVWF B2 CALL MPY ; A = (10^4 - LS)*.000007 MOVLW H'81' ; B =1 MOVWF BX CLRF B0 CLRF B1 CLRF B2 CALL ADD ; A=((10^4 - LS)*.000007)+1 MOVF LSX,W ; B = LS MOVWF BX MOVF LS0,W MOVWF B0 MOVF LS1,W MOVWF B1 MOVF LS2,W MOVWF B2 CALL MPY ; A=(((10^4-LS)*.000007)+1)LS GOTO ENDIF13A ELSE13A MOVF LSX,W MOVWF AX ; B = LS MOVF LS0,W MOVWF A0 MOVF LS1,W MOVWF A1 MOVF LS2,W MOVWF A2 ENDIF13A EQU $ IF5A BTFSS _ZERO ; IF ZERO GOTO ELSE5A CALL MEASURE ; remeasure f1^2 CALL FEQUA CALL DISP00 GOTO ENDIF5A ELSE5A EQU $ ; ELSE CALL DISPLX ; "Lx= " CALL DISPVAL ; DISPLAY VALUE ENDIF5A GOTO ENDIF4A ; ENDIF ELSE4A CALL BEQUC ; ELSE (CX) CALL MPY ; A=(F1^2/F2^2-1)*C IF8A BTFSS _ZERO ; IF ZERO GOTO ELSE8A CALL MEASURE CALL FEQUA CALL DISP00 GOTO ENDIF8A ELSE8A EQU $ ; ELSE CALL DISPCX ; "Cx= " CALL DISPVAL ; DISPLAY VALUE ENDIF8A EQU $ ; ENDIF ENDIF4A GOTO ENDIF3A ; ENDIF ELSE3A EQU $ ; ELSE (invalid) IF11A BTFSS T0,1 ; IF stalled oscillator (W=2) GOTO ENDIF11A CALL CLRDSP MOVLW 'N' ; "NOT A" CALL CHARLCD MOVLW 'O' CALL CHARLCD MOVLW 'T' CALL CHARLCD CALL DISPSP MOVLW 'A' CALL CHARLCD IF12A BTFSS _LX ; IF LX GOTO ELSE12A MOVLW 'N' ; "N L" CALL CHARLCD MOVLW ' ' CALL CHARLCD CALL CHAR8 MOVLW 'L' CALL CHARLCD GOTO ENDIF12A ELSE12A EQU $ ; ELSE (CX) MOVLW ' ' ; " C" CALL CHARLCD MOVLW 'C' CALL CHARLCD ENDIF12A EQU $ ; ENDIF ENDIF11A EQU $ ; ENDIF ENDIF3A EQU $ ; ENDIF ENDIF1A EQU $ ; ENDIF GOTO DO1A ;LOOP PAGE ;********************************************************************************************** DISPVAL ;Compute value: ;Input: A=floating point Lx or Cx ;Output: A=BCD value of Lx or Cx ; ; DISPVAL CLRF T2 ;T2 = 0 WHILE1B MOVF AX,W ;WHILE A >= 1 SUBLW H'80' BTFSC _C GOTO WEND1B+1 MOVLW H'84' ; A = A / 10 MOVWF BX MOVLW H'20' MOVWF B0 CLRF B1 CLRF B2 CALL DIV INCF T2 ; T2 = T2 + 1 WEND1B GOTO WHILE1B ;WEND MOVLW H'8E' ;A = INT(A * 10000) MOVWF BX MOVLW H'1C' MOVWF B0 MOVLW H'40' MOVWF B1 CLRF B2 CALL MPY CALL INT CALL BCD ;A = STR$(A) MOVF T2,W MOVWF AX ;AX = T2 MOVLW H'E4' MOVWF LP ;default L prefix is micro MOVLW "p" MOVWF CP ;default C prefix is pico AX0 MOVF AX,W ;IF AX = 0 THEN BTFSS _Z GOTO AX1 CALL DISP0 ; PRINT 0.12 CALL DISPDOT CALL DIGIT1 CALL DIGIT2 CALL CHAR8 BTFSS _LX ; IF NOT LX THEN GOTO SP ; PRINT " " AND ENG UNITS CALL DIGIT3 ; ELSE PRINT 3 GOTO UNITS ; PRINT ENG UNITS AX1 DECFSZ AX ;ELSEIF AX - 1 = 0 THEN GOTO AX2 AX1LX CALL DIGIT1 ; PRINT 1.23 CALL DISPDOT CALL DIGIT2 CALL DIGIT3 CALL CHAR8 BTFSS _LX ; IF NOT LX THEN GOTO SP ; PRINT " " AND ENG UNITS CALL DIGIT4 ; ELSE PRINT 4 GOTO UNITS ; PRINT ENG UNITS AX2 DECFSZ AX ;ELSEIF AX - 2 = 0 THEN GOTO AX3 AX2LX CALL DIGIT1 ; PRINT 12.34 CALL DIGIT2 CALL DISPDOT CALL DIGIT3 CALL CHAR8 CALL DIGIT4 GOTO UNITS ; AND ENG UNITS AX3 DECFSZ AX ;ELSEIF AX - 3 = 0 THEN GOTO AX4 AX3LX CALL DIGIT1 ; PRINT 123.4 CALL DIGIT2 CALL DIGIT3 CALL DISPDOT CALL CHAR8 CALL DIGIT4 GOTO UNITS ; AND ENG UNITS AX4 MOVLW "m" MOVWF LP ;L PREFIX="m" MOVLW "n" BTFSS _JUMPER ;IF JUMPER SHORT THEN CP="n" MOVWF CP DECFSZ AX ;ELSEIF AX - 4 = 0 THEN GOTO AX5 BTFSC _LX ; IF LX THEN PRINT 1.234 GOTO AX4LX ; AND ENG UNITS BTFSC _JUMPER ; ELSEIF JUMPER GOTO AX4CX AX4LX CALL DIGIT1 ; PRINT 1.234 CALL DISPDOT CALL DIGIT2 CALL DIGIT3 CALL CHAR8 CALL DIGIT4 GOTO UNITS ; AND ENG UNITS AX4CX CALL DIGIT1 ; ELSE PRINT DIGITS 1234 CALL DIGIT2 CALL DIGIT3 CALL DIGIT4 CALL CHAR8 GOTO SP ; PRINT " " AND ENG UNITS AX5 MOVLW H'E4' BTFSC _JUMPER ;IF NOT JUMPER THEN CP="u" MOVWF CP DECFSZ AX ;ELSEIF AX - 5 = 0 THEN GOTO AX6 BTFSC _LX ; IF LX THEN PRINT 12.34 AND ENG UNITS GOTO AX2LX BTFSS _JUMPER ; IF JUMPER PRINT 12.34 AND ENG UNITS GOTO AX2LX CALL DISPDOT ; ELSE PRINT .0123 CALL DISP0 CALL DIGIT1 CALL DIGIT2 CALL CHAR8 CALL DIGIT3 GOTO UNITS AX6 DECFSZ AX ;ELSEIF AX - 6 = 0 THEN GOTO AX7 BTFSC _LX ; IF LX THEN GOTO AX3LX ; PRINT 123.4 AND ENG UNITS BTFSS _JUMPER ; IF JUMPER GOTO AX3LX ; PRINT 123.4 AND ENG UNITS CALL DISPDOT ; ELSE PRINT .1234 CALL DIGIT1 CALL DIGIT2 CALL DIGIT3 CALL CHAR8 CALL DIGIT4 GOTO UNITS AX7 MOVLW " " MOVWF LP ;LP = " " MOVLW H'E4' MOVWF CP ;CP = "u" GOTO AX4LX ;PRINT 1.234 SP CALL DISPSP UNITS CALL DISPSP BTFSS _LX ;IF LX THEN GOTO CXP MOVF LP,W CALL CHARLCD MOVLW "H" ; PRINT "Hy's" CALL CHARLCD MOVLW "y" GOTO PX CXP MOVF CP,W CALL CHARLCD MOVLW "F" ;ELSE PRINT "F's" PX CALL CHARLCD ;END IF MOVLW "'" CALL CHARLCD MOVLW "s" CALL CHARLCD GOTO DISPSP ;exit displaying a space ; ; DIGIT1 SWAPF A1 ;PRINT DIGIT 1 MOVF A1,W CALL NUMLCD RETLW 0 DIGIT2 EQU DIGIT1 ;PRINT DIGIT 2 DIGIT3 SWAPF A2 ;PRINT DIGIT 3 MOVF A2,W CALL NUMLCD RETLW 0 DIGIT4 EQU DIGIT3 ;PRINT DIGIT 4 ;********************************************************************************************** ; Delay timer. Delay = 771*MSD microseconds (.197 sec max) ; entry CALL DELAY, W = MSD ; CALL DLY200 implements a 200 us delay DLY15 CALL DLY5 CALL DLY5 DLY5 MOVLW 07 GOTO DELAY DLY200 MOVLW 40 ;delay 200us MOVWF T1 MOVLW 01 GOTO DELAY2 DELAY CLRF T1 DELAY2 MOVWF T0 DELAYL DECFSZ T1 ;decrement LSB until zero GOTO DELAYL DECFSZ T0 ;decrement MSB until zero GOTO DELAYL RETLW 0 ;exit ;********************************************************************************************** ; Send one byte to LCD ; CALL CMDLCD sends command in W to LCD ; CALL NUMLCD sends BCD digit in low nibble in W as ASCII char ; CALL CHARLCD sends ASCII character in W to LCD ;There is a 200 us delay built into the end of the routine. ; CHAR8 MOVLW H'C0' ;SET TO SECOND 8 CHARS CMDLCD MOVWF B0 ;save byte CLRF PORTB ;SET /RW, /ENB, /RS GOTO SENDLCD NUMLCD ANDLW 0F ;mask LS nibble IORLW 30 ;make ASCII number CHARLCD MOVWF B0 ;save byte MOVLW 08 MOVWF PORTB ;set /RW, /ENB, RS SENDLCD SWAPF B0 ;send high nibble first MOVF B0,W MOVWF PORTA BSF _ENB ;toggle ENB on BCF _ENB ;toggle ENB off SWAPF B0 ;swap nibbles MOVF B0,W MOVWF PORTA ;send low nibble SEND BSF _ENB ;toggle ENB on BCF _ENB ;toggle ENB off CALL DLY200 ;delay 200us RETLW 0 ;exit ;********************************************************************************************** CLRDSP MOVLW 01 CLR6 CALL CMDLCD ;clear display CALL DLY5 ;delay 5ms MOVLW H'28' ;set 4 bit 2 line CALL CMDLCD GOTO DISPSP ;********************************************************************************************** DISPDOT MOVLW "." GOTO CHARLCD DISP0 MOVLW "0" GOTO CHARLCD ;********************************************************************************************** DISPSW MOVLW 'S' ;DISPLAY SWITCH ERROR CALL CHARLCD MOVLW 'W' CALL CHARLCD MOVLW 'I' CALL CHARLCD MOVLW 'T' CALL CHARLCD MOVLW 'C' CALL CHARLCD MOVLW 'H' CALL CHARLCD CALL DISPSP CALL CHAR8 MOVLW 'E' CALL CHARLCD MOVLW 'R' CALL CHARLCD MOVLW 'R' CALL CHARLCD MOVLW 'O' CALL CHARLCD MOVLW 'R' CALL CHARLCD CALL DISPSP CALL DISPSP GOTO DISPSP ;********************************************************************************************** DISP00 CALL CLRDSP CALL DISP0 CALL DISPDOT CALL DISP0 CALL DISP0 CALL DISP0 GOTO DISPSP ;********************************************************************************************** DISPLX MOVLW "L" CALL CHARLCD GOTO DISPX DISPCX MOVLW "C" CALL CHARLCD DISPX MOVLW "x" CALL CHARLCD MOVLW "=" CALL CHARLCD RETLW 0 ;********************************************************************************************** DISPSP MOVLW " " CALL CHARLCD RETLW 0 ;********************************************************************************************** ;********************************************************************************************** ;********************************************************************************************** ;********************************************************************************************** ;********************************************************************************************** ;MEASURE Measure frequency on RTCC pin ; returns A=count squared=(freq*time)squared ; time = .2 seconds ;DISPVAL Display value of Lx or Cx ; Input: A=floating point value ; Output: A=5 digit BCD value in A0, A1, A2 ; AX=decimel exponent ; value is output to the LCD as: ; X.XXX, XX.XX, XXX.X or XXXX as a function of AX ;BEQUA B=A ;AEQUF A=F ;BEQUC B=C ;BEQUL B=L ;FEQUA F=A ;CEQUA C=A ;BCD 16 bit number in A1,A2 converted to 5 BCD ; digits in A0, A1 and A2 with MS digit in A0 ;FLOAT 24 bit unsigned integer to 32 bit floating point ; Input: integer right justified in A0, A1, A2 ; Output: 32 bit floating point number in AX, A0, A1, A2 ;INT 32 bit floating point to 16 bit integer ; Input: 32 bit floating point number in AX, A0, A1, A2 ; Output:24 bit 2's compl' integer right justified in A0, A1, A2 ;ADD 32 bit floating point add ; Input: 32 bit floating point number in AX, A0, A1, A2 ; 32 bit floating point number in BX, B0, B1, B2 ; Output: 32 bit floating point sum in AX, A0, A1, A2 ;SUB 32 bit floating point subtract ; Input: 32 bit floating point number in AX, A0, A1, A2 ; 32 bit floating point number in BX, B0, B1, B2 ; Output: 32 bit floating point difference in AX, A0, A1, A2 ;MPY 32 bit floating point multiply ; Input: 32 bit floating point number in AX, A0, A1, A2 ; 32 bit floating point number in BX, B0, B1, B2 ; Output: 32 bit floating point product in AX, A0, A1, A2 ;DIV 32 bit floating point divide ; Input: 32 bit floating point dividend in AX, A0, A1, A2 ; 32 bit floating point divisor in BX, B0, B1, B2 ; Output: 32 bit floating point quotient in AX, A0, A1, A2 PAGE ;********************************************************************************************** ; Routine to measure frequency ; returns floating point number = count squared in A ; IF switch settings on exit match those on entry ; return T0=0 (valid measurement) ; ELSEIF switches have changed ; return T0=1 (invalid measurement) ; ELSEIF oscillator stalled ; return T0=2 (open circuit inductor or short circuit capacitor) ; (invalid measurement) ; ENDIF ; MEASURE MOVF PORTB,W ;save switch settings ANDLW H'60' MOVWF T2 CLRF A0 ;clear count CLRF A1 CLRF A2 MOVLW H'38' ;initialize delay = 200,000us (.2 sec) MOVWF T0 ;loop is 14us MOVLW H'CD' ;so initialize counter to 14285+256(H'38CD) MOVWF T1 ;actual period is 200006 us CLRF CNTR ;initialize CNTR MEAS1 GOTO MEAS2 ;2 cycle delay MEAS2 MOVF CNTR,W ;W=CNTR SUBWF A2,W ;W=A2-CNTR BTFSS _C ;Did A2 overflow? (CARRY) GOTO MEAS5 ; NO, do not increment A1 BTFSS _Z ;Does A2=0, NO do not increment A1 INCFSZ A1 ; YES, inc A1, overlow? (ZERO) GOTO MEAS3 ; NO INCF A0 ; YES, increment A0 MEAS3 SUBWF A2 ;A2=W=A2-(A2-CNTR)=CNTR DECFSZ T1 ;decrement delay GOTO MEAS1 DECFSZ T0 GOTO MEAS2 CLRF T0 ;initialize return code=0 MOVF A0,W ;measurement complete, 17 bits in A0,A1,A2 BTFSS _Z ; IF A0 GOTO MEAS4 MOVF A1,W ; and A1 both zero BTFSS _Z GOTO MEAS4 BSF T0,1 RETLW 0 ; return T0=2 (stalled oscillator) MEAS4 MOVF PORTB,W ; IF switch settings changed ANDLW H'60' ; (MASK SWITCHES) SUBWF T2,W BTFSC _Z GOTO MEAS6 BSF T0,0 ; switches have changed RETLW 0 ; return with T0=1 (invalid measurement) MEAS6 CALL FLOAT ;convert to floating point CALL BEQUA ;B=A CALL MPY ;A=A*A CLRF T0 RETLW 0 ;return with T0=0 (valid measurement) MEAS5 NOP GOTO MEAS3 ;********************************************************************************************** BEQUA MOVF AX,W MOVWF BX MOVF A0,W MOVWF B0 MOVF A1,W MOVWF B1 MOVF A2,W MOVWF B2 RETLW 0 ;************************************************************** AEQUF MOVF FX,W MOVWF AX MOVF F0,W MOVWF A0 MOVF F1,W MOVWF A1 MOVF F2,W MOVWF A2 RETLW 0 ;********************************************************** BEQUC MOVF CX,W MOVWF BX MOVF C0,W MOVWF B0 MOVF C1,W MOVWF B1 MOVF C2,W MOVWF B2 RETLW 0 ;************************************************************ BEQUL MOVF LX,W ; B=L MOVWF BX MOVF L0,W MOVWF B0 MOVF L1,W MOVWF B1 MOVF L2,W MOVWF B2 RETLW 0 ;************************************************************* FEQUA MOVF AX,W ;save A in F MOVWF FX MOVF A0,W MOVWF F0 MOVF A1,W MOVWF F1 MOVF A2,W MOVWF F2 RETLW 0 ;************************************************************* CEQUA MOVF AX,W ;save A in C MOVWF CX MOVF A0,W MOVWF C0 MOVF A1,W MOVWF C1 MOVF A2,W MOVWF C2 RETLW 0 ;********************************************************************************************** ; Binary To BCD Conversion Routine ; This routine converts a 16 Bit binary Number to a 5 Digit ; BCD Number. ; The 16 bit binary number is input in locations A1 and ;A2 with the high byte in A1. ; The 5 digit BCD number is returned in A0, A1 and A2 with A0 ; containing the MSD in its right most nibble. ; ; Performance : ; Program Memory : 35 ; Clock Cycles : 885 ; ;********************************************************************************************** BCD MOVF A1,W MOVWF B0 MOVF A2,W MOVWF B1 bcf _C ; clear the carry bit movlw .16 movwf T1 clrf A0 clrf A1 clrf A2 loop16 rlf B1 rlf B0 rlf A2 rlf A1 rlf A0 decfsz T1 goto adjDEC RETLW 0 adjDEC movlw A2 movwf FSR call adjBCD movlw A1 movwf FSR call adjBCD movlw A0 movwf FSR call adjBCD goto loop16 adjBCD movlw 3 addwf 0,W movwf T0 btfsc T0,3 ; test if result > 7 movwf 0 movlw 30 addwf 0,W movwf T0 btfsc T0,7 ; test if result > 7 movwf 0 ; save as MSD RETLW 0 ;********************************************************************************************** ;********************************************************************************************** ;********************************************************************************************** ; PIC16 32 BIT FLOATING POINT LIBRARY ; Unary operations: both input and output are in AX,A ; Binary operations: input in AX,A and BX,B with output in AX,A ;********************************************************************************************** ;********************************************************************************************** ; 32 bit floating point representation ; EXPONENT 8 bit biased exponent ; It is important to note that the use of biased exponents produces ; a unique representation of a floating point 0, given by ; EXP = HIGHBYTE = MIDBYTE = LOWBYTE = 0x00, with 0 being ; the only number with AX = 0. ; HIGHBYTE 8 bit most significant byte of sign-magnitude representation, with ; SIGN = MSB, and implicit mantissa MSB = 1 and radix point to the ; left of MSB ; MIDBYTE 8 bit middle significant byte of sign-magnitude matissa ; LOWBYTE 8 bit least significant byte of sign-magnitude matissa ; RADIX ; EXPONENT POINT HIGHBYTE MIDBYTE LOWBYTE ; xxxxxxxx . Sxxxxxxx xxxxxxxx xxxxxxxx EXPBIAS equ H'80' ;********************************************************************************************** ; Integer to float conversion ; Input: 24 bit unsigned integer right justified in A0, A1, A2 ; Use: CALL FLOAT ; Output: 32 bit floating point number in AX, A0, A1, A2 ; Result: A <-- FLOAT( A ) FLOAT MOVLW H'18'+EXPBIAS ; initialize exponent and add bias MOVWF AX CLRF SIGN ; fall thru to normalize ;------------------------------------------------------------------- ; Normalization routine ; Input: 32 bit unnormalized floating point number in AX, A0, A1, A2 ; with sign in SIGN,MSB ; Use: CALL NRM32 ; Output: 32 bit normalized floating point number in AX, A0, A1, ; A2 ; Result: A <-- NORMALIZE( A ) NRM32 CLRF T0 ; clear exponent decrement MOVF A0,W ; test if highbyte=0 BTFSS _Z GOTO NORM32 MOVF A1,W ; if so, shift 8 bits by move MOVWF A0 MOVF A2,W MOVWF A1 CLRF A2 BSF T0,3 ; increase decrement by 8 MOVF A0,W ; test if highbyte=0 BTFSS _Z GOTO NORM32 MOVF A1,W ; if so, shift 8 bits by move MOVWF A0 CLRF A1 BCF T0,3 ; increase decrement by 8 BSF T0,4 MOVF A0,W ; if highbyte=0, result=0 BTFSC _Z GOTO RES032 NORM32 MOVF T0,W SUBWF AX BCF _C NORM32A BTFSC A0,MSB ; if MSB=1, normalization done GOTO FIXSIGN32 RLF A2 ; otherwise, shift left and RLF A1 ; decrement AX RLF A0 DECF AX GOTO NORM32A FIXSIGN32 BTFSS SIGN,MSB BCF A0,MSB ; clear explicit MSB if positive RETLW 0 ;********************************************************************************************** ;********************************************************************************************** ; Float to integer conversion ; Input: 32 bit floating point number in AX, A0, A1, A2 ; Use: CALL INT ; Output: 24 bit unsigned integer right justified in A0, A1, A2 ; Result: A <-- INT( A ) INT BSF A0,MSB ; make MSB explicit MOVLW EXPBIAS ; remove bias from AX SUBWF AX BTFSS AX,MSB ; if <= 0, result=0 BTFSC _Z GOTO RES032 MOVF AX,W SUBLW 18 MOVWF AX SHIFT32 BCF _C RRF A0 ; right shift by AX RRF A1 RRF A2 DECFSZ AX GOTO SHIFT32 RETLW 0 RES032 CLRF A0 ; integer result equals zero CLRF A1 CLRF A2 CLRF AX ; clear AX for other routines INT32OK RETLW 0 ;********************************************************************************************** ;********************************************************************************************** ; Floating Point Multiply ; Input: 32 bit floating point number in AX, A0, A1, A2 ; 32 bit floating point number in BX, B0, B1, B2 ; Use: CALL MPY ; Output: 32 bit floating point product in AX, A0, A1, A2 ; Result: A <-- A * B MPY MOVF AX,W ; test for zero arguments BTFSS _Z MOVF BX,W BTFSC _Z GOTO RES032 M32BNE0 MOVF A0,W XORWF B0,W MOVWF SIGN ; save sign in SIGN MOVF BX,W ADDWF AX MOVLW EXPBIAS BTFSS _C GOTO MTUN32 ADDWF AX GOTO MOK32 MTUN32 ADDWF AX MOK32 BSF A0,MSB ; make argument MSB's explicit BSF B0,MSB BCF _C CLRF A3 ; clear initial partial product CLRF A4 CLRF A5 MOVLW 18 MOVWF T0 ; initialize counter MLOOP32 BTFSS A2,LSB ; test high byte GOTO MNOADD32 MADD32 MOVF B2,W ADDWF A5 MOVF B1,W BTFSC _C INCFSZ B1,W ADDWF A4 MOVF B0,W BTFSC _C INCFSZ B0,W ADDWF A3 MNOADD32 RRF A3 RRF A4 RRF A5 RRF A0 RRF A1 RRF A2 BCF _C DECFSZ T0 GOTO MLOOP32 BTFSC A3,MSB ; check for postnormalization GOTO MUL32OK RLF A0 RLF A5 RLF A4 RLF A3 DECF AX MUL32OK BTFSS SIGN,MSB BCF A3,MSB ; clear explicit MSB if positive MOVF A3,W MOVWF A0 ; move result to A MOVF A4,W MOVWF A1 MOVF A5,W MOVWF A2 RETLW 0 ;********************************************************************************************** ;********************************************************************************************** ; Floating Point Divide ; Input: 32 bit floating point dividend in AX, A0, A1, A2 ; 32 bit floating point divisor in BX, B0, B1, B2 ; Use: CALL DIV ; Output: 32 bit floating point quotient in AX, A0, A1, A2 ; Result: A <-- A / B ; PM: 152 DM: 14 DIV MOVF A0,W XORWF B0,W MOVWF SIGN ; save sign in SIGN BSF A0,MSB ; make argument MSB's explicit BSF B0,MSB TALIGN32 CLRF T0 ; clear align increment MOVF A0,W MOVWF A3 ; test for alignment MOVF A1,W MOVWF A4 MOVF A2,W MOVWF A5 MOVF B2,W SUBWF A5 MOVF B1,W BTFSS _C INCFSZ B1,W TS1ALIGN32 SUBWF A4 MOVF B0,W BTFSS _C INCFSZ B0,W TS2ALIGN32 SUBWF A3 CLRF A3 CLRF A4 CLRF A5 BTFSS _C GOTO DALIGN32OK BCF _C ; align if necessary RRF A0 RRF A1 RRF A2 RRF A3 MOVLW 0x01 MOVWF T0 ; save align increment DALIGN32OK MOVF BX,W ; compare AX and BX SUBWF AX BTFSS _C GOTO ALTB32 AGEB32 MOVLW EXPBIAS ADDWF T0,W ADDWF AX GOTO DARGOK32 ALTB32 MOVLW EXPBIAS ADDWF T0,W ADDWF AX DARGOK32 MOVLW 18 ; initialize counter MOVWF T1 DLOOP32 RLF A5 ; left shift RLF A4 RLF A3 RLF A2 RLF A1 RLF A0 RLF T0 MOVF B2,W ; subtract SUBWF A2 MOVF B1,W BTFSS _C INCFSZ B1,W DS132 SUBWF A1 MOVF B0,W BTFSS _C INCFSZ B0,W DS232 SUBWF A0 RLF B0,W IORWF T0 BTFSS T0,LSB ; test for restore GOTO DREST32 BSF A5,LSB GOTO DOK32 DREST32 MOVF B2,W ; restore if necessary ADDWF A2 MOVF B1,W BTFSC _C INCFSZ B1,W DAREST32 ADDWF A1 MOVF B0,W BTFSC _C INCF B0,W ADDWF A0 BCF A5,LSB DOK32 DECFSZ T1 GOTO DLOOP32 DDIV32OK BTFSS SIGN,MSB BCF A3,MSB ; clear explicit MSB if positive MOVF A3,W MOVWF A0 ; move result to A MOVF A4,W MOVWF A1 MOVF A5,W MOVWF A2 RETLW 0 ;********************************************************************************************** ;********************************************************************************************** ; Floating Point Subtract ; Input: 32 bit floating point number in AX, A0, A1, A2 ; 32 bit floating point number in BX, B0, B1, B2 ; Use: CALL SUB ; Output: 32 bit floating point sum in AX, A0, A1, A2 ; Result: A <-- A - B SUB MOVF BX,W BTFSS _Z GOTO SUB1 MOVF B0,W BTFSC _Z RETLW 0 SUB1 MOVLW 0x80 XORWF B0 ;------------------------------------------------------------------- ; Floating Point Add ; Input: 32 bit floating point number in AX, A0, A1, A2 ; 32 bit floating point number in BX, B0, B1, B2 ; Use: CALL ADD ; Output: 32 bit floating point sum in AX, A0, A1, A2 ; Result: A <-- A - B ADD MOVF A0,W ; exclusive or of signs in TEMP XORWF B0,W MOVWF T0 MOVF AX,W ; use A if AX >= BX SUBWF BX,W BTFSS _C GOTO USEA32 MOVF BX,W MOVWF A5 ; otherwise, swap A and B MOVF AX,W MOVWF BX MOVF A5,W MOVWF AX MOVF B0,W MOVWF A5 MOVF A0,W MOVWF B0 MOVF A5,W MOVWF A0 MOVF B1,W MOVWF A5 MOVF A1,W MOVWF B1 MOVF A5,W MOVWF A1 MOVF B2,W MOVWF A5 MOVF A2,W MOVWF B2 MOVF A5,W MOVWF A2 USEA32 MOVF A0,W MOVWF SIGN ; save sign in SIGN BSF A0,MSB ; make MSB's explicit BSF B0,MSB MOVF B0,W MOVWF A3 MOVF B1,W MOVWF A4 MOVF B2,W MOVWF A5 MOVF BX,W ; compute shift count in BX SUBWF AX,W MOVWF BX BTFSC _Z GOTO ALIGNED32 MOVLW 8 SUBWF BX,W BTFSS _C ; if BX >= 8, do byte shift GOTO ALIGNB32 MOVWF BX RLF A5 ; rotate next bit for rounding MOVF A4,W MOVWF A5 MOVF A3,W MOVWF A4 CLRF A3 MOVLW 8 SUBWF BX,W BTFSS _C ; if BX >= 8, do byte shift GOTO ALIGNB32 MOVWF BX RLF A5 ; rotate next bit for rounding MOVF A4,W MOVWF A5 CLRF A4 ALIGNB32 MOVF BX,W ; already aligned if BX = 0 BTFSC _Z GOTO ALIGNED32 ALOOPB32 BCF _C ; right shift by BX RRF A3 RRF A4 RRF A5 DECFSZ BX GOTO ALOOPB32 ALIGNED32 BTFSS T0,MSB ; negate if signs opposite GOTO AOK32 COMF A3 COMF A4 COMF A5 INCF A5 BTFSC _Z INCF A4 BTFSC _Z INCF A3 AOK32 MOVF A5,W ; add ADDWF A2 MOVF A4,W BTFSC _C INCFSZ A4,W ADDWF A1 MOVF A3,W BTFSC _C INCFSZ A3,W ADDWF A0 BTFSC T0,MSB GOTO ACOMP32 BTFSS _C GOTO FIXSIGN32 RRF A0 ; shift right and increment AX RRF A1 RRF A2 INCF AX GOTO FIXSIGN32 ACOMP32 BTFSC _C GOTO NRM32 ; normalize and fix sign COMF A0 ; negate, toggle sign bit and COMF A1 ; then normalize COMF A2 INCF A2 BTFSC _Z INCF A1 BTFSC _Z INCF A0 MOVLW 0x80 XORWF SIGN GOTO NRM32 END