;
;	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
; 44  Ported to pic16f876a, added option for Common-Cathode display - by KPL

#define INVERT_A	; invert common pins of a display
#define INVERT_SEG      ; invert segment pins of a display

;	list      p=16f870A             ; list directive to define processor
	list      p=16f876A             ; list directive to define processor
;	#include <p16f870.inc>         ; processor specific variable definitions
	#include P16F876A.INC         ; 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	 	044 			;Version to display

#define LPTIME	 	42990   ;calibration time for counter

#define MAXMODE	 	21			;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
	bcf	INTCON,TMR0IF
	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,TMR0IE
	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
	bcf	INTCON,TMR0IF
	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
	bsf	INTCON,TMR0IE	;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?
	btfss	INTCON,TMR0IF ;counter overflow?
	goto	lpno
;	bcf	INTCON,T0IF
	bcf	INTCON,TMR0IF
	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
	btfss	INTCON,TMR0IF	;overflow
	return						;not yet.
;	bcf	INTCON,T0IF
	bcf	INTCON,TMR0IF
	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?
	btfss	INTCON,TMR0IF	;overflow?
	goto	dno
;	bcf	INTCON,T0IF	;clear the flag
	bcf	INTCON,TMR0IF	;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	
#ifdef INVERT_SEG
	movlw	! 0BFh
#else
	movlw	0BFh
#endif
	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
#ifdef INVERT_SEG
;	xorlw	0ffh		;invert
#else
	xorlw	0ffh		;invert
#endif
	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 <acc> into a bcd number
; at <bcd>. 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 <unknown>_ 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