; Base 16F87x Program
;	By David V. Fansler
;		2604 Northstream Court
;		Haw River, NC  27258
;		336-578-3028
;		dfansler@mindspring.com
;
;		Created: Oct 28, 2002
;		Last Updated:Nov 9, 2002
;
;		This program is designed to be the base program for the 16F87x
;		series of PIC processors.  It sets up the Interrupts for the serial
;		port (19.2k-8-n-1), Timer0 for a 5ms interrupt
;
;
;
;		PIC16F873 Device Info
;			Reset starts execution at locaion 0000h
;			Interrupts will start execution at the address location
;				provided at address 0004h.
;			Program memory is:
;					Page 0  0005h - 07ffh
;					Page 1  0800h - 0fffh
;
;			Data Memory is in 4 banks, addressed by RP1:RP0.  Each bank
;				is 128 bytes long with the lower locations of each bank
;				reserved for Special Functionn Registers.
;				Bank 0 00h-1fh SFR, 20h - 7fh GPR
;				Bank 1 80h-9fh SFR, a0h - ffh GPR  Locations f0h-ffh can
;					be addresses at 70h-7fh.
;				Bank 2 100h-17fh SFR, 120h - 17fh GPR  Locations 170h-17fh can
;					be addresses at 70h-7fh.
;				Bank 3 180h-19fh SFR, 1f0h - 1ffh GPR  Locations 1f0h-1ffh can
;					be addresses at 70h-7fh.
;
;	Configuration Word
;		Bit 0 - 0	HS Oscillator
;		Bit 1 - 1	HS Oscillator
;		Bit 2 - 0	WDT disabled
;		Bit 3 - 0	Power-up Timer Enabled
;		Bit 4 - CP0
;		Bit 5 - CP1
;		Bit 6 - 0 	Brown-out Reset diabled
;		Bit 7 - 0	In-circuit Programming disabled
;		Bit 8 - 1 	Data EEPROM code protection off
;		Bit 9 - 1	Can not write to unprotected program memory
;		Bit 10 - 1	Unimplemented
;		Bit 11 - 1	In-circuit debugger disabled
;		Bit 12 - 1 	Code protection off (duplicate in Bit 4)
;		Bit 13 - 1	Code protection off (duplicate in Bit 5)
;
	include 'C:\pictools\16f873.inc'
	FUSES _HS_OSC
	FUSES _WDT_OFF
	FUSES _CP_OFF
;	FUSES _PWRT_OFF
	FUSES _BODEN_OFF
;	FUSES _MCLR_OFF
	FUSES _LVP_OFF

;	DEVICE PIC16F873,HS_OSC, WDT_OFF; PROTECT_OFF,PWRT_ON,BOD_OFF,MCLR_OFF
; ACKDT=5091    ACKEN=4091    ACKSTAT=6091  ADCON0=001F
; ADCON1=009F   ADCS0=601F    ADCS1=701F    ADIE=608C
; ADIF=600C     ADON=001F     ADRES=001E    ADRESH=001E
; BF=0094       BOD_OFF=FFBF  BOD_ON=FFFF   BOR=008E
; BOR_OFF=FFBF  BOR_ON=FFFF   BRGH=2098
; C=0003        CCP1CON=0017  CCP1IE=208C   CCP1IF=200C
; CCP1M0=0017   CCP1M1=1017   CCP1M2=2017   CCP1M3=3017
; CCPR1H=0016   CCPR1L=0015   CCP1X=5017    CCP1Y=4017
; CCP2CON=001D  CCP2IE=008D   CCP2IF=000D   CCP2M0=001D
; CCP2M1=101D   CCP2M2=201D   CCP2M3=301D   CCP2X=501D
; CCP2Y=401D    CCPR2H=001C   CCPR2L=001B   CHS0=301F
; CHS1=401F     CHS2=501F     CKP=4014      CPD_OFF=FFFF
; CPD_ON=FEFF   CREN=4018     CSRC=7098
; DA=5094       DC=1003       DEBUG_OFF=FFFF  DEBUG_ON=F7FF
; EEADR=010D    EEADRH=010F   EECON1=018C   EECON2=018D
; EEDATA=010C   EEDATH=010E   EEPGD=718C    EERD=018C
; EERESL=009E   EEWR=118C
; FERR=2018     FSR=0004
; GCEN=7091     GIE=700B      GO_DONE=201F
; HS_OSC=FFFE
; IBF=7089      IBOV=5089     INDF=0000     INTCON=000B
; INDIRECT=0000 INTEDG=6081   INTE=400B     INTF=100B
; IRP=7003
; LVP_OFF=FF7F  LVP_ON=FFFF   LP_OSC=FFFC
; OBF=6009      OERR=1018     OPTION=0081
; P=4094        PCFG0=009F    PCFG1=109F    PCFG2=209F
; PCL=0002      PCLATH=000A   PCON=008E     PD=3003
; PIE1=008C     PIE2=008D     PEIE=600B     PEN=2091
; PIR1=000C     PIR2=000D     POR=108E      PORTA=0005
; PORTB=0006    PORTC=0007    PORTD=0008    PORTE=0009
; PR2=0092      PROTECT_HALF=DFDF           PROTECT_OFF=FFFF
; PROTECT_ON=CFCF  PROTECT_1_QTR=EFEF       PS0=0081
; PS1=1081      PS2=2081      PSA=3081      PSPIE=708C
; PSPIF=700C    PSPMODE=4089  PWRT_OFF=FFFF PWRT_ON=FFF7
; RA=0005       RB=0006       RBIE=300B     RBIF=000B
; RBPU=7081     RC=0007       RC89=6018     RCD8=0018
; RCEN=3091     RCIE=508C     RCIF=500C     RCSTA=0018
; RCREG=001A    RC_OSC=FFFF   RD=0008       RE=0009
; RP0=5003      RP1=6003      RSEN=1091     RW=2094
; S=3094        SEN=0091      SPBRG=0099    SPEN=7018
; SREN=5018     SSPADD=0093   SSPBUF=0013   SSPCON=0014
; SSPCON2=0091  SSPEN=5014    SSPIE=308C    SSPIF=300C
; SSPM0=0014    SSPM1=1014    SSPM2=2014    SSPM3=3014
; SSPOV=6014    SSPSTAT=0094  STATUS=0003   SYNC=4098
; T0CS=5081     T0SE=4081     T0IE=500B     T0IF=200B
; T1CKPS0=4010  T1CKPS1=5010  T1CON=0010    T1OSCEN=3010
; T1SYNC=2010   T2CKPS0=0012  T2CKPS1=1012  T2CON=0012
; TMR0=0001     TMR1CS=1010   TMR1IE=008C   TMR1IF=000C
; TMR1H=000F    TMR1L=000E    TMR1ON=0010   TMR2=0011
; TMR2IE=108C   TMR2IF=100C   TMR2ON=2012   TO=4003
; TOUTPS0=3012  TOUTPS1=4012  TOUTPS2=5012  TOUTPS3=6012
; TRISA=0085    TRISB=0086    TRISC=0087    TRISD=0088
; TRISE=0089    TRISE0=0089   TRISE1=1089   TRISE2=2089
; TRMT=1098     TX89=6098     TXD8=0098     TXEN=5098
; TXIE=408C     TXIF=400C     TXREG=0019    TXSTA=0098
; WCOL=7014     WDT_ON=FFFF   WDT_OFF=FFFB  WRERR=318C
; WREN=218C     WRTEN_OFF=FDFF  WRTEN_ON=FFFF
; XT_OSC=FFFD   xUA=1094
; Z=2003
;
;PORT A
;	0 - analog input  - focus speed/direction
;	1 - output - LED OE
;	2 - output - LED CLK
;	3 - output - LED RS
;	4 - output - LED *RST (open drain)
;	5 - output - LED DATA IN
;	6 - (874/877)
;	7 - (874/877)
;
;PORT B
;	0 - Input *Motor Enable
;	1 - Input *LED Brightness
;	2 - Input *Zero
;	3 - Input Motor Opto Channel B
;	4 - Input Gnd
;	5 - Input Gnd
;	6 - Input Gnd
;	7 - Input Motor Opto Channel A
;
;PORT C
;	0 - Output - *Disable Motor
;	1 - Output PWM2 - Motor Reverse
;	2 - Output PWM1 - Motor Forward
;	3 - N/A
;	4 - N/A
;	5 - N/A
;	6 - Output RS232 Tx
;	7 - Input RS232 Rx
;			Ports D & E only available on 874/877
;PORT D
;	0 -
;	1 -
;	2 -
;	3 -
;	4 -
;	5 -
;	6 -
;	7 -
;
;PORT E
;	0 -
;	1 -
;	2 -
ONE_T_HIGH	equ 01h		;high & low byte for constant that is used
ONE_T_LOW	equ 0E0h		;to compare number of pulses to equal .001"
FSR		equ 04h
CR 		equ 0dh		;constant for carriage return
CHAR_OUT_PTR equ 20h		;pointer to character # to output via rs-232 (bank 0)
BUFFER_OUT 	equ 21h		;start of rs-232 output buffer (bank 0)
BUFFER_PTR 	equ 30h		;pointer to rs-232 input buffer (bank 0)
BUFFER_IN 	equ 31h		;start of rs-232 input buffer   (bank 0)
TX_PTR	equ 40h		;pointer for RS-232 transmission
Five_mS_Cont equ 61		;tmr0 constant to load for 5mS
BAUD_CONST 	equ 64		;constant for baud (19.2k high speed)
SPEED		equ 63h		;storage for PWM speed
CNTR		equ 64h		;counter for bcd to binary conversion
BIN_LOW	equ 65h		;storage for bcd to binary conversion
BIN_HIGH	equ 66h		;storage for bcd to binary conversion
MOV_LOW	equ 67h		;storage for distance to move (low byte)
MOV_HIGH	equ 68h		;storage for distance to move (high byte)
AD_ORG	equ 69h		;sotrage for doubled ad value
_232_TEMP	equ 6ah		;storage for 232 conversion
POS_TEMP	equ 6ch		;temp for position storage during display
POS_LOW	equ 6dh		;low two nibbles of ZSF position
POS_HIGH	equ 6eh		;high nibble of ZSF position
LED_TEMP 	equ 6fh		;temp register to store led digit to display
W_TEMP 	equ 70h		;temp register for interrupts
STATUS_TEMP equ 71h		;temp register for interrupts
PCLATH_TEMP equ 72h		;temp register for interrupts
FSR_TEMP	equ 73h		;temp register for interrupts
FLAGS		equ 74h		;flag register
Tmr5ms 	equ 0			;bit 0 5 ms timer flag
AD_FLAG     equ 1			;bit 1 A/D Done Flag
LED_CHANGE  equ 2			;bit 2 need to update display when set
RX		equ 3			;bit 3 valid rx move command
;	      equ 4			;bit 4
;          	equ 5			;bit 5
;		equ 6			;bit 6
;		equ 7			;bit 7
;		equ 74h		;
;		equ 75h		;
TEMP_A 	equ 76h		;temporary storage location
TEMP_B	equ 77h		;temporary register
;		equ 78h		;
PWM_CUR 	equ 79h		;current pwm value
LED_OUT	equ 7ah		;table pointer for led digit
B_TEMP	equ 7bh		;temp storage for reading port B
B_CHNG	equ 7ch		;temp storage during port b change irq
HIGH_CNT	equ 7dh		;pulse counter (high byte)
LOW_CNT	equ 7eh		;pulse counter (low byte)
DEBOUNCE	equ 7fh		;debouce delay storage
EEIF 		equ 400Dh		;define EE interrupt flag
BCLIF 	equ 300dh		;define Bus Collision int flag
PSPIF		equ 700Ch		;define PSP int flag
LED_OE	equ 1005h		;Port A bit 1
LED_CLK	equ 2005h		;Port A bit 2
LED_RS	equ 3005h		;Port A bit 3
LED_RST	equ 4005h		;Port A bit 4
LED_DATA_IN	equ 5005h		;Port A bit 5
MOTOR_ENB	equ 0006h		;Port B bit 0
LED_BRIGHT	equ 1006h		;Port B bit 1
ZERO_CTR	equ 2006h		;Port B bit 2
CH_B		equ 3006h		;Port B bit 3
CH_A		equ 7006h		;Port B bit 7
MOTOR_CHIP_EN equ 0007h		;Port C bit 1

	org 0000
	goto START			;jump to start routine

	org 0004
INT_SRV
	movwf W_TEMP		;copy W to temp register
	swapf status,W		;swap status to be saved into W
	clrf status			;bank 0, regardless of current bank.  Clears IRP, RP1,RP0
	movwf STATUS_TEMP		;save status to bank 0 temp register
	movf pclath,w		;only required if usings pages 1,2 and/or 3
	movwf PCLATH_TEMP		;save pclath into w
	clrf pclath			;page 0 regardless of current page
	movf FSR,W			;get current value of FSR
	movwf FSR_TEMP		;save value of FSR register
		;first check to see who caused the interrupt
	btfsc t0if			;was it timer 0?
	goto ServiceTMR0		;if so then jump
	movf TX_PTR,W		;move character pointer to W
	btfsc Z			;is it 0? if not then jump
	goto INT_SRV_1		;else jump
	btfsc TXIF			;was it TX clear to send?
	goto ServiceTX		;if so then jump
	btfsc rbif			;is it the RB Port change flag
	goto PB_CNG			;if so then jump
	btfsc adif			;was it the a/d int flag
	goto AD_CONV		;of so then jump
	btfsc RCIF			;was it RX input received?
	goto ServiceRX		;if so then jump
INT_SRV_1
	bcf intf			;clear RB0/INT flag
	bcf pspif			;clear parallel slave port int flag
	bcf sspif			;synchronous int flag
	bcf ccp1IF			;clear ccp1 int flag
	bcf tmr2if			;clear tmr2 int flag
	bcf tmr1if			;clear tmr1 int flag
	bcf bclif			;clear bus collision int flag
	bcf ccp2if			;clear ccp2 int flag
	bsf t0ie			;re-enable timer 0
	;
INT_SRV_EXIT
	movf FSR_TEMP,W		;restore FSR
	movwf FSR			;
	movf PCLATH_TEMP,w	;restore pclath
	movwf PCLATH		;move w into pclath
	swapf STATUS_TEMP,w	;swap status_temp register into w
					;(sets bank to original state)
	movwf STATUS		;movew into status register
	swapf W_TEMP,F		;swap w_temp
	swapf W_TEMP,W		;swap w_temp into W
	retfie			;and return from interrupt

START
	bcf rp0			;point to
	bcf rp1			;bank 0
	call INIT_PORTS		;call to setup the ports
	call INIT_IRQ		;call to setup the interrupts
	bcf rp0			;point to
	bcf rp1			;bank 0
	clrf FLAGS			;clear the flag register
	bsf MOTOR_CHIP_EN		;disable motor chip
	movlw 0			;set position counter to +000
	movlw 0			;clear the TX
	movwf TXREG			;
	movwf POS_HIGH		;high and
	movwf POS_LOW		;low byte
	movwf HIGH_CNT		;set pulse counter to 0
	movwf LOW_CNT		;
	bcf LED_CLK			;clear the clock bit
	bcf LED_DATA_IN		;clear the data bit
	bcf LED_RS			;clear the register select bit
	bsf LED_OE			;set the ouput enable bit
	bcf LED_RST			;enable the reset
	movlw 0			;clear the TX
	movwf TXREG			;
	nop				;give a 200ns delay
	bsf LED_RST			;disable the reset
	movlw 31h			;set up Rx buffer pointer
	movwf BUFFER_PTR		;
	call LED_POS		;output to display
	call LED_INIT		;call to initialize the LED display

MAIN
	btfss FLAGS,LED_CHANGE	;if flag set then update display
	goto MAIN_1			;else jump
	call LED_POS		;update display
	bcf FLAGS,LED_CHANGE	;clear flag
MAIN_1
	movf PORTB,W		;read port B
	movwf B_TEMP		;and store
	btfss ZERO_CTR		;is the zero button depressed?
	call ZERO_POS		;if so then call
	btfss LED_BRIGHT		;is the set LED brightness button depressed?
	call SET_BRIGHT		;if so then call
	btfss MOTOR_ENB		;is the motor enable button pushed
	call MOVE			;if so then call
	btfss FLAGS, RX		;if valid RX data then skip next
	goto MAIN			;else loop back
RX_MOVE
	bcf FLAGS, RX		;clear rx data flag
	movlw 34h			;point to .x
	movwf BUFFER_PTR		;
	movwf FSR			;setup indirect addressing
	movf INDF,W			;get .x
	andlw 0fh			;mask off high nibble
	movwf MOV_HIGH		;and store
	incf FSR,1			;point to .0x
	movf INDF,W			;get .0x value
	andlw 0fh			;mask off high nibble
	movwf MOV_LOW		;and store
	swapf MOV_LOW,1		;swap nibbles
	incf FSR,1			;point to .00x
	movf INDF,W			;get .00x value
	andlw 0fh			;mask off high nibble
	iorwf MOV_LOW,1		;OR with high nibble
		;convert from packed BCD to binary
	movlw 0			;zero out the final storage
	movwf BIN_LOW		;low byte
	movwf BIN_HIGH		;high byte
	movf MOV_LOW,W		;get 10:1 into W
	andlw 0fh			;mask off high nibble
	movwf BIN_LOW		;and store
	swapf MOV_LOW,W		;swap nibbles, ,move to W
	andlw 0fh			;mask off high nibble
	movwf CNTR			;and store in counter
	btfsc Z			;if value was not 0 then skip next
	goto BCD_BIN_100		;10's was 0 so jump
ADD_10		;loop while adding 10
	movlw 10			;load 10 into W
	addwf BIN_LOW,F		;add to low byte
	decfsz CNTR			;decrement counter, skip next if 0
	goto ADD_10			;loop back
BCD_BIN_100
	movf MOV_HIGH,W		;get 100s
	btfsc Z			;was it 0?
	goto BCD_BIN_DONE		;if so jump to done
	movwf CNTR			;else move into the counter
ADD_100		;loop while adding 100
	movlw 100			;load 100 into W
	addwf BIN_LOW,F		;add to low byte
	btfss C			;was there a carry?
	goto NO_CARRY		;if not then jump
	incf BIN_HIGH,F		;else increment high byte
NO_CARRY
	decfsz CNTR			;decrement counter,  skip if not 0
	goto ADD_100		;else loop back
	goto BCD_BIN_DONE		;else conversion done so jump

BCD_BIN_DONE
		;check for move distance
	movf BIN_LOW,W		;get the low byte
	sublw 5			;is it greater than 5?
	btfss C			;if so then skip next
	goto HIGH_SPEED		;jump to load high speed move
	movlw 14h			;else load for low speed move
	movwf SPEED			;and store
	goto BB_DONE_1		;and jump
HIGH_SPEED
	movlw 100			;load high speed move
	movwf SPEED			;and store
BB_DONE_1
	movlw 32h			;point to sign
	movwf BUFFER_PTR		;
	movwf FSR			;setup indirect addressing
	movf INDF,W			;get sign
	xorlw '+'			;compare to plus sign
	btfss Z			;if + then skip next
	goto SIGN_MINUS		;else jump
SIGN_PLUS
	movlw 31h			;point to beginning of buffer
	movwf BUFFER_PTR		;
	movf POS_HIGH,W		;get high display byte
	andlw 0f0h			;mask off low nibble
	btfss Z			;if 0 (+) then skip next
	goto MPLUS_DMINUS		;else if display - then jump
	goto MPLUS_DPLUS		;goto move +, display +
SIGN_MINUS
	movlw 31h			;point to beginning of buffer
	movwf BUFFER_PTR		;
	movf POS_HIGH,W		;get high display byte
	andlw 0f0h			;mask off low nibble
	btfss Z			;if 0 (+) then skip next
	goto MMINUS_DMINUS	;else if display - then jump
	goto MMINUS_DPLUS		;goto move -, display +
MPLUS_DPLUS		;move sign +, display + so move out
	movf SPEED,W		;load PWM value
	movwf CCPR2L		;move value into PWM2
	bcf MOTOR_CHIP_EN		;enable motor chip
	goto MONITOR_OUT		;jump to monitor move
MMINUS_DMINUS	;move sign -, display - so move in
	movf SPEED,W		;load PWM value
	movwf CCPR1L		;move value into PWM1
	bcf MOTOR_CHIP_EN		;enable motor chip
	goto MONITOR_IN		;jump to monitor move
MMINUS_DPLUS	;move sign -, display + so move in
	movf SPEED,W		;load PWM value
	movwf CCPR1L		;move value into PWM1
	bcf MOTOR_CHIP_EN		;enable motor chip
	goto MONITOR_IN		;jump to monitor move
MPLUS_DMINUS	;move sign +, display - so move out
	movf SPEED,W		;load PWM value
	movwf CCPR2L		;move value into PWM2
	bcf MOTOR_CHIP_EN		;enable motor chip
	goto MONITOR_OUT		;jump tp monitor move
MONITOR_OUT
	btfss FLAGS,LED_CHANGE	;if flag set then update display
	goto MONITOR_OUT_1	;else jump
	call LED_POS		;update display
	bcf FLAGS,LED_CHANGE	;clear flag
MONITOR_OUT_1
	;check for move distance
	movf BIN_LOW,W		;get the low byte
	sublw 5			;is it greater than 5?
	btfss C			;if so then skip next
	goto MONITOR_OUT_2	;jump to load high speed move
	movlw 14h			;else load for low speed move
	movwf CCPR2L		;move value into PWM2
MONITOR_OUT_2
	movf BIN_LOW, W		;get low binary count
	btfss Z			;is it 0?
	goto MONITOR_OUT		;if not then loop back
	movf BIN_HIGH,W		;get high binary count
	btfss Z			;is it 0?
	goto MONITOR_OUT		;if not then loop back
	bsf MOTOR_CHIP_EN		;disable motor drive
	movlw 0			;turn off PWMs
	movwf CCPR1L		;
	movwf CCPR2L		;
	goto MAIN			;and loop back
MONITOR_IN
	btfss FLAGS,LED_CHANGE	;if flag set then update display
	goto MONITOR_IN_1		;else jump
	call LED_POS		;update display
	bcf FLAGS,LED_CHANGE	;clear flag
MONITOR_IN_1
			;check for move distance
	movf BIN_LOW,W		;get the low byte
	sublw 5			;is it greater than 5?
	btfss C			;if so then skip next
	goto MONITOR_IN_2		;jump to load high speed move
	movlw 14h			;else load for low speed move
	movwf CCPR1L		;move value into PWM2
MONITOR_IN_2
	movf BIN_LOW, W		;get low binary count
	btfss Z			;is it 0?
	goto MONITOR_IN		;if not then loop back
	movf BIN_HIGH,W		;get high binary count
	btfss Z			;is it 0?
	goto MONITOR_IN		;if not then loop back
	bsf MOTOR_CHIP_EN		;disable motor drive
	movlw 0			;turn off PWMs
	movwf CCPR1L		;
	movwf CCPR2L		;
	goto MAIN			;and loop back

ZERO_POS
	bcf rp0			;point to
	bcf rp1			;bank 0
	movlw 0			;set position counter to +000
	movwf POS_HIGH		;high and
	movwf POS_LOW		;low byte
	movwf HIGH_CNT		;set pulse counter to 0
	movwf LOW_CNT		;
	call LED_POS		;then update display
:loop
	movf PORTB,W		;read port B
	movwf B_TEMP		;and store
	btfss ZERO_CTR		;is the zero button depressed?
	goto :loop			;if so then jump
	movlw 255			;set up a debounce delay
	movwf DEBOUNCE		;and store
:loop_1
	decfsz DEBOUNCE		;subtract one and skip next if not 0
	goto :loop_2		;not 0 so jump
	return			;if 0 then return
:loop_2
	movf PORTB,W		;read port B
	movwf B_TEMP		;and store
	btfss ZERO_CTR		;is the zero button depressed?
	goto :loop			;if so then jump
	goto :loop_1		;else jump back
	return			;return to caller
SET_BRIGHT
		;set the PWM value in the display - the bits D0-D3 in Control Word 0 by
		;reading the cureent value of the pot.  It has a range of 0-255 and the
		;PWM has a range of 0-16, so only the upper nibble will be used to set
		;the PWM.
	call AD_START		;start the AD converter
	btfss FLAGS, AD_FLAG	;is the ad finished?
	goto $-1			;if not then loop back
	bcf FLAGS, AD_FLAG	;clear ad flag
	SWAPF ADRESH		;swap upper and lower nibbles
	movf ADRESH,W		;move the ad conversion to W
	andlw 0fh			;mask off upper nibble
	iorlw 40h			;set the sleep bit to high
	movwf LED_TEMP		;store data to output
	bsf LED_RS			;select Control Register
	bcf LED_OE			;enable chip
	call LED_WRITE		;and output
	bsf LED_OE			;disable chip
	return			;return to caller

MOVE
	;do an ad conversion - if in the range of 100 - 156 then take no action.
	;if value is less than 100, clear C, shift left once to double, shift the
	;original value right once and add to doubled value - then invert and use
	;as the PWM value.  If the ad conversion is above 156, then then subtract
	;156, shift left once to double, then shift the subtracted value right once
	;to half and add to doubled value and use as the PWM value.  Check status of
	;motor enable button - if still pressed do it all over again.

	bcf rp0			;point to
	bcf rp1			;bank 0
	movf PORTB,W		;read port B
	movwf B_TEMP		;and store
	btfsc MOTOR_ENB		;is the motor enable button pushed
	goto MOVE_1			;if not then jump forward
	call AD_START		;start the ad conversion
	btfss FLAGS,LED_CHANGE	;if flag set then update display
	goto MOVE_0			;else jump
	call LED_POS		;update display
	bcf FLAGS,LED_CHANGE	;clear flag
MOVE_0
	btfss FLAGS, AD_FLAG	;is the ad finished?
	goto $-1			;if not done then loop back
MOVE_0A
	bcf FLAGS, AD_FLAG	;clear ad flag
	movf ADRESH,W		;move ad value to W
	sublw 120			;subtract 120 - W
	btfsc C			;if C is 1 then ad value is 120 or less
	goto MOVE_IN		;so jump to motor move in
	movf ADRESH,W		;move ad value to W
	sublw 136			;subtract 136 - W
	btfss C			;if C is 0 then W is more than 136
	goto MOVE_OUT		;if 0 then jump to motor move out
		;ad value is in the dead zone, so check button again, if still depressed
		;then start ad conversion again
MOVE_1
	bsf MOTOR_CHIP_EN		;disable motor chip
	movlw 0			;load 0 into PWMs
	movwf CCPR1L		;move value into PWM1
	movwf CCPR2L		;move value into PWM1
	movf PORTB,W		;read port B
	movwf B_TEMP		;and store
	btfss MOTOR_ENB		;is the motor enable button pushed
	goto MOVE			;if so then loop back
	return			;else return
MOVE_IN
	movlw 0			;load 0 into W
	movwf CCPR2L		;move value into PWM2
	movf ADRESH,W		;move ad value to W
	movwf AD_ORG		;and store
:CHECK_5
	movlw 5			;load with 5
	subwf AD_ORG,W		;AD_ORG - 5
	btfsc C			;if not neg then skip next
	goto :CHECK_10		;if positive then jump
	movlw 100			;load PWM with 100
	goto MOVE_IN_LOAD		;and jump
:CHECK_10
	movlw 10			;load with 10
	subwf AD_ORG,W		;AD_ORG - 10
	btfsc C			;if not neg then skip next
	goto :CHECK_20		;if positive then jump
	movlw 32			;load PWM with 32
	goto MOVE_IN_LOAD		;and jump
:CHECK_20
	movlw 20			;load with 20
	subwf AD_ORG,W		;AD_ORG - 20
	btfsc C			;if not neg then skip next
	goto :CHECK_50		;if positive then jump
	movlw 16			;load PWM with 16
	goto MOVE_IN_LOAD		;and jump
:CHECK_50
	movlw 50			;load with 50
	subwf AD_ORG,W		;AD_ORG - 50
	btfsc C			;if not neg then skip next
	goto :CHECK_70		;if positive then jump
	movlw 10			;load PWM with 8
	goto MOVE_IN_LOAD		;and jump
:CHECK_70
	movlw 70			;load with 70
	subwf AD_ORG,W		;AD_ORG - 70
	btfsc C			;if not neg then skip next
	goto :CHECK_100		;if positive then jump
	movlw 8			;load PWM with 4
	goto MOVE_IN_LOAD		;and jump
:CHECK_100
	movlw 100			;load with 100
	subwf AD_ORG,W		;AD_ORG - 100
	btfsc C			;if not neg then skip next
	goto :CHECK_120		;if positive then jump
	movlw 6			;load PWM with 2
	goto MOVE_IN_LOAD		;and jump
:CHECK_120
	movlw 4			;load PWM with 1

MOVE_IN_LOAD
	movwf CCPR1L		;move value into PWM1
	bcf MOTOR_CHIP_EN		;enable motor chip
	goto MOVE			;loop back

MOVE_OUT_LOAD
	movwf CCPR2L		;move value into PWM2
	bcf MOTOR_CHIP_EN		;enable motor chip
	goto MOVE			;loop back

MOVE_OUT
	movlw 0			;load 0 into W
	movwf CCPR1L		;move value into PWM1
	movf ADRESH,W		;move ad value to W
	movwf AD_ORG		;and store
:CHECK_251
	movlw 251			;load with 251
	subwf AD_ORG,W		;AD_ORG - 251
	btfss C			;if not neg then skip next
	goto :CHECK_246		;if positive then jump
	movlw 100			;load PWM with 100
	goto MOVE_OUT_LOAD	;and jump
:CHECK_246
	movlw 246			;load with 246
	subwf AD_ORG,W		;AD_ORG - 246
	btfss C			;if not neg then skip next
	goto :CHECK_236		;if positive then jump
	movlw 32			;load PWM with 32
	goto MOVE_OUT_LOAD	;and jump
:CHECK_236
	movlw 236			;load with 236
	subwf AD_ORG,W		;AD_ORG - 236
	btfss C			;if not neg then skip next
	goto :CHECK_206		;if positive then jump
	movlw 16			;load PWM with 16
	goto MOVE_OUT_LOAD	;and jump
:CHECK_206
	movlw 206			;load with 206
	subwf AD_ORG,W		;AD_ORG - 206
	btfss C			;if not neg then skip next
	goto :CHECK_186		;if positive then jump
	movlw 10			;load PWM with 8
	goto MOVE_OUT_LOAD	;and jump
:CHECK_186
	movlw 186			;load with 186
	subwf AD_ORG,W		;AD_ORG - 186
	btfss C			;if not neg then skip next
	goto :CHECK_156		;if positive then jump
	movlw 8			;load PWM with 4
	goto MOVE_OUT_LOAD	;and jump
:CHECK_156
	movlw 156			;load with 156
	subwf AD_ORG,W		;AD_ORG - 156
	btfss C			;if not neg then skip next
	goto :CHECK_136		;if positive then jump
	movlw 6			;load PWM with 2
	goto MOVE_OUT_LOAD	;and jump
:CHECK_136
	movlw 4			;load PWM with 1
	goto MOVE_OUT_LOAD	;and jump

AD_START
	bcf rp0			;point to
	bcf rp1			;bank 0
	movlw 81h			;select Fosc/32, ch 0, AD on
	movwf ADCON0		;and store in ADCON 0 register
		; delay settle time, ~50 uSec: ~250 instruction cycles at 20 MHz
	movlw	84			; 84 * 3 * .20 uSec = 50uSec
	movwf	ADRESH		;temporary storage
	decfsz ADRESH		;decrement until 0
	goto	$-1			;until then wait
	bsf GO_DONE			;start AD conversion
	return

LED_POS
	;this sub writes the contents of memory location LED_BUF out to the
	;HCMS-29xx 4 digit display.  The display is made of 4 columns of 8 rows
	;of LEDs.  The bottom row (7) is not used.  Data is written to the LED
	;serially starting with the left most column of the left most digit.  The
	;msb is written first with the lsb written last.  A period is always displayed
	;in the left most display along with either a + or - sign.
	;This is done by reading position of the ZSF from POSITION storage
	;goto $

	bcf RP0			;point to bank 0
	bcf RP1			;
	bcf LED_CLK			;clear the clock bit
	bcf LED_DATA_IN		;clear the data bit
	bcf LED_RS			;clear the register select bit
	bcf LED_OE			;enable chip
		;do digit 4
	btfsc POS_HIGH,4		;check bit 4 for Positive (0) or Negative (1)
	goto POS_NEG		;if set (negative) then jump
			;Positive so output +.
			;do column 5
	movlw 0			;load column 0 to get
	call LED_PLUS		;get data
	movwf LED_TEMP		;and store in temp location
	call LED_WRITE		;and display data
		;now do column 4
	movlw 1			;load column 1 to get
	call LED_PLUS		;get data
	movwf LED_TEMP		;and store in temp location
	call LED_WRITE		;and display data
		;now do column 3
	movlw 2			;load column 2 to get
	call LED_PLUS		;get data
	movwf LED_TEMP		;and store in temp location
	call LED_WRITE		;and display data
		;now do column 2
	movlw 3			;load column 3 to get
	call LED_PLUS		;get data
	movwf LED_TEMP		;and store in temp location
	call LED_WRITE		;and display data
		;now do column 1
	movlw 4			;load column 4 to get
	call LED_PLUS		;get data
	movwf LED_TEMP		;and store in temp location
	call LED_WRITE		;and display data
	goto POS_CONT		;jump to characters 2-4
POS_NEG
			;Negative so output -.
		;do column 5
	movlw 0			;load column 0 to get
	call LED_Minus		;get data
	movwf LED_TEMP		;and store in temp location
	call LED_WRITE		;and display data
		;now do column 4
	movlw 1			;load column 1 to get
	call LED_Minus		;get data
	movwf LED_TEMP		;and store in temp location
	call LED_WRITE		;and display data
		;now do column 3
	movlw 2			;load column 2 to get
	call LED_Minus		;get data
	movwf LED_TEMP		;and store in temp location
	call LED_WRITE		;and display data
		;now do column 2
	movlw 3			;load column 3 to get
	call LED_Minus		;get data
	movwf LED_TEMP		;and store in temp location
	call LED_WRITE		;and display data
		;now do column 1
	movlw 4			;load column 4 to get
	call LED_Minus		;get data
	movwf LED_TEMP		;and store in temp location
	call LED_WRITE		;and display data
POS_CONT
		;do digit 2
		;do column 5 first
	bcf C				;clear the carry bit
	movf POS_HIGH,W		;get position into w
	andlw 0fh			;mask off upper nibble
	movwf POS_TEMP		;and store in temp location
	rlf POS_TEMP		;rotate left
	rlf POS_TEMP		;rotate a second time
	rlf POS_TEMP		;rotate a third time
	movf POS_TEMP,W		;move data to W
	call LED_DIGIT		;get data
	movwf LED_TEMP		;and store in temp location
	call LED_WRITE		;and display data
		;now do column 4
	incf POS_TEMP		;increment to next column
	movf POS_TEMP,W		;move data to W
	call LED_DIGIT		;get data
	movwf LED_TEMP		;and store in temp location
	call LED_WRITE		;and display data
		;now do column 3
	incf POS_TEMP		;increment to next column
	movf POS_TEMP,W		;move data to W
	call LED_DIGIT		;get data
	movwf LED_TEMP		;and store in temp location
	call LED_WRITE		;and display data
		;now do column 2
	incf POS_TEMP		;increment to next column
	movf POS_TEMP,W		;move data to W
	call LED_DIGIT		;get data
	movwf LED_TEMP		;and store in temp location
	call LED_WRITE		;and display data
		;now do column 1
	incf POS_TEMP		;increment to next column
	movf POS_TEMP,W		;move data to W
	call LED_DIGIT		;get data
	movwf LED_TEMP		;and store in temp location
	call LED_WRITE			;and display data
		;do digit 3
		;do column 5 first
	bcf C				;clear the carry bit
	movf POS_LOW,W		;get position into w
	andlw 0f0h			;mask off lower nibble
	movwf POS_TEMP		;and store in temp location
	rrf POS_TEMP		;rotate right
	movf POS_TEMP,W		;move data to W
	call LED_DIGIT		;get data
	movwf LED_TEMP		;and store in temp location
	call LED_WRITE		;and display data
		;now do column 4
	incf POS_TEMP		;increment to next column
	movf POS_TEMP,W		;move data to W
	call LED_DIGIT		;get data
	movwf LED_TEMP		;and store in temp location
	call LED_WRITE		;and display data
		;now do column 3
	incf POS_TEMP		;increment to next column
	movf POS_TEMP,W		;move data to W
	call LED_DIGIT		;get data
	movwf LED_TEMP		;and store in temp location
	call LED_WRITE		;and display data
		;now do column 2
	incf POS_TEMP		;increment to next column
	movf POS_TEMP,W		;move data to W
	call LED_DIGIT		;get data
	movwf LED_TEMP		;and store in temp location
	call LED_WRITE		;and display data
		;now do column 1
	incf POS_TEMP		;increment to next column
	movf POS_TEMP,W		;move data to W
	call LED_DIGIT		;get data
	movwf LED_TEMP		;and store in temp location
	call LED_WRITE		;and display data
		;do digit 4
		;do column 5 first
	bcf C				;clear the carry bit
	movf POS_LOW,W		;get position into w
	andlw 0fh			;mask off upper nibble
	movwf POS_TEMP		;and store in temp location
	rlf POS_TEMP		;rotate left
	rlf POS_TEMP		;rotate a second time
	rlf POS_TEMP		;rotate a third time
	movf POS_TEMP,W		;move data to W
	call LED_DIGIT		;get data
	movwf LED_TEMP		;and store in temp location
	call LED_WRITE		;and display data
		;now do column 4
	incf POS_TEMP		;increment to next column
	movf POS_TEMP,W		;move data to W
	call LED_DIGIT		;get data
	movwf LED_TEMP		;and store in temp location
	call LED_WRITE		;and display data
		;now do column 3
	incf POS_TEMP		;increment to next column
	movf POS_TEMP,W		;move data to W
	call LED_DIGIT		;get data
	movwf LED_TEMP		;and store in temp location
	call LED_WRITE		;and display data
		;now do column 2
	incf POS_TEMP		;increment to next column
	movf POS_TEMP,W		;move data to W
	call LED_DIGIT		;get data
	movwf LED_TEMP		;and store in temp location
	call LED_WRITE		;and display data
		;now do column 1
	incf POS_TEMP		;increment to next column
	movf POS_TEMP,W		;move data to W
	call LED_DIGIT		;get data
	movwf LED_TEMP		;and store in temp location
	call LED_WRITE		;and display data
	bsf LED_OE			;and disable chip
WRITE_RS_232	;output the display via RS-232 - terminate with CR
	bcf RP0			;make sure still bank 0
	movlw 21h			;set character pointer to begin of buffer
	movwf CHAR_OUT_PTR	;
	movwf FSR			;use indirect addressing to point to buffer beginning
	movf POS_HIGH,W		;get high display position
	andlw 0f0h			;mask off low nibble
	btfss Z			;if 0 (+) then skip next
	goto :_232_MINUS		;else jump to output minus sign
:_232_PLUS
	movlw '+'			;load + sign
	movwf INDF			;load in character buffer
	goto :_232_DEC		;and jump
:_232_MINUS
	movlw '-'			;load - sign
	movwf INDF			;load in character buffer
:_232_DEC
	incf fsr,1			;point to next character
	movlw '.'			;load with decimal
	movwf INDF			;and load in character buffer
	incf fsr,1			;point to next character
	movf POS_HIGH,W		;get display high byte
	movwf _232_TEMP		;and move to temp storage
;	swapf _232_TEMP,W		;swap nibbles and put into W
	andlw 0fh			;mask off high nibble
	iorlw 30h			;or with 30h to make ASCII
	movwf INDF			;and load in character buffer
	incf fsr,1			;point to next character
	movf POS_LOW,W		;get low display byte
	movwf _232_TEMP		;and move to temp storage
	swapf _232_TEMP,W		;swap nibbles and put into W
	andlw 0fh			;mask off high nibble
	iorlw 30h			;or with 30h to make ASCII
	movwf INDF			;and load in character buffer
	incf fsr,1			;point to next character
	movf POS_LOW,W		;get low display byte
	andlw 0fh			;mask off high nibble
	iorlw 30h			;or with 30h to make ASCII
	movwf INDF			;and load in character buffer
	incf fsr,1			;point to next character
	movlw CR			;load with CR
	movwf INDF			;and load in character buffer
	incf fsr,1			;point to next character
	movlw 0			;load with end of string
	movwf INDF			;and load in character buffer
;	call RS232_OUT		;start RS-232 output
	movlw 21h			;set character pointer to begin of buffer
	movwf TX_PTR		;
	movwf FSR			;use indirect addressing to point to buffer beginning
	bsf RP0			;bank 1
	bsf TXIE			;enable tx interrupts (bank1:8C  PIE1.4)
	bcf RP0			;bank 0
BIN_CTR_SUB	;subtract 1 from the binary counter
	movlw 1			;subtract one from the low byte
	subwf BIN_LOW,F		;and store back in BIN_LOW
	btfsc C			;was there a borrow? (c=0 if borrow)
	return			;return to caller
BIN_BORROW		;was a borrow so subtract one from high byte
	movf BIN_HIGH,W		;first check to see if high is 0
	btfss Z			;if 0 then skip next
	decf BIN_HIGH		;
	return			;and return to caller

LED_INIT
	;this sub initializes the HCMS-29xx display.  This is done by writing +.000 to the
	;display, setting the sleep bit(6) to high and setting the PWM to 60% (HHLH) in Control
	;Word 0.
;	1 - output - LED OE
;	2 - output - LED CLK
;	3 - output - LED RS
;	4 - output - LED *RST
;	5 - output - LED DATA IN
		;write to control word 0 to disable sleep and enable PWM
	bsf LED_RS			;select Control Register
	movlw 4dh			;move data to end sleep, set PWM to 60%
	movwf LED_TEMP		;store data to output
	bcf LED_OE			;enable chip
	call LED_WRITE		;and output
	bsf LED_OE			;disable chip
	return			;return to caller

LED_WRITE
	movlw 8			;load temp register with bit count
	movwf TEMP_A		;and store
:loop
	rlf LED_TEMP		;rotate led bit to Carry
	btfsc C			;if the bit was 0, skip next
	bsf LED_DATA_IN		;if bit was high, set data out as high
	bsf LED_CLK			;raise clock
	bcf LED_CLK			;lower clock
	bcf LED_DATA_IN		;clear data bit
	decfsz TEMP_A		;decrement bit count
	goto :loop			;and loop back for next bit
	return			;and return to caller


	;this sub writes the contents of memory location LED_BUF out to the
	;HCMS-29xx 4 digit display.  The display is made of 4 columns of 8 rows
	;of LEDs.  The bottom row (7) is not used.  Data is written to the LED
	;serially starting with the left most column of the left most digit.  The
	;msb is written first with the lsb written last.  A period is always displayed
	;in the left most display along with either a + or - sign.
	goto $

INIT_PORTS
	;set Port A 0 to analog input, 2-5 as digital outputs
	;set Port B to inputs
	;set Port C to outputs (bits 0,1,2,3,4,5,7),Input (bit 6) USART (bits 6,7)
	bcf rp0			;point to
	bcf rp1			;bank 0
	movlw 0			;load 00 into W
	movwf FLAGS			;clear Flags
	movwf SSPCON		;clear SSPCON to disable SYNC Port
	movwf T1CON			;clear Timer 1 to disable
	movlw 21h			;set rs-232 receive buffer
	movwf BUFFER_PTR		;pointer to 1st character
	clrf PORTA			;intitialize port a by clearing (bank 0:05)
					;data latches
	clrf CCP1CON		;ccp module 1 is off (bank0:17)
	clrf CCP2CON		;ccp module 2 is off (bank0:1d)
	clrf TMR2			;clear timer 2 (bank0:11)
	movlw 0			;set duty cycle to off
	movwf CCPR1L		;(bank0:15)
	movwf CCPR2L		;(bank0:1b)
	bsf RP0			;select bank 1
	movlw 7fh			;load Period Timer 2 register
	movwf PR2			;(bank1:92h)
	movlw 0eh			;configure 0 as analog, all others
	movwf ADCON1		;as digital (not analog)(bank1:9f)
	bsf ADIE 			; Enable A/D interrupts
	movlw 01h			;value used to initialize data direction
	movwf TRISA			;set 0 as input, 1-5 as outputs(bank1:85)
	movlw 0ffh			;value used to initialize data direction
	movwf TRISB			;set all pins to inputs (bank1:86)
	movlw 10000000b			;value used to initialize data direction
	movwf TRISC			;set pin 7 (Rx) as inputs, all other output (bank1:87)
	movlw 04h			;set 8-bit transmit, should be for using BRGH
;	movlw 00h			;set 8-bit transmit,
	movwf TXSTA			;asynchronous mode, high speed (bank1:98)
	movwf SSPCON2			;disable sync port
	movlw BAUD_CONST		;get the baud rate
	movwf SPBRG			;and set (bank1:99 )
	bsf TXEN			;enable transmissions
	bsf RCIE			;enable receive interrupts (bank1:8C  PIE1.5)
	bcf RP0				;point to bank 0
	bsf SPEN			;enable serial port (bank 0:18 RCSTA.7)
	bsf CREN			;8-bit receive, receiver enabled (bank0:18 RCSTA.4)
	movlw 0ch			;enable ccpxcon (was 2c in orginal code)
	movwf CCP1CON		;(bank0:17)
	movwf CCP2CON		;(bank0:1D)
	bsf T2CON, 2		;turn on timer 2
	movlw 0			;set character pointer to 0
	movwf CHAR_OUT_PTR	;
	return			;return to caller
INIT_IRQ
	;setup timer 0 for a 5 ms interrupt.  Using a 20MHz oscillator
	;and a prescaler of 128, the timer should be pre loaded with a
	;value of 61.  This is calculated by 20MHz/4 = 5MHz.
	;5 MHz/128 prescaler = 25.6uS.  5ms/25.6uS = 195.  Finally
	;(256-61)*25.6us = 5ms.
	bsf rp0			;point to
	bcf rp1			;bank 1
	movlw	10000110B		;disable PB PU, Prescaler to Timer 0, 1:128
	movwf option		;and set in option register
	bcf rp0			;select bank 0
	movlw 01101000B		;enable tmr0 & PORT B change & Peripheral int
	movwf intcon		;and place in register
	movlw Five_mS_Cont	;preset value for timer 0
	movwf tmr0			;store
	retfie			;return to caller while enabling interrupts

PB_CNG
	;A change has happened on CH-A connected to Port B pin 7.  Once the interrupt
	;has been dectected check the current value of CH-A and CH-B (port b bit 3).

	movf PORTB,W		;read port b
	movwf B_CHNG		;and store
	bcf RBIF			;clear the int flag
	btfsc B_CHNG,7		;if channel a low then skip
	goto CH_A_HIGH		;else jump since it is high
	btfsc B_CHNG,3		;if channel b is low then skip
	goto CH_AL_BH		;else jump since it is high
	goto CH_AL_BL		;jump to A low, B low
CH_A_HIGH
	btfsc CH_B			;if channel b is low then skip
	goto CH_AH_BH		;else since high jump to A high, B high
	goto CH_AH_BL		;since low, jump to A high, B low

CH_AL_BL	;channel A low, B low,  so moving in
CH_AH_BH	;channel A high, B high, so moving in
		;first check for +.000
	movf POS_LOW,W		;get the low display byte
	btfss Z			;if zero then skip next
	goto :IN_NZ			;else jump
	movf POS_HIGH, W		;get high display byte
	btfss Z			;if zero then skip next
	goto :IN_NZ			;not 0 so jump
	goto :IN_Z_P		;skip this if -
:IN_Z_P		;move in, raw cnt 0, sign +
	movf LOW_CNT,W		;get the low raw count
	btfss Z			;if zero then skip next
	goto :IN_RAW_NZ		;if not 0 then jump
	movf HIGH_CNT,W		;get the high raw count
	btfss Z			;if 0 then skip next
	goto :IN_RAW_NZ		;if not 0 then jump
:IN_RAW_Z	;raw count = 0, increment and change display to -.000
	incf LOW_CNT,1		;add one to raw count
	movlw 10h			;set display to -.000
	movwf POS_HIGH		;
	movlw 00h			;
	movwf POS_LOW		;
	bsf FLAGS,LED_CHANGE	;set display change flag
	goto INT_SRV_EXIT		;goto exit ISR
:IN_RAW_NZ		;raw count not 0, plus flag = + (0)
	call SUBTRACT_ONE		;subtract one from raw count
	goto INT_SRV_EXIT		;goto exit ISR
:IN_NZ		;display not 0
	movf POS_HIGH,W		;get flag
	andlw 0f0h			;mask off low nibble
	btfss Z			;if neg then skip next
	goto :IN_NZ_MINUS		;if neg then jump
:IN_NZ_PLUS	;display not 0 and positive
	movf LOW_CNT,W		;check raw count for = 0
	btfss Z			;if 0 then skip next
	goto :IN_NZ_P_RCNZ	;if not 0 then jump
	movf HIGH_CNT,W		;get high byte raw count
	btfsc Z			;if not Z skip next
	goto :IN_NZ_P_RCZ		;if  0 then jump
:IN_NZ_P_RCNZ	;move in, display not 0, positive, raw count not 0
	call SUBTRACT_ONE		;subtract one from raw
	goto INT_SRV_EXIT		;goto exit ISR
:IN_NZ_P_RCZ	;move in, display not 0, positive, raw count = 0
	movlw ONE_T_HIGH		;set raw counter to max value
	movwf HIGH_CNT		;high byte
	movlw ONE_T_LOW		;
	movwf LOW_CNT		;low byte
	call DISPLAY_SUB_1	;subtract one from display
	goto INT_SRV_EXIT		;goto exit ISR
:IN_NZ_MINUS	;display not 0 and negative
	movf LOW_CNT,W		;check raw count for max value
	xorlw ONE_T_LOW		;compare
	btfss Z			;if  equal (0) then skip next
	goto :IN_NZ_MINUS_RCNM	;if not at max then jump
	movf HIGH_CNT,W		;else get high raw count
	xorlw ONE_T_HIGH		;compare
	btfss Z			;if equal (0) then skip next
	goto :IN_NZ_MINUS_RCNM	;if not at max then jump
:IN_NZ_MINUS_RCMV	;display not 0, minus, raw count at max value
	movlw 0			;set raw counter to 0
	movwf LOW_CNT		;low byte
	movwf HIGH_CNT		;high byte
	call DISPLAY_ADD_1	;add one to display
	goto INT_SRV_EXIT		;goto exit ISR
:IN_NZ_MINUS_RCNM 	;display not 0, minus, raw count not max
	call ADD_ONE		;add one to raw
	goto INT_SRV_EXIT		;goto exit ISR



CH_AL_BH	;channel A low, B high, so moving out
CH_AH_BL	;channel A high, B low, so moving out
	;first check for -.000
	movf POS_LOW,W		;get the low display byte
	btfss Z			;if zero then skip next
	goto :OUT_NZ		;else jump
	movf POS_HIGH, W		;get high display byte
	xorlw 10h			;compare to -.0
	btfss Z			;if -.0 then skip next
	goto :OUT_NZ		;was not -.0 so jump
:OUT_Z_P		;move out, raw cnt 0, sign -
	movf LOW_CNT,W		;get the low raw count
	btfss Z			;if zero then skip next
	goto :OUT_RAW_NZ		;if not 0 then jump
	movf HIGH_CNT,W		;get the high raw count
	btfss Z			;if 0 then skip next
	goto :OUT_RAW_NZ		;if not 0 then jump
:OUT_RAW_Z	;raw count = 0, increment and change display to +.000
	incf LOW_CNT,1		;add one to raw count
	movlw 00h			;set display to +.000
	movwf POS_HIGH		;
	movwf POS_LOW		;
	bsf FLAGS,LED_CHANGE	;set display change flag
	goto INT_SRV_EXIT		;goto exit ISR
:OUT_RAW_NZ		;raw count not 0, display -
	call SUBTRACT_ONE		;subtract one from raw count
	goto INT_SRV_EXIT		;goto exit ISR
:OUT_NZ		;display not 0
	movf POS_HIGH,W		;get flag
	andlw 0f0h			;mask off low nibble
	btfsc Z			;if neg then skip next
	goto :OUT_NZ_POS		;if pos then jump
:OUT_NZ_NEG	;display not 0 and negative
	movf LOW_CNT,W		;check raw count for = 0
	btfss Z			;if 0 then skip next
	goto :OUT_NZ_NEG_RCNZ	;if not 0 then jump
	movf HIGH_CNT,W		;get high byte raw count
	btfsc Z			;if not Z skip next
	goto :OUT_NZ_NEG_RCZ	;else if 0 then jump
:OUT_NZ_NEG_RCNZ	;move in, display not 0, negative, raw count not 0
	call SUBTRACT_ONE		;subtract one from raw
	goto INT_SRV_EXIT		;goto exit ISR
:OUT_NZ_NEG_RCZ	;move in, display not 0, negative, raw count = 0
	movlw ONE_T_HIGH		;set raw counter to max value
	movwf HIGH_CNT		;high byte
	movlw ONE_T_LOW		;
	movwf LOW_CNT		;low byte
	call DISPLAY_SUB_1	;subtract one from display
	goto INT_SRV_EXIT		;goto exit ISR
:OUT_NZ_POS	;display not 0 and positive
	movf LOW_CNT,W		;check raw count for max value
	xorlw ONE_T_LOW		;compare
	btfss Z			;if equal (0) then skip next
	goto :OUT_NZ_POS_RCNM	;if not at max then jump
	movf HIGH_CNT,W		;else get high raw count
	xorlw ONE_T_HIGH		;compare
	btfss Z			;if equal (0) then skip next
	goto :OUT_NZ_POS_RCNM	;if not at max then jump
:OUT_NZ_POS_RCMV	;display not 0, positive, raw count at max value
	movlw 0			;set raw counter to 0
	movwf LOW_CNT		;low byte
	movwf HIGH_CNT		;high byte
	call DISPLAY_ADD_1	;add one to display
	goto INT_SRV_EXIT		;goto exit ISR
:OUT_NZ_POS_RCNM 	;display not 0, positive, raw count not max
	call ADD_ONE		;add one to raw
	goto INT_SRV_EXIT		;goto exit ISR

SUBTRACT_ONE		;subtract one from raw count
	movf LOW_CNT,W		;get low byte count
	btfsc Z			;if byte is not 0 then skip next
	goto :low_0			;else if 0 then jump
	decf LOW_CNT		;else decrement low counter
	return			;return to caller
:low_0		;low pulse counter is 0
	movf HIGH_CNT,W		;get high byte counter
	btfsc Z			;if byte is 0 then skip next
	goto high_low_0		;if both are 0 then jump
	decf LOW_CNT,1		;dec low counter
	decf HIGH_CNT,1		;dec high counter
	return			;return to caller
high_low_0	;both high and low pulse counters are 0.  Set to .001" constant
		;subtract one from display and set flag to update
		;the display
	movlw ONE_T_HIGH		;get high byte constant
	movwf HIGH_CNT		;and store
	movlw ONE_T_LOW		;get low byte constant
	movwf LOW_CNT		;and store
	return			;and return
DISPLAY_SUB_1	;subtract one from the display
		;first check to see if display is +.000
		;check to see if .001's digit is 0
	movf POS_LOW,W		;get low byte of display counter
	andlw 0fh			;mask off high nibble
	btfsc Z			;is the resulting value not 0? skip if so
	goto sub_001s		;if 0 then jump
	decf POS_LOW,1		;decrement .001's digit
	movf POS_LOW,W		;check for -.000 value
	btfss Z			;if byte is not 0 then skip next
	goto :CHECK_A		;and goto exit
	movf POS_HIGH,W		;get high counter
	xorlw 10h			;check for -0
	btfss Z			;if equal (0 flag set) then skip
	goto :CHECK_A		;if not equal then jump
	movlw 00h			;display was -.000
	movwf POS_HIGH		;change to +.000
	movlw 0			;set raw counter to 0
	movwf LOW_CNT		;
	movwf HIGH_CNT		;
:CHECK_A
	bsf FLAGS,LED_CHANGE	;set display change flag
	return			;and return
Sub_001s	;.001's digit is 0
	movf POS_LOW,W		;get low byte into W
	andlw 0f0h			;mask off low nibble
	btfss Z			;if the high nibble is 0 then skip next
	goto tenth_not_0		;else if not 0 then jump
		;.01's is 0, .001's is 0
	movlw 99h			;load low display with 99
	movwf POS_LOW		;
		;check .1s digit to subtract one
	decf POS_HIGH,1		;decrment .x
	bsf FLAGS,LED_CHANGE	;set display change flag
	return			;and return
tenth_not_0	;.01's not 0,  .001's is 0
	decf POS_LOW,0		;subtract one from low display
	andlw 0f0h			;mask off high nibble
	iorlw 09h			;or with low nibble as 9
	movwf POS_LOW		;and store
	bsf FLAGS,LED_CHANGE	;set display change flag
	return			;and return
ADD_ONE		;add one to the raw pulse count
	incf LOW_CNT,1		;add one to low pulse count
	btfsc Z			;did it become 0?
	incf HIGH_CNT,1		;if so increment high count
	return			;and return

DISPLAY_ADD_1	;add one from the display
	incf POS_LOW,1		;add one to low display
	movf POS_LOW,W		;get the low display
	andlw 0fh			;mask off high nibble
	xorlw 0ah			;is low nibble A
	btfsc Z			;if not then skip next
	goto :CARRY_001		;else is A so jump to carry
	bsf FLAGS,LED_CHANGE	;set display change flag
	return			;and return
:CARRY_001	;added 1 to .001 and went from 9 to A
	movf POS_LOW,W		;get low display
	andlw 0f0h			;mask off low nibble
	iorlw 00h			;and make low nibble 0
	movwf POS_LOW		;and store
	andlw 0f0h			;mask off low nibble
	xorlw 090h			;is it 9
	btfsc Z			;if not 9 then skip next
	goto :CARRY_01		;if 9 then jump
	swapf POS_LOW,1		;swap nibbles
	incf POS_LOW,1		;increment .0x
	swapf POS_LOW,1		;and swap nibbles again
	bsf FLAGS,LED_CHANGE	;set display change flag
	return			;and return
:CARRY_01
	movlw 0			;value was .x99, so set low display to 0
	movwf POS_LOW		;and store
	incf POS_HIGH,1		;increment .x digit
	movf POS_HIGH, W		;get high display
	andlw 0fh			;mask off sign (high nibble)
	xorlw 0ah			;compare to A
	btfsc Z			;if not A then skip next
	goto :CARRY_1		;else if A then jump
	bsf FLAGS,LED_CHANGE	;set display change flag
	return			;and return
:CARRY_1
	movlw 0f0h			;set low nibble to 0
	andwf POS_HIGH,1		;by ANDing off low nibble
	return			;and return

AD_CONV
	bcf adif			;clear the a/d int flag
	bsf FLAGS, AD_FLAG	;set the flag to indicate conversion done
	goto INT_SRV_EXIT		;goto exit ISR

ServiceTMR0		;5ms timer - set flag to indicate 5ms period
	movlw Five_mS_Cont	;get delay value for 5 ms
	movwf tmr0			;and load
	bcf t0if			;clear tmr0 interrupt flag
	bsf FLAGS,0			;set 5 ms flag
	goto INT_SRV_EXIT		;goto exit ISR

RS232_OUT		;send first character via RS232 and enable TX interrupts
	movlw 21h			;set character pointer to begin of buffer
	movwf CHAR_OUT_PTR	;
	movwf FSR			;use indirect addressing to point to buffer beginning
	bsf RP0			;bank 1
	bsf TXIE			;enable tx interrupts (bank1:8C  PIE1.4)
	bcf RP0			;bank 0
	movf INDF,W			;get character from buffer
	movwf TXREG			;load the char into the transmit register and send
	inc CHAR_OUT_PTR		;point to next character
	return			;return to caller

ServiceTX
	movf TX_PTR,W	  	;get current buffer location
	movwf FSR			;and store
	movf INDF,W			;get character from buffer
	btfsc Z			;is it 0 - if so do next step
	goto TX_1			;jump if zero
	movf INDF,W			;get character from buffer
	movwf TXREG			;and place in tx data register
	incf TX_PTR,1		;point to next character
	goto INT_SRV_EXIT		;goto exit ISR
TX_1
	bsf rp0			;point to bank 1
	bcf TXIE			;disable TX interrupts
	bcf RP0			;point to bank 0
	movf INDF			;get character from buffer
	movwf TXREG			;and place in tx data register
	goto INT_SRV_EXIT		;goto exit ISR

ServiceRX
	;load position to load next character in buffer using BUFFER_PTR
	movf BUFFER_PTR,W		;get current buffer position
	movwf FSR			;and store for indirect addressing
	movf RCREG,0		;get received data into W
	movwf INDF			;and store data in buffer
;	incf BUFFER_PTR,1		;point to next location
;	goto INT_SRV_EXIT		;goto exit ISR
	movf BUFFER_PTR,W		;get RX pointer
	xorlw 31h			;is it at the P position
	btfss Z			;if so then skip next
	goto CK_32			;else goto next position check
RX_P
	movf INDF,W			;get character at current buffer position
	xorlw 'P'			;is it a P?
	btfss Z			;if so then skip next
	goto ZERO_CHECK		;then check for zero command
	incf BUFFER_PTR,1		;increment buffer pointer
	goto INT_SRV_EXIT		;goto exit ISR
ZERO_CHECK
	movf INDF,W			;get character at current buffer position
	xorlw 'Z'			;is it a Z?
	btfss Z			;if so then skip next
	goto RX_ERROR		;not a valid entry so jump
	movlw 0			;set position counter to +000
	movwf POS_HIGH		;high and
	movwf POS_LOW		;low byte
	movwf HIGH_CNT		;set pulse counter to 0
	movwf LOW_CNT		;
	bsf FLAGS,LED_CHANGE	;set display change flag
	movlw 31h			;point buffer to begining
	movwf BUFFER_PTR		;
	goto INT_SRV_EXIT		;goto exit ISR

CK_32		;is buffer at location 32? P+-
	movf BUFFER_PTR,W		;get RX pointer
	xorlw 32h			;is it at the sign position
	btfss Z			;if so then skip next
	goto CK_33			;else goto next position check
	movf INDF,W			;get character
	xorlw '+'			;is it a plus sign
	btfss Z			;if so skip next
	goto MINUS_CK		;else jump
	incf BUFFER_PTR,1		;increment buffer pointer
	goto INT_SRV_EXIT		;goto exit ISR
MINUS_CK
	movf INDF,W			;get character
	xorlw '-'			;is it a minus sign
	btfss Z			;if so skip next
	goto RX_ERROR		;not a valid entry so jump
	incf BUFFER_PTR,1		;increment buffer pointer
	goto INT_SRV_EXIT		;goto exit ISR
CK_33		;is buffer at location 33 P+.
	movf BUFFER_PTR,W		;get RX pointer
	xorlw 33h			;is it at the decimal position
	btfss Z			;if so then skip next
	goto CK_34			;else goto next position check
	movf INDF,W			;get character
	xorlw '.'			;is it a .
	btfss Z			;if so skip next
	goto RX_ERROR		;not a valid entry so jump
	incf BUFFER_PTR,1		;increment buffer pointer
	goto INT_SRV_EXIT		;goto exit ISR
CK_34		;is buffer at location 34 P+.x
	movf BUFFER_PTR,W		;get RX pointer
	xorlw 34h			;is it at the P+.x position
	btfss Z			;if so then skip next
	goto CK_35			;else goto next position check
		;check .x for digit 0-9
	movf INDF,W			;get character
	andlw 0f0h			;mask off the low nibble
	sublw 030h			;is it 30h?
	btfss Z			;if so then skip next step
	goto RX_ERROR		;if not 30h then jump
	movf INDF,W			;get character
	andlw 0fh			;mask off the high nibble
	sublw 9			;subtract 9 from it
	btfss C			;check for borrow
	goto RX_ERROR		;if not 30h then jump
	incf BUFFER_PTR,1		;increment buffer pointer
	goto INT_SRV_EXIT		;goto exit ISR
CK_35		;is buffer at location 34 P+.0x
	movf BUFFER_PTR,W		;get RX pointer
	xorlw 35h			;is it at the P+.0x position
	btfss Z			;if so then skip next
	goto CK_36			;else goto next position check
		;check .0x for digit 0-9
	movf INDF,W			;get character
	andlw 0f0h			;mask off the low nibble
	sublw 030h			;is it 30h?
	btfss Z			;if so then skip next step
	goto RX_ERROR		;if not 30h then jump
	movf INDF,W			;get character
	andlw 0fh			;mask off the high nibble
	sublw 9			;subtract 9 from it
	btfss C			;check for borrow
	goto RX_ERROR		;if not 30h then jump
	incf BUFFER_PTR,1		;increment buffer pointer
	goto INT_SRV_EXIT		;goto exit ISR
CK_36		;is buffer at location 34 P+.00x
	movf BUFFER_PTR,W		;get RX pointer
	xorlw 36h			;is it at the P+.00x position
	btfss Z			;if so then skip next
	goto CK_37			;else goto next position check
		;check .00x for digit 0-9
	movf INDF,W			;get character
	andlw 0f0h			;mask off the low nibble
	sublw 030h			;is it 30h?
	btfss Z			;if so then skip next step
	goto RX_ERROR		;if not 30h then jump
	movf INDF,W			;get character
	andlw 0fh			;mask off the high nibble
	sublw 9			;subtract 9 from it
	btfss C			;check for borrow
	goto RX_ERROR		;if not 30h then jump
	incf BUFFER_PTR,1		;increment buffer pointer
	goto INT_SRV_EXIT		;goto exit ISR
CK_37		;is buffer at location 34 P+.000 CR
	movf BUFFER_PTR,W		;get RX pointer
	xorlw 37h			;is it at the P+.000 CR position
	btfss Z			;if so then skip next
	goto RX_ERROR		;else goto error
		;check CR
	movf INDF,W			;get character
	xorlw CR			;is it CR
	btfss Z			;if so then skip next step
	goto RX_ERROR		;if not 30h then jump
RX_VALID	;valid entry so act on it
	bsf FLAGS, RX		;valid rx data flag
	goto INT_SRV_EXIT		;goto exit ISR


RX_ERROR
	movlw 31h			;point buffer to begining
	movwf BUFFER_PTR		;
	goto INT_SRV_EXIT		;goto exit ISR



	org 0400h
LED_Plus
	movwf LED_TEMP		;store column in temp location
	movlw $<			;move high byte of PC into W
	movwf PCLATH		;and into PCLATH
	movf LED_TEMP,W		;get column # into W
	addwf PCL, F 		;add to PC low and save in PCL
	retw 04h
	retw 04h
	retw 1fh
	retw 04h
	retw 44h


LED_Minus
	movwf LED_TEMP		;store column in temp location
	movlw $<			;move high byte of PC into W
	movwf PCLATH		;and into PCLATH
	movf LED_TEMP,W		;get column # into W
	addwf PCL, F 		;add to PC low and save in PCL
	retw 04h
	retw 04h
	retw 04h
	retw 04h
	retw 44h

LED_DIGIT
	movwf LED_TEMP		;store column in temp location
	movlw $<			;move high byte of PC into W
	movwf PCLATH		;and into PCLATH
	movf LED_TEMP,W		;get column # into W
	addwf PCL, F 		;add to PC low and save in PCL
	retw 3eh			;Digit 0 Column 5
	retw 51h			;Digit 0 Column 4
	retw 49h			;Digit 0 Column 3
	retw 45h			;Digit 0 Column 2
	retw 3eh			;Digit 0 Column 1
	nop
	nop
	nop
	retw 00h			;Digit 1 Column 5
	retw 42h			;Digit 1 Column 4
	retw 7fh			;Digit 1 Column 3
	retw 40h			;Digit 1 Column 2
	retw 00h			;Digit 1 Column 1
	nop
	nop
	nop
	retw 62h			;Digit 2 Column 5
	retw 51h			;Digit 2 Column 4
	retw 49h			;Digit 2 Column 3
	retw 49h			;Digit 2 Column 2
	retw 46h			;Digit 2 Column 1
	nop
	nop
	nop
	retw 22h			;Digit 3 Column 5
	retw 49h			;Digit 3 Column 4
	retw 49h			;Digit 3 Column 3
	retw 49h			;Digit 3 Column 2
	retw 36h			;Digit 3 Column 1
	nop
	nop
	nop
	retw 18h			;Digit 4 Column 5
	retw 14h			;Digit 4 Column 4
	retw 12h			;Digit 4 Column 3
	retw 7fh			;Digit 4 Column 2
	retw 10h			;Digit 4 Column 1
	nop
	nop
	nop
	retw 27h			;Digit 5 Column 5
	retw 45h			;Digit 5 Column 4
	retw 45h			;Digit 5 Column 3
	retw 45h			;Digit 5 Column 2
	retw 39h			;Digit 5 Column 1
	nop
	nop
	nop
	retw 3ch			;Digit 6 Column 5
	retw 4ah			;Digit 6 Column 4
	retw 49h			;Digit 6 Column 3
	retw 49h			;Digit 6 Column 2
	retw 30h			;Digit 6 Column 1
	nop
	nop
	nop
	retw 01h			;Digit 7 Column 5
	retw 71h			;Digit 7 Column 4
	retw 09h			;Digit 7 Column 3
	retw 05h			;Digit 7 Column 2
	retw 03h			;Digit 7 Column 1
	nop
	nop
	nop
	retw 36h			;Digit 8 Column 5
	retw 49h			;Digit 8 Column 4
	retw 49h			;Digit 8 Column 3
	retw 49h			;Digit 8 Column 2
	retw 36h			;Digit 8 Column 1
	nop
	nop
	nop
	retw 06h			;Digit 9 Column 5
	retw 49h			;Digit 9 Column 4
	retw 49h			;Digit 9 Column 3
	retw 29h			;Digit 9 Column 2
	retw 1eh			;Digit 9 Column 1

end

