;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 $03,5 #DEFINE BANK1 BSF $03,5 List P=PIC16F628, R=DEC; __CONFIG h'3F21' include P16F628.inc CBLOCK 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 $70 ; 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 %00110011 ;initialise lcd - first byte retlw %00110011 ;2nd byte (repeat of first) retlw %00110010 ;set for 4-bit operation retlw %00101100 ;set for 2 lines retlw %00000110 ;set entry mode to increment each address retlw %00001100 ;set display on, cursor off, blink off retlw %00000001 ;clear display retlw %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 $07 movwf CMCON BANK1 movlw %11000000 movwf TRISB movlw %00011100 ; RA0,RA1 as output movwf TRISA movlw %10000110 ; timer 1:128, pull-ups off movwf OPTION_REG BANK0 clrf INTCON call PAUSIT call LCDSET call PAUSIT movlw %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 %00010000 xorwf SWITCH,W btfsc STATUS,Z goto MAIN2 movf PORTA,W andlw %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 %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 %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 %00000010 ; set for correct osc movwf PORTA clrf TIMEMSB call INDTIMER call COPY_TIME_REGA clrf POINT clrf LARGE movf TMR1H,W andlw %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 %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 %01000000 movwf STORE ; store it clrf SLOWIT bsf T1CON,0 ; start timer 1 WAITB1: movf PORTA,W andlw %00010000 xorwf SWITCH,W btfss STATUS,Z return WAITB2: movf PORTB,W ; get current status of RB6 andlw %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 %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 %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 %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 %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 %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 %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 %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 %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 %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 %01000000 movwf STORE2 xorwf STORE,W btfsc STATUS,Z goto OSCA2 ; yes movlw %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 %10000000 goto LCDLIN LCD5: movlw %10000101 goto LCDLIN LCD6: movlw %10000110 goto LCDLIN LCD8: movlw %10001000 goto LCDLIN LCD9: movlw %10001001 goto LCDLIN LCD13: movlw %10001101 goto LCDLIN LCD15: movlw %10001111 goto LCDLIN LCD21: movlw %11000000 goto LCDLIN LCD25: movlw %11000101 goto LCDLIN LCD26: movlw %11000110 goto LCDLIN LCD28: movlw %11001000 goto LCDLIN LCD29: movlw %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 $3B ; divide 1,000,000,000 ($3B9ACA00) by the answer movwf REGA3 movlw $9A movwf REGA2 movlw $CA movwf REGA1 movlw $00 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 %00000100 movwf OVERFLOW TIMEEND: movlw %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 $55 ;these lines cause the action required by movwf EECON2 ;by the eeprom to store the data in EEDATA movlw $AA ;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 $2100 ; data eeprom values DE 100,100,0,0,0,0 END