; ; Super Probe - Maximum Functions from Minimum Parts ; ; Current Functions ; ----------------- ; Logic Probe ; Voltmeter ; Frequency Counter ; Event Counter ; Capacitor Test ; Signal Generator ; Diode Tester ; Logic Pulser ; Serial Generator (4 rates) ; Midi Generator ; r/c servo pulse ; Square Wave ; 20kHz digital noise ; 38KHz burst ; Stopwatch ;line 2330 ; ; 29 added r/c square noise burst baudrates ; 29 added menu forward/back ; 30 added pwm function ; 31 reworked square wave for interrupt operation ; 32 fix logic probe function ; 33 (compatibility with new assembler) ; 34 fix dpcap syntax for hex values - last 2 ; 35 add inductance measure ; 36 recalibrate inductance ; 37 inverted display anodes ; Versions above 37 by Heli Tejedor, helitp@arrakis.es, http_//heli.xbot.es ; 38 added 4 new baud rates and #define INVERT_A for new hardware ; 39 NEW mode hivolt scaled to 25.00 (multiply by 2500 and divide by 1023) ; mode volt scaled to 5.00 (multiply by 500 and divide by 1023) ; by Heli Tejedor, http_//heli.xbot.es, helitp@arrakis.es ; 40 New mode Servo R/C measure (pulse width) R/C.i Servo output is now R/C.o ; tested from 990us to 100ms (theoretically work from 10us to >16seg) ; 41 R/C.i measure pulse-width high and low, 10us resolution (=200kHz pulse) ; 42 Increase scan-rate to reduce flikering 22-6-2011 - Colin Mitchell ; 43 LEDs feature - meaures voltage across a LED @approx 20mA ;#define INVERT_A ; New hardware with transistor output for anodes list p=16f870A ; list directive to define processor #include ; processor specific variable definitions errorlevel -302 ; Register not in bank 0 warning radix dec __CONFIG _CP_OFF & _WDT_OFF & _BODEN_OFF & _PWRTE_ON & _HS_OSC & _LVP_OFF & _DEBUG_OFF & _CPD_OFF #define VERS 043 ;Version to display #define LPTIME 42990 ;calibration time for counter #define MAXMODE 20 ;total operational modes - added stopwatch 23-6-2011 #define MAXBAUD 8 ;Serial generator baud rates #define CLAMP PORTA,5 ;clamp input to T0 #define R20 PORTA,0 ;22 ohm direct feed #define R100 PORTA,1 ;100 ohms #define R470 PORTA,4 ;470 ohms #define R150 PORTA,2 ;150 #define R10K PORTC,7 ;10k #define R10KA PORTC,6 ;10k #define R100K PORTA,3 ;100k feed to input #define BLACK R150 #define WHITE R100 #define SOUT R20 #define BUT1 PORTC,4 ;button 1 #define BUT2 PORTC,5 ;button 2 ; Data storange org 20h wsave equ 20H ssave equ 21H ;icount equ 22H ; not used bitcnt equ 22H ; flag equ 23H count equ 24H scount equ 25H csave equ 26H ddata equ 27H ; was data sdata equ 28H temp equ 29H ;TE added - see line 576 ontime equ 2BH oftime equ 2CH isrvec equ 2DH qtime equ 2EH ;comm timer for serial timer equ 30H freq equ 33H ; pwmp equ 35H mode equ 36H rate equ 37H baud equ 38H midic equ 39H ;midi channel pmode equ 3AH hi equ 3BH lo equ 3CH ; was low rand equ 3DH acc equ 40H ;32 bit register acc+0(40H)_MSB acc+3(43H)_LSB xacc equ 44H ;aux 32 bit value digits equ 48H ;segment data for LED dignr equ 4CH dp equ 4DH ftimer equ 4EH segmask equ 50H dela equ 51H bcd equ 54H ;10 digit packed bcd buffer (5 bytes) ;pto equ 59H ; not used ;pti equ 5AH ; not used cnt equ 59H ; 5BH ii equ 5AH frame equ 5BH place equ 5Ch port_temp equ 5Dh #define HOLD flag,0 #define DIR flag,1 #define SAVE flag,2 #define RUN flag,3 #define SWIT flag,4 #define HIV flag,5 #define MED_L flag,6 ; Program Start org 0 goto start ;line 400 ; Interrupt service routines ========================================== org 4 isr movwf wsave swapf STATUS,w movwf ssave clrf STATUS movf isrvec,w addwf PCL,f goto pwmi ; PWM interrupt goto sqri ; square wave generator interrupt ; goto here for exit from interrupt isrx swapf ssave,w movwf STATUS swapf wsave,f swapf wsave,w retfie ; Table for number to seven segment conversion ======================== digseg addwf PCL,f retlw 3fh ;0 retlw 6h ;1 retlw 5bh ;2 retlw 4fh ;3 retlw 66h ;4 retlw 6dh ;5 retlw 7dh ;6 retlw 7h ;7 retlw 7fh ;8 retlw 67h ;9 ; Get anode value for PORT C output getano addwf PCL,f #ifdef INVERT_A retlw 0FEh ; 1 inverted retlw 0FDh ; 2 inverted retlw 0FBh ; 4 inverted retlw 0F7h ; 8 inverted #else ; Original not inverted retlw 1 retlw 2 retlw 4 retlw 8 #endif ; bit 7 decimal point ; bit 6 flash decimal ; bit 5,4 dp location ; bit 3-0 starting digit from bcd buffer getdp addwf PCL,f retlw 03h retlw 03h retlw 03h retlw 03h retlw 94h retlw 0A5h retlw 0C6h retlw 0D7h retlw 0E8h retlw 0F9h dpcap addwf PCL,f retlw 01h retlw 01h retlw 84h retlw 84h retlw 84h retlw 95h retlw 0A6h retlw 0B7h retlw 0C8h retlw 0D9h ; Logic pulser table dpuls addwf PCL,f retlw 170 ; 5 Hz retlw 55 ; 50 Hz retlw 17 ; 500 Hz retlw 5 ; 5000 Hz srq movf temp,w incf temp,f addwf PCL,f ; 9 bits/byte Aprox_ (us_byte-50)/5,4 retlw low 1380 ; 1200 7500 us/byte retlw high 1380 ; 1200 retlw low 685 ; 2400 3750 us/byte retlw high 685 ; 2400 retlw low 338 ; 4800 1875 us/byte retlw high 338 ; 4800 retlw low 161 ; 9600 940 us/byte retlw high 161 ; 9600 retlw low 78 ; 19200 470 us/byte retlw high 78 ; 19200 retlw low 33 ; 38400 230 us/byte retlw high 33 ; 38400 retlw low 20 ; 57600 156 us/byte retlw high 20 ; 57600 retlw low 5 ; 115200 78 us/byte retlw high 5 ; 115200 modes movf temp,w incf temp,f addwf PCL,f vbase retlw 73h ;Prob retlw 50h ; retlw 5ch ; retlw 7ch ; retlw 73h ;PULS retlw 3eh ; retlw 38h ; retlw 6dh ; retlw 3eh ;VOLL retlw 5ch ; retlw 38h ; retlw 38h ; retlw 3eh ;VOLH retlw 5ch ; retlw 38h ; retlw 76h ; retlw 05eh ;diod retlw 4 ; retlw 5ch ; retlw 05eh ; retlw 38h ;L LEdS retlw 79h ;E retlw 05eh ;d retlw 6dh ;S retlw 71h ;FrEq retlw 50h ; retlw 79h ; retlw 6fh ; retlw 0 ; Cnt retlw 39h ; retlw 54h ; retlw 78h ; retlw 0 ; CAP retlw 39h ; retlw 77h ; retlw 73h ; retlw 39h ;CoiL retlw 5ch ; retlw 4 ; retlw 38h ; retlw 0 ; SIG retlw 6dh ; retlw 6 ; retlw 3dh ; retlw 54h ;ntSC retlw 78h ; retlw 6dh ; retlw 39h ; retlw 00h ; SEr retlw 6dh ; retlw 79h ; retlw 50h ; retlw 15h ;Midi retlw 4 ; retlw 5eh ; retlw 4 ; retlw 50h ;r/c.o retlw 52h ; retlw 0D8h ; retlw 5ch ; retlw 50h ;r/c.i retlw 52h ; retlw 0D8h ; retlw 4 ; retlw 08h ;_| |_ retlw 37h ; retlw 08h ; retlw 37h ; retlw 54h ;Nois retlw 5ch ; retlw 4 ; retlw 6dh ; retlw 04h ;ir38 retlw 50h ; retlw 4fh ; retlw 7fh ; retlw 73h ;PWm retlw 2ah ; retlw 15h ; retlw 0 ; retlw 6dh ;STOP retlw 78h retlw 3fh retlw 73h vpuls retlw 0 ; 5 retlw 0 ; retlw 0 ; retlw 6dh ; retlw 0 ; 50 retlw 0 ; retlw 6dh ; retlw 3fh ; retlw 0 ; 500 retlw 6dh ; retlw 3fh ; retlw 3fh ; retlw 0 ; 5.0 retlw 0 ; retlw 0edh ; retlw 3fh ; vbaud retlw 06h ;1200 retlw 5bh ; retlw 3fh ; retlw 3fh ; retlw 5bh ;2400 retlw 66h ; retlw 3fh ; retlw 3fh ; retlw 66h ;4800 retlw 7fh ; retlw 3fh ; retlw 3fh ; retlw 67h ;9600 retlw 7dh ; retlw 3fh ; retlw 3fh ; retlw 00h ; 19.2 (19200) retlw 06h ; retlw 0E7h ; retlw 5bh ; retlw 00h ; 38.4 (38400) retlw 4Fh ; retlw 0FFh ; retlw 66h ; retlw 00h ; 57.6 (57600) retlw 6dh ; retlw 087h ; retlw 7Dh ; retlw 06h ;115.2 (115200) retlw 06h ; retlw 0Edh ; retlw 5bh ; ; execute routine as selected from menu ============================= exec movf mode,w addwf PCL,f goto lp1 ;logic probe goto pulse ;logic pulser goto volt ;voltmeter 0 - 5.00V goto hivolt ;voltmeter 0 - 25.00V goto diode ;diode voltage goto LEDs ;voltage across a LED goto fcount ;frequency count goto dcount ;event count goto cap ;cap meter goto induct ;inductance meter goto sig ;signal generator goto vgen ;video generator goto serial ;serial out goto midi ;midi out goto radcon ;servo pulse generator goto servoi ;servo pulse measure goto square ;square wave goto noise ;digital noise goto ir38 ;38 kHz test signal goto pwm ;variable pulse width goto stop ;stop watch function start bsf STATUS,5 movlw b'00111111' movwf TRISA movlw 0 movwf TRISB movlw b'10110000' movwf TRISC movlw b'10001000' movwf OPTION_REG bcf STATUS,5 movlw 4 movwf T2CON clrf segmask bsf segmask,0 clrf dignr call getset ;restore current mode ;line 513 call signon ;line 561 movlw low 1000 movwf freq movlw high 1000 movwf freq+1 movlw 48 movwf pwmp ; menu selection of operational modes ================================ cycmode call putset ;save all parameters cycle bcf INTCON,GIE movf mode,w call setmode ;load segment menu data c2 call segout ;run display movlw 5 call delay ;line 1702 btfsc BUT1 ;still held down? goto c4 ;no btfss BUT2 goto c2 c5 call segout movlw 5 call delay ;line 1702 btfsc BUT1 goto doexec btfsc BUT2 goto c5 decf mode,f movlw MAXMODE-1 btfsc mode,7 ;underflow? movwf mode goto cycle c4 call segout movlw 5 call delay ;line 1702 btfsc BUT2 goto doexec ;both buttons up - execute btfsc BUT1 goto c4 incf mode,f movf mode,w xorlw MAXMODE btfsc STATUS,Z clrf mode goto cycle doexec call putset ;first, save op mode call clreg goto exec clreg bsf STATUS,RP0 ;Select BANK1 for TRIS registers bsf R20 ;then clear all lines bsf R100 bsf R470 bsf R150 bsf R10K bsf R10KA bsf R100K bsf CLAMP movlw 6 movwf ADCON1 bcf STATUS,RP0 ;select BANK0 return ; save current setup in eeprom ======================================= putopt btfss SAVE ;flagged for save? return ;no. bcf SAVE ;yes. putset clrf hi clrf lo movf mode,w call eewrite ;save current mode in eeprom incf lo,f movf pmode,w call eewrite incf lo,f movf midic,w call eewrite incf lo,f movf baud,w call eewrite return ; get op mode from eeprom ============================================ getset ;from line 415 clrf hi clrf lo call eeread movwf mode movf mode,w addlw -MAXMODE btfsc STATUS,C clrf mode ;restore incf lo,f ;next location call eeread movwf pmode ;pulse mode movf pmode,w addlw -4 btfsc STATUS,C clrf pmode incf lo,f call eeread movwf midic addlw -15 btfsc STATUS,C clrf midic incf lo,f ;next location call eeread movwf baud ;pulse mode movf baud,w addlw -4 btfsc STATUS,C clrf baud return ; put mode text on 4 char display ==================================== setmode movwf temp bcf STATUS,C rlf temp,f rlf temp,f call modes movwf digits call modes movwf digits+1 call modes movwf digits+2 call modes movwf digits+3 return ; show version nr and op mode at startup ============================= signon ;from line 416 movlw VERS call wtod ;put version nr ;to line 1397 movlw 0 ;blank. movwf digits call sign ;line 573 movf mode,w call setmode call sign ;line 573 return sign movlw .30 ;added 23-6-2011 movwf temp x1 call segout movlw 5 ;Changed V36 was .12 call delay ;line 1702 decfsz count,f goto x1 decfsz temp,f goto x1 return ; PWM interrupt handler ============================================== pwmi bcf INTCON,T0IF btfss SWIT goto on bcf SWIT off bcf R20 movf oftime,w movwf TMR0 goto isrx on bsf SWIT bsf R20 movf ontime,w movwf TMR0 goto isrx ; PWM control routine ================================================ pwm bsf STATUS,RP0 ;Select BANK1 for TRIS register bcf R20 ;Set R20 = output movlw b'10000010' ;/32 TMR0 movwf OPTION_REG bcf STATUS,RP0 ;Select BANK0 movlw 0 movwf isrvec ;set interrupt re-vector bsf INTCON,T0IE bsf INTCON,GIE p2 movf pwmp,w addlw 2 call wtod movf pwmp,w sublw 0 movwf ontime movf pwmp,w sublw 96 sublw 0 movwf oftime p4 movlw 5 call delay ;line 1702 call segout movlw 5 call delay ;line 1702 call segout decfsz timer,f goto p4 movlw 25 movwf timer p3 movlw 5 call delay ;line 1702 call segout btfss BUT1 goto dn btfss BUT2 goto up clrf timer goto p3 dn btfss BUT2 goto cycle decfsz pwmp,f decf pwmp,f incf pwmp,f goto p2 up btfss BUT1 goto cycle incf pwmp,f movf pwmp,w xorlw 96 btfsc STATUS,Z decf pwmp,f goto p2 ; IR38 Routine ======================================================= ir38 bsf STATUS,RP0 ;Select BANK1 for TRIS register bcf R20 ;Set R20 = output bcf STATUS,RP0 ;Select BANK0 ir2 call brst movlw 5 movwf count ir4 call segout movlw 5 ;9 call delay ;line 1702 decfsz count,f goto ir4 call segoff btfsc BUT1 goto ir2 btfsc BUT2 goto ir2 goto cycle brst movlw 38 movwf count b2 bsf R20 movlw 20 movwf dela b3 decfsz dela,f goto b3 nop nop nop bcf R20 movlw 20 movwf dela b5 decfsz dela,f goto b5 nop decfsz count,f goto b2 return ; 20 kHz digital noise @20MHz ======================================== noise bsf STATUS,RP0 ;Select BANK1 for TRIS register bcf R20 ;Set R20 = output bcf STATUS,RP0 ;Select BANK0 movlw 55h movwf rand n2 call pseudo btfsc rand,0 bsf R20 btfss rand,0 bcf R20 call segout movlw 65 movwf dela n4 decfsz dela,f goto n4 btfsc BUT2 goto n2 btfsc BUT1 goto n2 goto cycle pseudo movf rand,w addwf rand+1,w movwf rand+1 addwf rand+2,w movwf rand+2 bcf STATUS,C ;do 8 bit rotate rrf rand,f btfsc STATUS,C bsf rand,7 addwf rand,f return ; pulse width generation @20MHz ====================================== radcon bsf STATUS,RP0 ;Select BANK1 for TRIS register bcf R20 ;Set R20 = output bcf STATUS,RP0 ;Select BANK0 movlw low 1500 movwf timer movlw high 1500 movwf timer+1 rc1 movf timer,w movwf acc movf timer+1,w movwf acc+1 clrf acc+2 clrf acc+3 call b2bcd call format rc2 movlw 50 movwf count rc3 call segout movlw 10 call delay ;line 1702 decfsz count,f goto rc3 movf timer,w movwf lo movf timer+1,w movwf hi call segoff call rcpls btfss BUT1 goto rcdn btfss BUT2 goto rcup goto rc2 rcup btfss BUT1 goto cycle rcup2 movlw 10 addwf timer,f btfsc STATUS,C incf timer+1,f movf timer+1,w xorlw 9 btfsc STATUS,Z goto rcdn2 goto rc1 rcdn btfss BUT2 goto cycle rcdn2 movlw -10 addwf timer,f btfss STATUS,C decf timer+1,f movf timer+1,w xorlw 2 btfsc STATUS,Z goto rcup2 goto rc1 rcpls incf hi,f incf lo,f bsf R20 rc4 nop nop rc5 decfsz lo,f goto rc4 decfsz hi,f goto rc5 bcf R20 return ; servo input (pulse width measure) precise machine cycle count used !! ==== servoi bsf STATUS,RP0 ;Select BANK1 for TRIS register bsf CLAMP ;CLAMP = input bsf R10K ;no extra voltage = input bsf R150 ;disconnect other 10k = input bcf R100K ;use 100k pulldown = output bsf R20 ;Pulse input movlw 6 movwf ADCON1 ;all ra is digital bcf STATUS,RP0 ;Select BANK0 bcf R100K ;pull down lightly servo1 call show2 ;short delay and run display btfsc R20 ;check direct input goto servo4 ;wait R20 low servo2 ;not display data in this loop!! call segout btfss BUT1 goto servo4 ;button anti freeze btfss BUT2 goto servo4 ;button anti freeze btfss R20 ;check direct input goto servo2 ;wait R20 high clrf acc ;clear count at start clrf acc+1 clrf acc+2 clrf acc+3 nop nop nop goto servo6 servoHa nop servoHb nop servoHc ; loop 3+(3*13) processor cycles nop ; movlw 13 ;if not call segout movlw 3 movwf bitcnt ; used in math!! call segout ;run display_ 30 machine cycles servo_dh decfsz bitcnt,f goto servo_dh servo6 btfss R20 ;check direct input goto r20low movlw 10 ;inc acc in 10 units (10us) addwf acc,f btfss STATUS,C goto servoHa incfsz acc+1,f ; 24 bit count = 16,7seg goto servoHb incfsz acc+2,f goto servoHc ; total 10us constant r20low clrf xacc ;clear count at start clrf xacc+1 clrf xacc+2 clrf xacc+3 nop movlw 11 movwf bitcnt ; used in math!! goto servo_dl servoLa nop servoLb nop servoLc nop ; loop 3+(3*13) processor cycles ; movlw 13 ;if not call segout movlw 3 movwf bitcnt ; used in math!! call segout ;run display_ 30 machine cycles servo_dl decfsz bitcnt,f goto servo_dl btfsc R20 ;check direct input goto r20high movlw 10 ;inc acc in 10 units (10us) addwf xacc,f btfss STATUS,C goto servoLa incfsz xacc+1,f goto servoLb incfsz xacc+2,f goto servoLc ; total 10us constant r20high btfss MED_L ;show high or low goto ser_sh ;show high call xfer ;show low call b2bcd call format ;show 4 digits call flash ;add decimal point call segout ;run display_ 30 machine cycles ; call show2 goto servo4 ser_sh call b2bcd call format ;show 4 digits call flash ;add decimal point call segout ;run display_ 30 machine cycles ; call show2 servo4 btfsc BUT1 goto servo5 ;But1 bcf MED_L ;set show high clrf digits clrf digits+1 clrf digits+2 movlw 76h ;'H' movwf digits+3 call segout btfss BUT2 goto cycle servo5 btfsc BUT2 goto servo1 bsf MED_L ;set show low clrf digits clrf digits+1 clrf digits+2 movlw 38h ;'L' movwf digits+3 call segout btfss BUT1 goto cycle goto servo1 return ; Square wave interrupt handler ====================================== sqri bcf INTCON,T0IF movf freq,w addwf timer,f movf freq+1,w btfsc STATUS,C incfsz freq+1,w addwf timer+1,f btfss timer+1,7 bcf R20 btfsc timer+1,7 bsf R20 movlw -73 addwf TMR0,f goto isrx ; linear squarewave generation @20MHz ================================ square bsf STATUS,RP0 ;Select BANK1 for TRIS register bcf R20 ;set R20 = output movlw b'10001000' movwf OPTION_REG ;/32 clock bcf STATUS,RP0 ;Select BANK0 movlw 1 movwf isrvec bsf INTCON,GIE bsf INTCON,T0IE ;timer-0 interrupt on sqhl movf freq,w movwf acc movf freq+1,w movwf acc+1 clrf acc+2 clrf acc+3 call b2bcd call format sq2 movf rate,w movwf count sqs1 call segout movlw 5 call delay ;line 1702 decfsz count,f goto sqs1 movlw -5 addwf rate,f movf rate,w addlw -5 btfsc STATUS,C goto sq4 movlw 6 movwf rate sq4 btfss BUT1 goto sqdn btfss BUT2 goto squp clrf rate goto sq2 squp btfss BUT1 goto cycle incf freq,f btfsc STATUS,Z incf freq+1,f goto sqhl sqdn btfss BUT2 goto cycle movlw -1 addwf freq,f btfss STATUS,C decf freq+1,f btfss freq+1,7 goto sqhl clrf freq clrf freq+1 goto sqhl ; logic pulser ======================================================= pulse bsf STATUS,RP0 ;Select BANK1 for ADCON1 register movlw 6 movwf ADCON1 ;all digital on ra bcf STATUS,RP0 ;Select BANK0 ppp2 movf pmode,w ;get pulse mode addlw (vpuls-vbase)/4 ;NOTE_ = (vpuls-vbase)/4 in this assember call setmode movf pmode,w ;now, get delay factor call dpuls movwf timer goto ppp3 ppp5 bsf STATUS,RP0 bcf R20 ;activate pulse nop bsf R20 ;end of pulse bcf STATUS,RP0 bsf digits,6 ;show pulse is active goto ppp8 ppp3 bsf R20 ;set latch to low. btfsc R470 ;which way to pulse? bcf R20 ;then set latch to high. movlw 8 ;low level detected? btfsc R20 movlw 1 ;no - show high movwf digits ;in 1st display ppp8 movf timer,w call delsq ;delay w/display movlw 2 call delsq ;adjust for hi end error btfsc BUT1 goto ppp4 ;no button 1. btfsc BUT2 goto ppp5 ;but 1 only - do pulses goto cycmode ;exit to menu. ppp4 btfsc BUT2 ;only button 2 ? goto ppp3 ;no - set pulse direction ppp4x movlw 5 call delay ;line 1702 call blank call segout btfss BUT1 ;exit? goto cycmode ;yes - and save params btfss BUT2 goto ppp4x incf pmode,f movf pmode,w sublw 3 btfss STATUS,C clrf pmode goto ppp2 ; signal generator (0.5 v square wave) ============================== sig bsf STATUS,RP0 ;Select BANK1 for TRIS register bcf R10K ;engage 10k resistor = output bcf R100K ;engage 100k resistor = output movlw 6 movwf ADCON1 ;all digital on ra bcf STATUS,RP0 ;Select BANK0 bcf R10K ;10k pull to ground bcf R100K ;100k for signal gen clrf digits movlw 5 call digseg movwf digits+1 movlw 0 call digseg movwf digits+2 movwf digits+3 sis3 btfss timer,6 bsf digits,6 bsf R100K call sis8 sis4 incf timer,f btfsc timer,6 bcf digits,6 bcf R100K call sis8 btfsc BUT1 goto sis4 btfsc BUT2 goto sis3 goto cycle sis8 movlw 32 movwf count sis9 call segout ;run diplay movlw 14 call short decfsz count,f goto sis9 return ; do short delays short movwf dela shs2 nop nop nop nop nop decfsz dela,f goto shs2 return ; measure capacitor from tip to ground lead =========================== cap bsf STATUS,RP0 ;Select BANK1 for TRIS register bcf R100K ;enable 100k resistor = output bcf STATUS,RP0 ;Select BANK0 bsf R100K ;pull up resistor bcf R20 ;pull down for clamp bsf HOLD ;default hold condition cac2 call segoff clrf acc ;clear accum clrf acc+1 clrf acc+2 clrf acc+3 bsf STATUS,RP0 ;Select BANK1 for TRIS register bsf R20 ;release clamp R20 = input bcf STATUS,RP0 ;Select BANK0 nop nop ;compensate nop ;for stray nop ;capacitance nop nop cac7 nop ;tune loop with nop's nop nop nop nop nop nop nop nop btfsc R20 ;check direct (a/d) input goto cahit incfsz acc,f goto cac7 incfsz acc+1,f goto cac7 incfsz acc+2,f goto cac7 incfsz acc+3,f goto cac7 cahit bsf STATUS,RP0 ;Select BANK1 for TRIS register bcf R20 ;discharge cap R20 = output bcf STATUS,RP0 ;Select BANK0 call b2bcd call cform ;format for caps cac6 call show2 btfsc BUT1 goto cac6 ;no button - hold reading btfsc BUT2 goto cac2 ;but1 only - do reading goto cycle ; measure inductor from tip to gound lead ============================ induct bsf STATUS,RP0 ;Select BANK1 for TRIS register bcf R100 ;enable 470 ohm resistor = output bcf STATUS,RP0 ;Select BANK0 bcf R100 ;pull up resistor bsf HOLD ;default hold condition inc2 call segoff movlw 80 call delay ;line 1702 clrf acc ;clear accum clrf acc+1 clrf acc+2 clrf acc+3 bsf R100 ;start voltage inc7 nop ;Changed V36 btfss R20 ;check direct (a/d) input goto inhit incfsz acc,f goto inc7 incfsz acc+1,f goto inc7 incfsz acc+2,f goto inc7 incfsz acc+3,f goto inc7 inhit bcf R100 call b2bcd movlw 3 call xform bsf digits+2,7 inc6 call show2 btfsc BUT1 goto inc6 ;no button - hold reading btfsc BUT2 goto inc2 ;but1 only - do reading goto cycle ; turn off all digits segoff #ifdef INVERT_A bsf PORTC,0 ; inverted anodes bsf PORTC,1 bsf PORTC,2 bsf PORTC,3 #else bcf PORTC,0 bcf PORTC,1 bcf PORTC,2 bcf PORTC,3 #endif return ; Logic probe function =============================================== ; show Low, High, and Float w/ Pulse detection lp1 bsf STATUS,RP0 ;Select BANK1 for TRIS register bcf R10K ;turn on voltage feed = output bcf R10KA ;turn on other feed = output movlw b'10101000' ;no prescale on TMR0 movwf OPTION_REG movlw 0Eh ;ana0 on, left justify movwf ADCON1 bcf STATUS,RP0 ;Select BANK0 bsf R10K ;10k pull up bcf R10KA ;10k pull down movlw 81h ;read a/d on RA.0 movwf ADCON0 clrf dp ;no decimal movlw 0ffh movwf TMR0 ;set for single count overflow lpx1 btfsc BUT1 goto lpx2 btfsc BUT2 goto lpx2 goto cycle lpx2 call atod ;read the input movf hi,w ;8 bit value sublw 40 ;low enough for low? btfsc STATUS,C goto lplow movf hi,w sublw 180 btfss STATUS,C goto lphi lpflo movlw 40h ;'-' goto lphl lphi movlw 76h ;'H' goto lphl lplow movlw 38h ;'L' lphl call letter btfss INTCON,T0IF ;counter overflow? goto lpno bcf INTCON,T0IF movlw 0ffh movwf TMR0 ;set for next time clrf timer movlw 73h ;'P' movwf digits+1 ;show pulse detected lpno call show1 incf timer,f movf timer,f btfsc STATUS,Z clrf digits+1 ;always flash off goto lpx1 ; run display for a short time show2 clrf count goto shos2 show1 clrf count bsf count,7 goto shos2 show clrf count bsf count,6 shos2 call segout ;show digits call flash ;add dp movlw 5 ;10 call delay ;line 1702 decfsz count,f goto shos2 return ; show one character and blank other 3 letter movwf digits goto blnk2 blank clrf digits blnk2 clrf digits+1 clrf digits+2 clrf digits+3 return ; show 8 bit value on display wtod ;from 563 movwf acc clrf acc+1 clrf acc+2 clrf acc+3 call b2bcd call format return ; measures diode drop ================================================ ; same as voltmeter but with 5v feed to probe diode bcf HIV ;scale flag 5V bsf STATUS,RP0 ;Select BANK1 for TRIS register bcf R10K ;enable feed resistor = output goto vdx ;otherwise, like voltmeter ; measures voltage across a LED ================================================ ; same as voltmeter but with 5v feed to probe LEDs bcf HIV ;scale flag 5V bsf STATUS,RP0 ;Select BANK1 for TRIS register bcf PORTA,5 ;enable 470R feed resistor = output bcf STATUS,RP0 bsf PORTA,5 goto vdx ;otherwise, like voltmeter ; voltmeter function, 0-25 volts ====================================== hivolt bsf HIV ;scale flag 25V goto vdx ; voltmeter function, 0-5 volts ======================================= volt bcf HIV ;scale flag 5V vdx bsf STATUS,RP0 ;Select BANK1 for ADCON1 register movlw 8Eh ;enable ra.0 analog right justify movwf ADCON1 bcf STATUS,RP0 ;Select BANK0 bsf R10K ;only used for 'diode' mode. movlw 81h ;select ana0 and enable a/d movwf ADCON0 vov2 call atod ;get 10 bits ; bcf STATUS,C ; rrf hi,f ; rrf lo,f ;scale to 9 bits 0-5.11 V call Scale ;scale to 0-5.00 V or 0-25V movf lo,w movwf acc movf hi,w movwf acc+1 clrf acc+2 clrf acc+3 call b2bcd call format bsf digits+1,7 movlw 200 movwf count vov4 call segout movlw 5 ;10 call delay ;line 1702 decfsz count,f goto vov4 btfsc BUT1 goto vov2 btfsc BUT2 goto vov2 goto cycle ; read 16 bit a/d value in hi/low atod bsf ADCON0,2 nop nop adchk btfsc ADCON0,2 ;check for conversion complete goto adchk bsf STATUS,RP0 movf ADRESL,w bcf STATUS,RP0 movwf lo movf ADRESH,w movwf hi return ; count events using TMR0 directly ==================================== dcount bsf STATUS,RP0 ;Select BANK1 for TRIS register bsf CLAMP ;disable clamp = input bcf R10K ;use 10k only = output bsf R150 ;disconnect other 10k = input bsf R100K ;no 100k feed = input bsf R20 ;float direct resistor = input movlw b'10101000' ;no prescale on TMR0 movwf OPTION_REG movlw 6 movwf ADCON1 ;all ra is digital bcf STATUS,RP0 ;;Select BANK0 bsf R10K ;use 10k pullup dcic2 clrf TMR0 ;clear hardware timer clrf xacc ;clear 32bit count clrf xacc+1 clrf xacc+2 clrf xacc+3 dcic3 call xfer call b2bcd movlw 3 dcic5 call xform ;show low 4 digits call segout ;run display call icup ;update counter btfss BUT1 ;button 1 ? goto dcic9 ;no - continue btfss BUT2 goto dcic2 ;reset counting. goto dcic3 ;continue count. dcic9 btfss BUT2 ;both buttons? goto cycle ;yes - exit. call xfer call b2bcd movlw 7 goto dcic5 ; update 32bit count from hardware timer icup movf TMR0,w ;hardware counter to accum movwf xacc btfss INTCON,T0IF ;overflow return ;not yet. bcf INTCON,T0IF incfsz xacc+1,f return incfsz xacc+2,f return incf xacc+3,f return ; move aux count to accum xfer movf xacc,w movwf acc movf xacc+1,w movwf acc+1 movf xacc+2,w movwf acc+2 movf xacc+3,w movwf acc+3 return ; measure frequency using TMR0 with 8-bit prescale =================== fcount bsf STATUS,RP0 ;Select BANK1 for TRIS register bsf CLAMP ;CLAMP = input bsf R10K ;no extra voltage = input bsf R150 ;disconnect other 10k = input bcf R100K ;use 100k pulldown = output bsf R20 ;float direct resistor = input movlw b'10100111' ;256 count prescaler movwf OPTION_REG movlw 6 movwf ADCON1 ;all ra is digital bcf STATUS,RP0 ;Select BANK0 bcf R150 ;pull down lightly clrf acc clrf acc+1 clrf acc+2 clrf acc+3 fcf2 call b2bcd call format btfsc BUT1 goto fcf4 fcf7 btfss BUT2 ;both buttons? goto cycle fcfx movlw 3 call xform fcf4 call cnton call onesec call cntoff goto fcf2 ; clear 32bit count and turn on TMR0 cnton bcf CLAMP clrf TMR0 ;clear timer and prescale clrf acc clrf acc+1 clrf acc+2 clrf acc+3 bsf STATUS,RP0 ;Select BANK1 for TRIS register bsf CLAMP ;tristate the clamp = input bcf STATUS,RP0 ;Select BANK0 return ; turn off counter and pulse input to read out prescale cntoff bcf CLAMP bsf STATUS,RP0 ;Select BANK1 for TRIS register bcf CLAMP ;CLAMP = output bcf STATUS,RP0 ;Select BANK0 movf TMR0,w movwf acc+1 clrf acc cnc2 decf acc,f bsf CLAMP bcf CLAMP movf TMR0,w xorwf acc+1,w btfsc STATUS,Z goto cnc2 return ;--------------------------------------------------------- ; add decimal point to display flash swapf dp,w andlw 3 ;bits 5,4 = digit nr. addlw digits movwf FSR btfsc dp,7 ;decimal used? bsf 0,7 ;light decimal point incf ftimer,f btfsc STATUS,Z incf ftimer+1,f btfss ftimer+1,5 goto fno btfsc dp,6 ;flash mode? bcf 0,7 ;flash back off return fno nop return ; open count gate for exactly 1.000000 second onesec movlw low LPTIME movwf timer movlw high LPTIME movwf timer+1 osx1 nop ;100 cycle loop count nop osx2 call ffill ;time filler call segout ;show last data call flash ;include decimal call dotime ;check for TMR0 overflow decfsz timer,f goto osx1 decfsz timer+1,f goto osx2 movlw 8 movwf timer osx5 call dotime decfsz timer,f goto osx5 return ; just kill some time ffill movlw 16 movwf temp fif2 decfsz temp,f goto fif2 nop nop return ; check for TMR0 rollover ; (constant execution times) dotime btfss INTCON,T0IF ;overflow? goto dno bcf INTCON,T0IF ;clear the flag incf acc+2,f ;increment next byte btfsc STATUS,Z incf acc+3,f ;and next on rollover return dno nop nop nop return ; squared delay function delsq movwf dela+1 movwf dela+2 dlsd1 movf dela+2,w movwf dela dlsd0 call segout decfsz dela,f goto dlsd0 decfsz dela+1,f goto dlsd1 return ; qubic delay function delay movwf dela+2 dld2 movwf dela+1 dld1 movwf dela dld0 decfsz dela,f goto dld0 decfsz dela+1,f goto dld1 decfsz dela+2,f goto dld2 return ; format used for capacitor measurements ; each count = 100pf cform call first movf count,w ;1st non zero call dpcap movwf dp andlw 0fh ;where to start movwf count goto ff5 ; ***** video pattern generation ***** =============================== vgen bsf STATUS,RP0 ;Select BANK1 for TRIS register bcf BLACK ;BLACK = output bcf WHITE ;WHILE = output bcf R100 ;R100 = output bcf STATUS,RP0 ;Select BANK0 bcf R100 #ifdef INVERT_A bsf PORTC,2 ; inverted anodes bsf PORTC,3 #else bcf PORTC,2 bcf PORTC,3 #endif movlw 0BFh movwf PORTB vgv2 call vsync movlw 40 movwf count vc1 nop call bline decfsz count,f goto vc1 movlw 15 movwf count vc2 call dline call dline4 call dline4 call bline4 call bline4 call bline4 call bline4 call bline4 call bline4 call bline4 call bline4 call bline4 call bline4 nop decfsz count,f goto vc2 movlw 17 movwf count vc3 call bline nop decfsz count,f goto vc3 call zline4 btfsc BUT2 goto vgv2 goto cycle vsync movlw 6 movwf count vv2 bcf BLACK call dla10 bsf BLACK movlw 46 call vdela decfsz count,f goto vv2 movlw 6 movwf count vv3 bcf BLACK movlw 46 call vdela bsf BLACK call dla8 decfsz count,f goto vv3 movlw 6 movwf count vv4 bcf BLACK call dla10 bsf BLACK movlw 46 call vdela decfsz count,f goto vv4 return zline4 call dla4 zline bcf BLACK ;start h-sync call dla16 call dla7 bsf BLACK call vseg movlw 89 call vdela nop return bline4 call dla4 bline bcf BLACK ;start h-sync call dla16 call dla7 bsf BLACK movlw 93 call vdela nop return dline4 call dla4 dline bcf BLACK ;start h-sync call dla16 call dla7 bsf BLACK call dla18 call dla18 movlw 19 movwf temp bd2 nop nop nop nop nop nop bsf WHITE nop bcf WHITE decfsz temp,f goto bd2 movlw 5 call vdela return ; delay in processor cycles (includes call/return) dla18 nop dla17 nop dla16 nop dla15 nop dla14 nop dla13 nop dla12 nop dla11 nop dla10 nop dla9 nop dla8 nop dla7 nop dla6 nop dla5 nop dla4 return vdela movwf temp vd2 decfsz temp,f goto vd2 return ; light alternate digits (12 ct) vseg incf frame,f ;count frames #ifdef INVERT_A bsf PORTC,0 ; inverted anodes bsf PORTC,1 btfss frame,0 bcf PORTC,0 btfsc frame,0 bcf PORTC,1 #else bcf PORTC,0 bcf PORTC,1 btfss frame,0 bsf PORTC,0 btfsc frame,0 bsf PORTC,1 #endif nop return ; **** end video gen ***** ================================================ ; turn off displays clear #ifdef INVERT_A movlw 0Fh ; inverted anodes iorwf PORTC,f #else movlw 0F0h andwf PORTC,f #endif return ; cycle thru individual segment drives on 4 digits ; (constant execution time_ 30 instructions) ; ************** Do Not Modify ******************* segout #ifdef INVERT_A movlw 00Fh iorwf PORTC,f ;inverted anodes set low 4 bits #else movlw 0F0h andwf PORTC,f ;clear low 4 bits #endif movf dignr,w ;get digit nr addlw digits ;base of segment list movwf FSR movf 0,w ;get the data andwf segmask,w ;mask the bit xorlw 0ffh ;invert movwf PORTB ;one possible segment line low movf dignr,w call getano #ifdef INVERT_A andwf PORTC,f ; inverted anodes set one high inverted #else iorwf PORTC,f ; set one high. #endif bcf STATUS,C rlf segmask,f btfsc STATUS,C goto nseg nop nop nop nop nop return nseg bsf segmask,0 ;rotate incf dignr,f btfsc dignr,2 ;overflow? clrf dignr bak return ; display digits from specified position xform movwf count goto ff5 ; format first 4 signifcant digits on display format call first ;find 1st non-zero digit ffx movf count,w call getdp ;get formating info movwf dp andlw 0fh movwf count ff5 call ff9 ;get segment pattern movwf digits call ff9 movwf digits+1 call ff9 movwf digits+2 call ff9 movwf digits+3 return ff9 movf count,w decf count,f call getbd ;get bcd value call digseg return ; set count to 1st non zero digit first movlw 9 ;start w/last digit movwf count ff2 movf count,w ;get next digit call getbd xorlw 0 ;set z flag btfss STATUS,Z return ;hit non zero decfsz count,f goto ff2 return ; get bcd digit specified by 'w' getbd movwf temp ;save digit nr clrw btfsc temp,7 ;negative value? return ;zero if negative. bcf STATUS,C rrf temp,f ;find buffer offset movf temp,w rlf temp,f ;restore all bits addlw bcd ;add start of bcd buff movwf FSR ;set pointer movf 0,w ;get the byte movwf ddata ;and store it. btfsc temp,0 ;low or hi nibble? swapf ddata,f ;hi. movf ddata,w andlw 0fh return ; Convert 32-bit binary number at into a bcd number ; at . Uses Mike Keitz's procedure for handling bcd ; adjust; Modified Microchip AN526 for 32-bits. b2bcd movlw 32 ; 32-bits movwf ii ; make cycle counter clrf bcd ; clear result area clrf bcd+1 clrf bcd+2 clrf bcd+3 clrf bcd+4 b2bcd2 movlw bcd ; make pointer movwf FSR movlw 5 movwf cnt ; Mike's routine_ b2bcd3 movlw 33h addwf 0,f ; add to both nybbles btfsc 0,3 ; test if low result > 7 andlw 0f0h ; low result >7 so take the 3 out btfsc 0,7 ; test if high result > 7 andlw 0fh ; high result > 7 so ok subwf 0,f ; any results <= 7, subtract back incf FSR,f ; point to next decfsz cnt,f goto b2bcd3 rlf acc+0,f ; get another bit rlf acc+1,f rlf acc+2,f rlf acc+3,f rlf bcd+0,f ; put it into bcd rlf bcd+1,f rlf bcd+2,f rlf bcd+3,f rlf bcd+4,f decfsz ii,f ; all done? goto b2bcd2 ; no, loop return ; read data 'w' at address hi/low eeread bcf STATUS,RP0 bsf STATUS,RP1 ;bank-2 movf lo,w movwf EEADR movf hi,w movwf EEADRH bsf STATUS,RP0 ;bank-3 bcf EECON1,EEPGD ;access data memory bsf EECON1,RD ;start the read bcf STATUS,RP0 ;bank-2 movf EEDATA,w bcf STATUS,RP1 bcf STATUS,RP0 return ; write data 'w' at address hi/low eewrite bcf STATUS,RP0 bsf STATUS,RP1 ;bank-2 movwf EEDATA ;set data movf lo,w movwf EEADR ;set address movf hi,w movwf EEADRH bsf STATUS,RP0 ;bank-3 bcf EECON1,EEPGD ;access data memory bsf EECON1,WREN ;start write operation movlw 55h movwf EECON2 movlw 0AAh movwf EECON2 bsf EECON1,WR nop nop ee2 btfsc EECON1,WR ;wait for complete goto ee2 bcf STATUS,RP0 bcf STATUS,RP1 return ; Serial signal generator ================================================ serial call clear bsf STATUS,RP0 ;Select BANK1 for TRIS register bsf SOUT ;set to input bcf STATUS,RP0 ;Select BANK0 movf baud,w movwf temp bcf STATUS,C rlf temp,f call srq ;get low byte movwf qtime call srq movwf qtime+1 movlw (vbaud-vbase)/4 addwf baud,w call setmode ss5 call segout btfss BUT2 goto ss8 btfsc BUT1 goto ss5 btfss BUT2 goto cycle call setdir movlw 'A' ; 55h TEST movwf sdata movlw 26 movwf scount ss2 movf sdata,w call serout incf sdata,f ; TEST movlw 43 call delsq decfsz scount,f goto ss2 movlw 13 call serout movlw 100 call delsq movlw 10 call serout movlw 220 call delsq btfss BUT1 ;still held down? goto ss5 ;repeat operation. goto serial ss8 call clear ;blank display movlw 20 call delay ;line 1702 btfss BUT1 goto cycle btfss BUT2 goto ss8 incf baud,f ; bcf baud,2 ;limit 0-3 movf baud,w xorlw MAXBAUD ; limit 0-MAXBAUD (8) btfsc STATUS,Z clrf baud bsf SAVE goto serial ; Midi note generator ================================================ midi movf midic,w addlw 1 ;convert to midi number call wtod movlw 39h ;'C' movwf digits movlw 76h ;'H' movwf digits+1 bsf STATUS,RP0 ;Select BANK1 for TRIS register bsf SOUT ;set to input bcf STATUS,RP0 ;Select BANK0 ms5 call segout btfss BUT2 goto madj btfsc BUT1 goto ms5 call setdir movlw 45 ;31250 baud, may be 44 movwf qtime clrf qtime+1 movf midic,w ;get midi chan nr. iorlw 90h ;add note on command. call serout ;note on movlw 60 call serout ;middle C movlw 40 call serout ;velocity ms6 movlw 20 call delsq btfss BUT1 ;wait for button release goto ms6 movf midic,w iorlw 90h call serout movlw 60 call serout movlw 0 call serout ;send note off call putopt ;maybe save channel movlw 250 call delsq goto midi madj movlw 100 call delsq btfss BUT1 goto cycle btfss BUT2 goto madj bsf SAVE ;flag for saving new channel incf midic,f ;next midi channel movlw 0fh andwf midic,f ;roll over at 15 goto midi ; check for current state setdir bcf DIR ;check for resting state btfss SOUT bsf DIR bsf STATUS,RP0 ;Select BANK1 for TRIS register bcf SOUT ;set to output bcf STATUS,RP0 ;Select BANK0 return ; send serial data from outdat serout clrf count ;bit count bsf count,3 ;count=8 movwf ddata call zero ;start bit sers2 call full btfsc ddata,0 call one btfss ddata,0 call zero rrf ddata,f decfsz count,f goto sers2 call full call one call full call full call full retlw 00 zero btfss DIR ;which way is up? bcf SOUT btfsc DIR bsf SOUT retlw 00 one btfss DIR ;which way is up? bsf SOUT btfsc DIR bcf SOUT retlw 00 full movf qtime+1,w movwf temp+1 movf qtime,w movwf temp incf temp+1,f incf temp,f ff3 decfsz temp,f goto ff3 decfsz temp+1,f goto ff3 retlw 00 ; Stopwatch funcion ; Button 1_ start/stop; probe change_ start/stop ; Button 2_ reset stop bsf STATUS,5 bcf R10K ;select 10k bcf STATUS,5 bcf R10k ;10k to ground movlw 1 movwf T1CON ; Wait for a start condition _clr call clear call clrxac ;clear accum call disp ;set up for display call flip ;init the probe tip _wait call segdel call flip ;change on tip? btfss status,z goto _run ;yes. btfsc BUT1 ;button 1 ? goto _two ;no - wait btfsc BUT2 ;but 2 ? goto _start ;no - begin count goto cycle ;yes - exit. _two btfsc BUT2 ;only button 2 ? goto _wait goto _clr ;reset on 2 only. ; Run until stop condition _start call _next ;count time call _next call _next ;debounce but 1 call _next _s3 call _next btfss BUT1 ;hit but 1? goto _s3 ;but 1 still down? _run call _next ;count time call flip ;probe tip changed? btfss status,z goto _done ;yes. btfsc BUT1 ;hit but 1 ? goto _run ;keep running _done call segdel btfsc BUT2 ;reset? goto _done ;no. goto _clr ;yes _next call segdel btfss PIR1,0 ;TMR1IF,0 ;overflow? goto _next ;not yet. call clear ;all segs off bcf PIR1,0 ;TMR1IF ;clear the flag. movlw 0 ;-50000> ;reset the timer movwf TMR1L movlw 0 ;-50000< movwf TMR1H ;set timer 1 to -50000 call disp call incxac ;count movf place,w addlw -4 btfss status,c bsf digits+1,7 btfsc status,z bsf digits+2,7 retlw 0 ; look for state change on probe tip flip movf port_temp,w ;last port data movwf temp ;save it movf porta,w ;read port a movwf port_temp ;for next time. xorwf temp,w ;compare to last value andlw 1 ;ra0 only btfsc status,z retlw 00 ;return nz = change. disp call xfer call b2bcd call format retlw 00 segdel call segout movlw 5 goto delay ; increment the 32bit accumulator incxac incf xacc,1 btfss status,z retlw 00 incf xacc+1,1 btfss status,z retlw 00 incf xacc+2,1 btfss status,z retlw 00 incf xacc+3,1 btfss status,z retlw 00 ; clear the 32bit accumulator clrxac clrf xacc ;clear 32bit count clrf xacc+1 clrf xacc+2 clrf xacc+3 retlw 00 ;===================================================================== ; SCALE multiply by 500 and divide by 1023 if HIV is reset ; multiply by 100 and divide by 1023 if HIV is set ; input= hi_lo output hi_lo ;===================================================================== Scale btfsc HIV ;flag clear scale=5V? goto scal25 ;yes scale = 25V ; multiply by 500 movlw high 500 movwf acc+0 movlw low 500 movwf acc+1 goto scal1 scal25 ; multiply by 2500 movlw high 2500 movwf acc+0 movlw low 2500 movwf acc+1 scal1 call mul16_16 ;call multiply, acc0_2*hi_lo=acc0_3 ; now divide by 1023 movlw high 1023 movwf hi movlw low 1023 movwf lo call div32_16 ;call divide, acc0_3/hi_lo=acc2_3 movf acc+2,w movwf hi movf acc+3,w movwf lo return ;***************************************************************************************** ; PIC16 fast unsigned multiply routines by Jim Bixby, bix@san.rr.com ; ; Unsigned multiply routine ; Multiplies of any size can easily be made from the macros - for this code, only MUL16X16 ; is made ; ; The approach here is linear code for speed at the expense of RAM and registers ; Adapted from _ http_//www.piclist.org/techref/microchip/math/mul/8x8u.htm ;***************************************************************************************** ; Add16AB macro - add AH_AL to BH_BL, result goes to BH_BL Add16AB MACRO AH,AL,BH,BL movf AL,w addwf BL,f movf AH,w btfsc STATUS,C incfsz AH,w addwf BH,f ENDM ;***************************************************************************************** ; Macro for adding & right shifting - used once per bit by mulmac mult MACRO bit,A,H,L ;A=multiplier,H_L=result, other arg in W btfsc A,bit addwf H,f rrf H,f rrf L,f ENDM ; End of macro ;***************************************************************************************** ; 8x8-->16 multiply macro A * B --> H_L ; Invokes mult macro above mulmac MACRO A,B,H,L ; H_L = A*B clrf H clrf L movf B,W ; move the multiplicand to W reg. bcf STATUS,C ; Clear the carry bit in the status Reg. mult 0,A,H,L mult 1,A,H,L mult 2,A,H,L mult 3,A,H,L mult 4,A,H,L mult 5,A,H,L mult 6,A,H,L mult 7,A,H,L ENDM ; NOEXPAND ;***************************************************************************************** ; mul16_16 ; acc+0_1 * hi_1 --> acc+0_3 ; ARG0=Msb, ARG3=Lsb ; Invokes the three macros above ; 164 prog words, 168 inst cycles, 10 registers (6 for call/return arguments + 4) ; Uses xacc+0_3 also. hi_1 unchanged on return ;***************************************************************************************** mul16_16 ; 32 bit result is first calculated into T0_T1_A2_A3 ; When done, T0_1 is moved to A0_1 so the final result is in A0_3 ; Register names can be changed at will, and any register can be located ; anywhere - order is not important. mulmac acc+0, hi, xacc+0, xacc+1 ;T0_1 <--A0*B0 mulmac acc+1, lo, acc+2, acc+3 ;A2_3 <--A1*B1 mulmac acc+1, hi, xacc+2, xacc+3 ;T2_3 <--A1*B0 Add16AB xacc+2, xacc+3, xacc+1, acc+2 ; Add T2_3 to T1_A2, carry into T0 btfsc STATUS,C ; nb_ this relies on the _C bit being incf xacc+0,f ; correct after the Add16AB macro mulmac acc+0, lo, xacc+2, xacc+3 ;T2_3 <--A0*B1 Add16AB xacc+2, xacc+3, xacc+1, acc+2 ; Add T2_3 to T1_A2, carry into T0 btfsc STATUS,C incf xacc+0,f movf xacc+1,w ;Move T0_1 to A0_1 movwf acc+1 ;to finish movf xacc+0,w movwf acc+0 return EXPAND ;********************************************************************************************** ; PIC16 unsigned 32 by 16 divide routines by Peter Hemsley ; acc+0_3 / hi_1 --> acc+2_3 ; acc+0=Msb, acc+3=Lsb ; xacc+0_1 quotient ; hi_1 unchanged on return ;********************************************************************************************** div32_16 movlw 32 ; 32-bit divide by 16-bit movwf bitcnt clrf xacc+0 ; Clear remainder (high) clrf xacc+1 ; (low) dvloop clrc ; Set quotient bit to 0 ; Shift left dividend and quotient rlf acc+3,f ; lsb rlf acc+2,f rlf acc+1,f rlf acc+0,f ; lsb into carry rlf xacc+1,f ; and then into partial remainder rlf xacc+0,f skpnc ; Check for overflow goto subd movf hi,w ; Compare partial remainder and divisor (high) subwf xacc+0,w skpz goto testgt ; Not equal so test if remdrH is greater movf lo,w ; High bytes are equal, compare low bytes (low) subwf xacc+1,w testgt skpc ; Carry set if remdr >= divis goto remrlt subd movf lo,w ; Subtract divisor from partial remainder subwf xacc+1,f skpc ; Test for borrow decf xacc+0,f ; Subtract borrow movf hi,w subwf xacc+0,f bsf acc+3,0 ; Set quotient bit to 1 ; Quotient replaces dividend which is lost remrlt decfsz bitcnt,f goto dvloop return end