
; LED Tachometer 
	ERRORLEVEL -302
	ERRORLEVEL -306

	list P=16F88
	#include p16f88.inc

;Program Configuration Register 1
		__CONFIG    _CONFIG1, _CP_ALL & _CCP1_RB0  & _DEBUG_OFF & _WRT_PROTECT_OFF & _CPD_OFF & _LVP_OFF & _BODEN_ON & _MCLR_ON & _PWRTE_ON & _WDT_OFF & _HS_OSC

;Program Configuration Register 2
		__CONFIG    _CONFIG2, _IESO_OFF & _FCMEN_OFF
; Define variables at memory locations


EEPROM0		equ	H'00'	; non-volatile storage for redline RPM ms
EEPROM1		equ	H'01'	; non-volatile storage for redline RPM ls
EEPROM2		equ	H'02'	; non-volatile storage for number of red LEDs
EEPROM3		equ	H'03'	; non-volatile storage for rpm /LED ms
EEPROM4		equ	H'04'	; non-volatile storage for rpm /LED ls
EEPROM5		equ	H'05'	; non-volatile storage for cylinder setting
EEPROM6		equ	H'06'	; non-volatile storage for shift rpm ms byte
EEPROM7		equ	H'07'	; non-volatile storage for shift rpm ls byte
EEPROM8		equ	H'08'	; non-volatile storage for options (bar or dot, 3-LEDs or 1 LED dot, >10,000 rpm
EEPROM9		equ	H'09'	; non-volatile storage for digital display update counter
EEPROMA		equ	H'0A'	; non-volatile storage for LED bargraph hysteresis
EEPROMB		equ	H'0B'	; non-volatile storage for limit RPM ms
EEPROMC		equ	H'0C'	; non-volatile storage for limit RPM ls
EEPROMD		equ	H'0D'	; non-volatile storage for limiter sense
EEPROME		equ	H'0E'	; non-volatile storage for limiter on time

; Bank 0 RAM

RED_LINE1	equ	H'20'	; redline rpm
RED_LINE2	equ	H'21'	; redline rpm
RED_LEDS	equ	H'22'	; number of red LEDs
TACHO_CAL1	equ	H'23'	; calculation of rpm per LED (RED_LINE rpm/(32 - number of RED_LEDS)ms byte
TACHO_CAL2	equ	H'24'	; calculation of rpm per LED (RED_LINE rpm/(32 - number of RED_LEDS)ls byte
CYL_SET		equ	H'25'	; cylinder setting
SHIFT1		equ	H'26'	; ms byte of shift rpm
SHIFT2		equ	H'27'	; ls byte of shift rpm
COUNT0		equ	H'28'	; ms 32-bit rpm counter
COUNT1		equ	H'29'	; 32-bit rpm counter
COUNT2		equ	H'2A'	; 32-bit rpm counter
COUNT3		equ	H'2B'	; ls 32-bit rpm counter
RPM_VAL0	equ	H'2C'	; ms byte calculated RPM
RPM_VAL1	equ	H'2D'	; ls byte calculated RPM
OPTIONS		equ	H'2E'	; options flags

LED_VALUE	equ	H'2F'	; discrete LED rpm value (0-32)
IC1_LED1	equ	H'30'	; 40-bit shift register for IC1 ls byte
IC1_LED2	equ	H'31'	; 40-bit shift register for IC1 
IC1_LED3	equ	H'32'	; 40-bit shift register for IC1 				 
IC1_LED4	equ	H'33'	; 40-bit shift register for IC1 
IC1_LED5	equ	H'34'	; 40-bit shift register for IC1 ms byte

IC2_LED1	equ	H'35'	; 40-bit shift register for IC2 ls byte
IC2_LED2	equ	H'36'	; 40-bit shift register for IC2 
IC2_LED3	equ	H'37'	; 40-bit shift register for IC2 				 
IC2_LED4	equ	H'38'	; 40-bit shift register for IC2 
IC2_LED5	equ	H'39'	; 40-bit shift register for IC2 ms byte

CLK_CNT		equ	H'3A'	; clock counter
COUNTER0	equ	H'3B'	; ms 32-bit timer1 overflow counter
COUNTER1	equ	H'3C'	; 32-bit timer1 overflow counter
NIL_SIG		equ	H'3D'	; flag indicating if timer1 continues to overflows beyond COUNTER0
DELCNT		equ	H'3E'	; delay counter
VALUE_1		equ	H'3F'	; delay value
VALUE_2		equ	H'40'	; delay value
SHIFT_MS	equ	H'41'	; current rpm for shift light
SHIFT_LS	equ	H'42'	; current rpm for shift light
UPDATE_TM	equ	H'43'	; seven segment digital display update counter
UPDATE_CT 	equ	H'44'	; stored update
ONE_ONE		equ	H'45'	; display values store
ONE_TWO		equ	H'46'	; display values store
ONE_THREE	equ	H'47'	; display values store
ONE_FOUR	equ	H'48'	; display values store
ONE_FIVE	equ	H'49'	; display values store
TWO_ONE		equ	H'4A'	; display values store
TWO_TWO		equ	H'4B'	; display values store
TWO_THREE	equ	H'4C'	; display values store
TWO_FOUR	equ	H'4D'	; display values store
TWO_FIVE	equ	H'4E'	; display values store
STO_LEDVAL	equ	H'4F'	; storage
STORE0		equ	H'50'	; rpm storage
STORE1		equ	H'51'	; rpm storage
HYSTERESIS	equ	H'52'	; hysteresis
TWO_CNT		equ	H'53'	; count of 2
TOTAL0		equ	H'54'	; ms byte of rpm addition
TOTAL1		equ	H'55'	; mid byte of rpm addition
TOTAL2		equ	H'56'	; ls byte of rpm addition
TALLY_CNT	equ	H'57'	; tally counter for averaging
TEN_THOU	equ	H'58'	; over ten thousand flag
OPTION_STO	equ	H'59'	; options storage
SETTINGS	equ	H'5A'	; settings mode flag
LABEL		equ	H'5B'	; label value

; math routines

BIN_0		equ	H'5C'	; binary value lsd
BIN_1		equ	H'5D'	; binary value 
BCD_0		equ	H'5E'	; BCD MS
BCD_1		equ	H'5F'	; display value MS
BCD_2		equ	H'60'	; display value LS
CNT_16		equ	H'61'	; counter for BCD conversion

TEMP		equ H'62'
REMB3		equ H'63'
REMB2		equ	H'64'
REMB1      	equ H'65'
REMB0		equ	H'66'
AARGB3		equ	H'67'
AARGB2      equ H'68'
AARGB1      equ H'69'
AARGB0      equ H'6A'	; most significant byte of argument A
BARGB3      equ H'6B'
BARGB2      equ H'6C'
BARGB1      equ H'6D'
BARGB0      equ H'6E'	; most significant byte of argument B
LOOPCOUNT   equ H'6F'  	; division counter

; All Banks RAM (70 to 7F)

W_TMP		equ	H'70'	; storage of w before interrupt
STATUS_TMP	equ	H'71'	; status storage before interrupt
PCLATH_TMP	equ	H'72'	; PCLATH store

NUMER_0		equ	H'73'	; rpm numerator value ms byte
NUMER_1		equ	H'74'	; rpm numerator value mid byte
NUMER_2		equ	H'75'	; rpm numerator value mid byte
NUMER_3		equ	H'76'	; rpm numerator value ls byte
DELAY_FLG	equ	H'77'	; flag for delay after switch press
START_FLG	equ	H'78'	; start count down flag
LIMIT1		equ	H'79'	; limiter rpm ms byte
LIMIT2		equ	H'7A'	; limiter rpm ls byte
LIMIT_SENSE	equ	H'7B'	; limiter sense
LIMIT_ON	equ	H'7C'	; limiter on timer stored value
LIMIT_TM	equ	H'7D'	; limiter on timer running value
NO_BAR		equ	H'7E'	; no bargraph when shift light on flag
	
; preprogram EEPROM DATA 
; initial values	
	ORG     H'2100'
	DE	H'23', H'28'; 9000rpm red line
	DE  D'05'		; 5-red LEDs
	DE 	H'01', H'4D'; 333rpm/LED 9000/(32-5)
	DE 	D'04'		; 4-cylinders
	DE	H'1F', H'40'; 8000rpm shift
	DE	B'00000001'	; options, bit 0 dot/bar, 1&2 display format, 3&4 resolution
	DE	D'100'		; digital display update count (2ms/value) 
	DE	D'50'		; rpm hysteresis for LED bargraph display
	DE  H'26', H'AC'; limit rpm 9900
	DE	D'00'		; limiter sense
	DE	D'100'		; limiter on period (2ms/value)

; start at memory 0

	org		H'0'	; main program start
	goto	MAIN
	org 	H'4'	; interrupt vector 0004h, start interrupt routine here
	goto	INTRUPT		

;******************************************************************************************* 


; Calculations

; 1.
; 1/2 pulse per rpm (1cyl 4-stroke)
; Timer 1 internal clock count /1
; capture every + edge
; 1Hz (120rpm) has 5M count (numerator needs to be 120 x 5 x 10^6)
; Calculations: min 600M/5M = 120rpm 

; 2.
; 1 pulse per rpm (2cyl 4-stroke, 1 cyl 2-stroke)
; Timer 1 internal clock count /1
; capture every + edge
; 1Hz (60rpm) has 5M count (numerator needs to be 60 x 5 x 10^6)
; Calculations: min 300M/5M = 60rpm 

; 3.
; 1.5 pulse per rpm (3cyl 4-stroke)
; Timer 1 internal clock count /1
; capture every + edge
; 1Hz (45rpm) has 5M count (numerator needs to be 45 x 5 x10^6)
; Calculations: min 225M/5M = 45rpm 

; 4.
; 2 pulses per rpm (4cyl 4-stroke, 2 cyl 2-stroke)
; Timer 1 internal clock count /1
; capture every positive edge 
; 1Hz (30rpm) has 5MHz count (numerator needs to be 30 x 5 x 10^6)
; Calculations: min 150M/5M = 30rpm 

; 5.
; 2.5 pulses per rpm (5cyl 4-stroke)
; Timer 1 internal clock count /1
; capture every + edge
; 1Hz (24rpm) has 5M count (numerator needs to be 24 x 5 x 10^6)
; Calculations: min 120M/5M = 24rpm 

; 6.
; 3 pulses per rpm (6cyl 4-stroke, 3 cyl 2-stroke)
; Timer 1 internal clock count /2
; capture every 4th edge
; 1Hz (20rpm) has 10M count (numerator needs to be 20 x 10 x 10^6)
; Calculations: min 200M/10M = 20rpm 

; 7 (and 11) (caters for assymetrical twin engine)
; 1 pulse per rpm (2cyl 4-stroke, 1 cyl 2-stroke)
; Timer 1 internal clock count /2
; capture every 4th edge
; 1Hz (60rpm) has 10M count (numerator needs to be 60 x 10 x 10^6)
; Calculations: min 600M/10M = 60rpm 

; 8.
; 4 pulses per rpm (8cyl 4-stroke, 4 cyl 2-stroke)
; Timer 1 internal clock count /2
; capture every 4th edge
; 1Hz (15rpm) has 10M count (numerator needs to be 15 x 10 x 10^6)
; Calculations: min 150M/10M = 15rpm 

; 9 caters for assymetrically firing 3-cylinder 4-stroke
; 1.5 pulse per rpm (3cyl 4-stroke)
; Timer 1 internal clock count /2
; capture every 4th edge
; 1Hz (45rpm) has 10M count (numerator needs to be 45 x 10 x10^6)
; Calculations: min 450M/10M = 45rpm 
 
; 11 see 7

; 10.
; 5 pulses per rpm (10 cyl 2-stroke)
; Timer 1 internal clock count /2
; capture every 4th edge
; 1Hz (12rpm) has 10M count (numerator needs to be 12 x 10 x 10^6)
; Calculations: min 120M/20M = 12rpm 

; 12
; 6 pulses per rpm (12cyl 4-stroke, 6 cyl 2-stroke)
; Timer 1 internal clock count /2
; capture every 4th edge
; 1Hz (10rpm) has 10M count (numerator needs to be 10 x 10 x 10^6)
; Calculations: min 100M/10M = 10rpm 		

; INTERRUPT

; start interrupt by saving w and status registers before altered by interrupt routine

INTRUPT
	movwf	W_TMP		; w to w_tmp storage
	swapf	STATUS,w	; status to w
	movwf	STATUS_TMP	; status in status_tmp 
	bcf 	STATUS,RP0	; bank 0 
	btfss	PIR1,CCP1IF	; if capture place into Count2,3, clear NIL_SIG 
	goto	CK_TMR_O
	bcf		T1CON,0		; stop timer
	
; check for capture before 
; overflow flag set 
	
	btfss	PIR1,TMR1IF	; if timer overflow flag set, ignore values 
	goto	XFER_VAL	; capture and no overflow then values are valid
TMR_CLFLG
	bcf		PIR1,TMR1IF	; clear flag
	bcf		PIR1,CCP1IF	; clear flag
	clrf	NIL_SIG		; signal captured so clear value 
	
	goto	CLR_COUNT

; check timer overflow
CK_TMR_O	
	btfss	PIR1,TMR1IF	; if timer overflow flag set, increase COUNTER1
	goto	RECLAIM		; 
	bcf		PIR1,TMR1IF	; clear flag
	incfsz	COUNTER1,f	; overflow counter FFFF to 0000
	goto	RECLAIM
	incf	COUNTER0,f	; increase ms byte if ls byte overflows
	btfsc	COUNTER0,0	; if past count of ~ 67 000 000 clear
	bsf		NIL_SIG,0	; set flag if overflows beyond COUNTER0 
	goto	RECLAIM
XFER_VAL
	bcf		PIR1,CCP1IF	; clear flag
	clrf	NIL_SIG		; signal captured so clear value 

; transfer COUNTER0,1 to COUNT0,1
; CCPR1L and H to COUNT2,3
	movf	COUNTER0,w
	movwf	COUNT0		; ms 32-bit rpm counter
	movf	COUNTER1,w
	movwf	COUNT1		; 32-bit rpm counter
	movf	CCPR1H,w	; capture compare value
	movwf	COUNT2		; 32-bit rpm counter
	movf	CCPR1L,w
	movwf	COUNT3		; ls 32-bit rpm counter

; clear counters
CLR_COUNT
	movf	CCP1CON,w	; store value
	clrf	CCP1CON		; clears prescaler
	movwf	CCP1CON		; restore value capture compare (bank 0)
	clrf	COUNTER0
	clrf	COUNTER1
	clrf	CCPR1L
	clrf	CCPR1H

	clrf	TMR1L
	clrf	TMR1H
	bsf		T1CON,0		; restart timer

; end of interrupt reclaim w and status 

RECLAIM	
	swapf	STATUS_TMP,w; status temp storage to w
	movwf	STATUS		; w to status register
	
	swapf	W_TMP,f		; swap upper and lower 4-bits in w_tmp
	swapf   W_TMP,w		; swap bits and into w register
	retfie				; return from interrupt

; *********************************************************************************

; initialise ports

MAIN
; set limiter output	
	movlw	EEPROMD		; Limiter sense
	call	EEREAD		; get value
	movwf	LIMIT_SENSE	; sense
	btfss	LIMIT_SENSE,0	; if 0 set low
	goto	LIMITER_LOW1
	movlw	B'01111100'	; limiter output high RB6
	goto	DRV_PORTB
LIMITER_LOW1
	movlw	B'00111100'	; limiter output low RB6
DRV_PORTB
	movwf	PORTB		; portB,7 output low, RB6 limiter out 
	movlw	B'00000000'
	movwf	PORTA		; portA,0 and 1 output low
	bsf		STATUS,RP0	; select memory bank 1
	clrf	ANSEL		; analog inputs off

; set inputs/outputs
	movlw	B'00000111'	; comparators off
	movwf	CMCON
	movlw	B'00111101'	; port B outputs/ inputs set 
	movwf	TRISB		; port B data direction register
	movlw	B'11100000'	; outputs (0) and inputs (1)
	movwf	TRISA		; port A data direction register
	movlw	B'00000111'	; settings (pullups enabled TMR0/256)
	movwf	OPTION_REG
	bcf		STATUS,RP0	; select memory bank 0

	call	DELAY1		; delay
	clrf	SETTINGS	; settings mode clear (set if down switch pressed)
	clrf	LABEL		; label value
	clrf	UPDATE_TM	; update timer
	clrf	LIMIT_TM	; limit timer
	movlw	H'FF'
	movwf	START_FLG	; start count down flag
	clrf	LED_VALUE	; start LED bar at 0

; Read EEPROM

	movlw	EEPROM0		; redline RPM ms
	call	EEREAD		; get value
	movwf	RED_LINE1	; redline rpm
	movlw	EEPROM1		; redline RPM 
	call	EEREAD		; get value
	movwf	RED_LINE2	; redline rpm

	movlw	EEPROMB		; limit RPM ms
	call	EEREAD		; get value
	movwf	LIMIT1		; limit rpm
	movlw	EEPROMC		; limit RPM 
	call	EEREAD		; get value
	movwf	LIMIT2		; limit rpm

	movlw	EEPROM2		; number of red LEDs
	call	EEREAD		; get value
	movwf	RED_LEDS	; red LEDs

	movlw	EEPROM3		; rpm/LED ms byte
	call	EEREAD		; get value
	movwf	TACHO_CAL1	; calculation of rpm/LED
	movlw	EEPROM4		; rpm/LED ls byte
	call	EEREAD		; get value
	movwf	TACHO_CAL2	; calculation of rpm/LED

	movlw	EEPROM5		; cylinder setting
	call	EEREAD		; get value
	movwf	CYL_SET		; cylinder setting

	movlw	EEPROM6		; shift rpm ms byte
	call	EEREAD		; get value
	movwf	SHIFT1		; ms byte of shift rpm
	movlw	EEPROM7		; shift rpm ms byte
	call	EEREAD		; get value
	movwf	SHIFT2		; ls byte of shift rpm

	movlw	EEPROM8		; options
	call	EEREAD		; get value
	movwf	OPTIONS		; ms byte of shift rpm

	movlw	EEPROM9		; digital display update count
	call	EEREAD		; get value
	movwf	UPDATE_CT	; stored value

	movlw	EEPROMA		; LED display hysteresis
	call	EEREAD		; get value
	movwf	HYSTERESIS	; hysteresis

	movlw	EEPROME		; Limiter on period timer
	call	EEREAD		; get value
	movwf	LIMIT_ON	; LIMIT period

	movlw	D'10'		; delay 
	call	DELAY_1

; read switches
	btfsc	PORTB,5		; if up switch on then settings mode
	goto	RES_PORTS	; change ports
	bsf		PCLATH,3	; page 1
	goto	WAIT_OPEN	; SETTINGS mode

; ***********************************************************
; normal rpm run mode	
RES_PORTS
	clrf	SETTINGS	; clear settings display mode
	clrf	PORTB		; outputs low
	btfss	LIMIT_SENSE,0	; if 0 set low
	goto	LIMITER_LOW2
	bsf		PORTB,6		; limiter output high RB6
	goto	SET_IN_OUT
LIMITER_LOW2
	bcf		PORTB,6		; limiter output low RB6
SET_IN_OUT
	bsf		STATUS,RP0	; select memory bank 1
; set inputs/outputs
	movlw	B'00000001'	; switch inputs as outputs 
	movwf	TRISB		; port B data direction register
	movlw	B'10000111'	; settings (pullups disabled TMR0/256)
	movwf	OPTION_REG
	bcf		STATUS,RP0	; select memory bank 0

; check cylinders and set required timer settings and numerator
CYL_VALUES
	movf	CYL_SET,w	; cylinder setting value 1 to 12
	xorlw	D'01'		; 1 cyl 4-stroke
	btfsc	STATUS,Z
	goto	NO_1
	movf	CYL_SET,w	; cylinder setting value 1 to 12
	xorlw	D'02'		; 2 cyl 4-stroke
	btfsc	STATUS,Z
	goto	NO_2
	movf	CYL_SET,w	; cylinder setting value 1 to 12
	xorlw	D'03'		; 3 cyl 4-stroke
	btfsc	STATUS,Z
	goto	NO_3
	movf	CYL_SET,w	; cylinder setting value 1 to 12
	xorlw	D'04'		; 4 cyl 4-stroke
	btfsc	STATUS,Z
	goto	NO_4
	movf	CYL_SET,w	; cylinder setting value 1 to 12
	xorlw	D'05'		; 5 cyl 4-stroke
	btfsc	STATUS,Z
	goto	NO_5
	movf	CYL_SET,w	; cylinder setting value 1 to 12
	xorlw	D'06'		; 6 cyl 4-stroke
	btfsc	STATUS,Z
	goto	NO_6
	movf	CYL_SET,w	; cylinder setting value 1 to 12
	xorlw	D'08'		; 8 cyl 4-stroke
	btfsc	STATUS,Z
	goto	NO_8
	movf	CYL_SET,w	; cylinder setting value 1 to 12
	xorlw	D'09'		; 3 cyl 4-stroke (asymmetrically fired)
	btfsc	STATUS,Z
	goto	NO_9
	movf	CYL_SET,w	; cylinder setting value 1 to 12
	xorlw	D'10'		; 10 cyl 4-stroke
	btfsc	STATUS,Z
	goto	NO_10
	movf	CYL_SET,w	; cylinder setting value 1 to 12
	xorlw	D'12'		; 12 cyl 4-stroke
	btfsc	STATUS,Z
	goto	NO_12

; numbers 7 and 11 cater for assymetrical twin 4-stroke
NO_7_11					; numerator is 600M
	movlw	H'23'
	movwf	NUMER_0		; rpm numerator value ms byte
	movlw	H'C3'
	movwf	NUMER_1		; rpm numerator value mid byte
	movlw	H'46'
	movwf	NUMER_2		; rpm numerator value mid byte
	movlw	H'00'
	movwf	NUMER_3		; rpm numerator value ls byte
	goto	SIX_TWELVE_SETTING
NO_1					; numerator is 600M
	movlw	H'23'
	movwf	NUMER_0		; rpm numerator value ms byte
	movlw	H'C3'
	movwf	NUMER_1		; rpm numerator value mid byte
	movlw	H'46'
	movwf	NUMER_2		; rpm numerator value mid byte
	movlw	H'00'
	movwf	NUMER_3		; rpm numerator value ls byte
	goto	ONE_FIVE_SETTING
NO_2					; numerator is 300M
	movlw	H'11'
	movwf	NUMER_0		; rpm numerator value ms byte
	movlw	H'E1'
	movwf	NUMER_1		; rpm numerator value mid byte
	movlw	H'A3'
	movwf	NUMER_2		; rpm numerator value mid byte
	movlw	H'00'
	movwf	NUMER_3		; rpm numerator value ls byte
	goto	ONE_FIVE_SETTING
NO_3					; numerator is 225M
	movlw	H'0D'
	movwf	NUMER_0		; rpm numerator value ms byte
	movlw	H'69'
	movwf	NUMER_1		; rpm numerator value mid byte
	movlw	H'3A'
	movwf	NUMER_2		; rpm numerator value mid byte
	movlw	H'40'
	movwf	NUMER_3		; rpm numerator value ls byte
	goto	ONE_FIVE_SETTING
NO_4					; numerator is 150M
	movlw	H'08'
	movwf	NUMER_0		; rpm numerator value ms byte
	movlw	H'F0'
	movwf	NUMER_1		; rpm numerator value mid byte
	movlw	H'D1'
	movwf	NUMER_2		; rpm numerator value mid byte
	movlw	H'80'
	movwf	NUMER_3		; rpm numerator value ls byte
	goto	ONE_FIVE_SETTING
NO_5					; numerator is 120M
	movlw	H'07'
	movwf	NUMER_0		; rpm numerator value ms byte
	movlw	H'27'
	movwf	NUMER_1		; rpm numerator value mid byte
	movlw	H'0E'
	movwf	NUMER_2		; rpm numerator value mid byte
	movlw	H'00'
	movwf	NUMER_3		; rpm numerator value ls byte
	goto	ONE_FIVE_SETTING
NO_6					; numerator is 200M
	movlw	H'0B'
	movwf	NUMER_0		; rpm numerator value ms byte
	movlw	H'EB'
	movwf	NUMER_1		; rpm numerator value mid byte
	movlw	H'C2'
	movwf	NUMER_2		; rpm numerator value mid byte
	movlw	H'00'
	movwf	NUMER_3		; rpm numerator value ls byte
	goto	SIX_TWELVE_SETTING
NO_8					; numerator is 150M
	movlw	H'08'
	movwf	NUMER_0		; rpm numerator value ms byte
	movlw	H'F0'
	movwf	NUMER_1		; rpm numerator value mid byte
	movlw	H'D1'
	movwf	NUMER_2		; rpm numerator value mid byte
	movlw	H'80'
	movwf	NUMER_3		; rpm numerator value ls byte
	goto	SIX_TWELVE_SETTING
NO_9					; numerator is 450M
	movlw	H'1A'
	movwf	NUMER_0		; rpm numerator value ms byte
	movlw	H'D2'
	movwf	NUMER_1		; rpm numerator value mid byte
	movlw	H'74'
	movwf	NUMER_2		; rpm numerator value mid byte
	movlw	H'80'
	movwf	NUMER_3		; rpm numerator value ls byte
	goto	SIX_TWELVE_SETTING
NO_10					; numerator is 120M
	movlw	H'07'
	movwf	NUMER_0		; rpm numerator value ms byte
	movlw	H'27'
	movwf	NUMER_1		; rpm numerator value mid byte
	movlw	H'0E'
	movwf	NUMER_2		; rpm numerator value mid byte
	movlw	H'00'
	movwf	NUMER_3		; rpm numerator value ls byte
	goto	SIX_TWELVE_SETTING
NO_12					; numerator is 100M
	movlw	H'05'
	movwf	NUMER_0		; rpm numerator value ms byte
	movlw	H'F5'
	movwf	NUMER_1		; rpm numerator value mid byte
	movlw	H'E1'
	movwf	NUMER_2		; rpm numerator value mid byte
	movlw	H'00'
	movwf	NUMER_3		; rpm numerator value ls byte
	goto	SIX_TWELVE_SETTING
ONE_FIVE_SETTING	
	movlw	B'00000001'	; timer 1 prescaler /1 fosc/4
	movwf	T1CON		; bank 0
	movlw	B'00000101'	; every positive edge
	movwf	CCP1CON		; capture compare (bank 0)
	goto	INIT
SIX_TWELVE_SETTING	
	movlw	B'00010001'	; timer 1 prescaler /2 fosc/4
	movwf	T1CON		; bank 0
	movlw	B'00000110'	; every 4th edge
	movwf	CCP1CON		; capture compare (bank 0)
; initial conditions
INIT
	bsf		NIL_SIG,0	; set bit to cause overflow condition
	clrf	UPDATE_TM	; digital display update counter
	movlw	H'FF'		; set high the last rpm
	movwf	STORE0
	movwf	STORE1
	clrf	TOTAL0		; totals for capture counts
	clrf	TOTAL1
	clrf	TOTAL2
	clrf	TALLY_CNT	; number of tallys

; enable interrupts
	bsf		STATUS,RP0	; select memory bank 1
	bsf		PIE1,TMR1IE	; timer1 interupt enable for overflow (bank 1)
	bsf		PIE1,CCP1IE	; capture compare interrupt
	bcf		STATUS,RP0	; select memory bank 0
	bsf		INTCON,PEIE	; enable peripheral interrupts
	bsf		INTCON,GIE	; global interrupt enable

TACHO_RUN
; tachometer run
	movf	NIL_SIG,w	; check if no signal
	btfss	STATUS,Z	; if zero can calculate
	goto	RESET_VALUES

; divide to get rpm  values in 	NUMER_x
	movf	NUMER_0,w		
	movwf	AARGB0		; numerator ms byte
	movf	NUMER_1,w	;
	movwf	AARGB1
	movf	NUMER_2,w	;
	movwf	AARGB2		; 
	movf	NUMER_3,w	; numerator ls byte
	movwf	AARGB3

; stop interrupt
	bcf		INTCON,PEIE
	nop
	movf	COUNT0,w	; denominator ms byte
	movwf	BARGB0
	movf	COUNT1,w	; denominator 
	movwf	BARGB1
	movf	COUNT2,w	; denominator
	movwf	BARGB2
	movf	COUNT3,w	; denominator ls byte
	movwf	BARGB3

; allow interrupts
	bsf		INTCON,PEIE
	call	FXD3232U	; divide to get rpm

; setup average count
; add values
TALLY_CK_CNT
	incfsz	TALLY_CNT,w	; check if 256
	goto	TALLY0
	goto	RES_VALUES	; stop average when tally is at maximum
TALLY0	
	movf	AARGB3,w
	addwf	TOTAL2,f
	btfss	STATUS,C	; if carry set increase
	goto	TALLY1		; next byte
	incfsz	TOTAL1,f	; increase if over
	goto	TALLY1
	incfsz	TOTAL0,f	; increase if over
	goto	TALLY1
	goto	CLEAR_TALLY	; clear if overrange
TALLY1
	movf	AARGB2,w
	addwf	TOTAL1,f
	btfss	STATUS,C	; if over increase next byte
	goto	REMEMBER_TALLY_COUNT
	incfsz	TOTAL0,f	; if overrange clear tally
	goto	REMEMBER_TALLY_COUNT
	
CLEAR_TALLY
	clrf	TOTAL0
	clrf	TOTAL1
	clrf	TOTAL2
REMEMBER_TALLY_COUNT
	incf	TALLY_CNT,f

RES_VALUES
	movf	AARGB2,w	; ms of 16 bit answer
	movwf	AARGB0		; for comparison
	movwf	SHIFT_MS
	movf	AARGB3,w	; ls byte of 16 bit answer
	movwf	AARGB1
	movwf	SHIFT_LS

; Add hysteresis 
; subtract last value from current value. 
; subroutine subtract AARGB0 AARGB1 - BARGB0 BARGB1 = AARGB
; get registers for subtraction

	movf	STORE0,w	; ms byte of last result
	movwf	BARGB0
	movf	STORE1,w	; ls byte of last result
	movwf	BARGB1

	call	D_SUB		; subtract

; check if smaller than last time
	btfss	AARGB0,7	; set if smaller
	goto	LARGE_VAL
; add to value
	movf	AARGB2,w	; ms byte of result
	movwf	AARGB0
	movf	AARGB3,w	; ls byte of result
	movwf	AARGB1
; add hysteresis
	movf	HYSTERESIS,w; hysteresis value
	addwf	AARGB1,f	; ls byte
	btfsc	STATUS,C	; if overrange add 1 to ms byte
	incf	AARGB0,f
	
	movf	STORE0,w	; ms byte of last result
	movwf	BARGB0
	movf	STORE1,w	; ls byte of last result
	movwf	BARGB1

	call	D_SUB		; subtract

; check if smaller than last time
	btfsc	AARGB0,7	; set if smaller
 	goto	LARGE_VAL
; use last values
	movf	STORE0,w
	movwf	AARGB2
	movf	STORE1,w
	movwf	AARGB3
	goto	GET_LED_VALUE

; use new values
LARGE_VAL
; save values
	movf	AARGB2,w
	movwf	STORE0
	movf	AARGB3,w
	movwf	STORE1

; get LED value by dividing rpm by calibration value for rpm/LED
GET_LED_VALUE
	clrf	AARGB0		; numerator ms byte
	clrf	AARGB1
	clrf	BARGB0		; denominator ms byte
	clrf	BARGB1
	movf	TACHO_CAL1,w; tacho cal rpm/LED (redline/32 - number of red LEDs)
	movwf	BARGB2
	movf	TACHO_CAL2,w
	movwf	BARGB3

	call	FXD3232U	; get LED value for 32 LED display

	movf	AARGB3,w
	movwf	LED_VALUE	; value for discrete LED display
	
; add delay for 1ms update
	call	DELAYX		; extra delay

; drive display
	call	SEVEN_SEG1	; 7-segment display get values to drive M5451

; store values if this section ran so 7-segment displays can be updated slower
; w returned with a 1 or 0

	xorlw	D'1'		; if 1 then the values were not updated
	btfsc	STATUS,Z	; if zero restore values
	goto	RES_LOOP
	movf	IC1_LED1,w
	movwf	ONE_ONE		; store
	movf	IC1_LED2,w
	movwf	ONE_TWO		; store
	movf	IC1_LED3,w
	movwf	ONE_THREE	; store
	movf	IC1_LED4,w
	movwf	ONE_FOUR
	movf	IC1_LED5,w
	movwf	ONE_FIVE
	movf	IC2_LED1,w
	movwf	TWO_ONE
	movf	IC2_LED2,w
	movwf	TWO_TWO
	movf	IC2_LED3,w
	movwf	TWO_THREE
	movf	IC2_LED4,w
	movwf	TWO_FOUR
	movf	IC2_LED5,w
	movwf	TWO_FIVE
RES_LOOP	
	call	LED_DRIVE	; LED bargraph display 
	call	SHIFT_LIGHT	; shift light on or off
	call	LIMIT		; limiter action
	call	DRIVE_5451	; send values to M5451s
	goto	TACHO_RUN	; tacho routines
RESET_VALUES
	clrf	AARGB2		; clear values
	clrf	AARGB3
	goto	RES_VALUES	; start where rpm is 0

; ************************************************************************
; subroutines
LIMIT
; LIMIT1 and LIMIT2 are the limit rpm setting. SHIFT_MS and SHIFT_LS is the current rpm
; subtract	AARGB0 AARGB1 - BARGB0 BARGB1 = AARGB
	movf	LIMIT1,w
	movwf	AARGB0
	movf	LIMIT2,w
	movwf	AARGB1
	movf	SHIFT_MS,w
	movwf	BARGB0
	movf	SHIFT_LS,w
	movwf	BARGB1
	call	D_SUB
	btfsc	AARGB0,7	; limit on if rpm greater than setting
	goto	LIMIT_ON1
	btfss	LIMIT_SENSE,0	; if 0 then limiter low for off high for on
	goto	ALT_OUT1
; off if limiter timer finished
	movf	LIMIT_TM,w	; timer
	btfss	STATUS,Z
	return				; timer not ended
	bsf		PORTB,6		; limiter off
	return
ALT_OUT1
; off if limiter timer finished
	movf	LIMIT_TM,w	; timer
	btfss	STATUS,Z
	return				; timer not ended
	bcf		PORTB,6		; limiter off
	return

LIMIT_ON1
;	set timer
	movf	LIMIT_ON,w	; stored limit timer
	movwf	LIMIT_TM	; counter (decreased when decreasing display update timer) 
	btfss	LIMIT_SENSE,0	; if 0 then limiter low for off high for on
	goto	ALT_OUT2
	bcf		PORTB,6		; limiter on
	return
ALT_OUT2
	bsf		PORTB,6		; limiter on
	return

SHIFT_LIGHT
	bcf		IC2_LED1,7	; clear bit (shift light)
; Shift1 and Shift2 are the shift rpm setting. SHIFT_MS and SHIFT_LS is the current rpm
; subtract	AARGB0 AARGB1 - BARGB0 BARGB1 = AARGB
	movf	SHIFT1,w
	movwf	AARGB0
	movf	SHIFT2,w
	movwf	AARGB1
	movf	SHIFT_MS,w
	movwf	BARGB0
	movf	SHIFT_LS,w
	movwf	BARGB1
	call	D_SUB
	btfsc	AARGB0,7	; light if rpm greater than setting
	bsf		IC2_LED1,7	; shift light on
	return

;  Subroutine to get LED values for Driving display
; IC1_LED1				; first 1-8 LEDs bits 1-8
; IC1_LED2				; second 9-16 LEDs bits 9-16
; IC1_LED3				; third 17-24 bits 17-24
; IC1_LED4				; fourth 25-32 bits 25-32
; IC1_LED5				; fifth 33-35 bits 33-25 
; IC2_LED1				; first 1-8 LEDs bits 1-8
; IC2_LED2				; second 9-16 LEDs bits 9-16
; IC2_LED3				; third 17-24 bits 17-24
; IC2_LED4				; fourth 25-32 bits 25-32
; IC2_LED5				; fifth 33-35 bits 33-25 

LED_DRIVE
; 1ms repeat
	incf	TWO_CNT,f	; count 2ms repeat	
	movf	UPDATE_TM,w	; update time for digital display
	btfsc	STATUS,Z	; if zero do not decrease
	goto	DEC_LIMIT
	btfss	TWO_CNT,0
	goto	DEC_LIMIT
	decf	UPDATE_TM,f
; decrease limit timer
DEC_LIMIT
	movf	LIMIT_TM,w	; limit timer
	btfsc	STATUS,Z	; do not decrease if 0
	goto	RESTORE_LED
	btfss	TWO_CNT,0
	goto	RESTORE_LED
	decf	LIMIT_TM,f	; decrease until 0

; restore LED display values
RESTORE_LED
	
	movf	ONE_ONE,w		; store
	movwf	IC1_LED1
	movf	ONE_TWO,w		; store
	movwf	IC1_LED2
	movf	ONE_THREE,w		; store
	movwf	IC1_LED3
	movf	ONE_FOUR,w
	movwf	IC1_LED4
	movf	ONE_FIVE,w
	movwf	IC1_LED5
	movf	TWO_ONE,w
	movwf	IC2_LED1
	movf	TWO_TWO,w
	movwf	IC2_LED2
	movf	TWO_THREE,w
	movwf	IC2_LED3
	movf	TWO_FOUR,w
	movwf	IC2_LED4
	movf	TWO_FIVE,w
	movwf	IC2_LED5

; clear LED display registers
CLR_LED
; IC1_LED5 bits 0,1,2
	movlw	B'11111000'
	andwf	IC1_LED5,f	; clear bits

; IC2_LED1, 0,1,2,3,4,5,6
	movlw	B'10000000'
	andwf	IC2_LED1,f

; IC2_LED2, 0,1,2,3,4,5,6	
	movlw	B'10000000'
	andwf	IC2_LED2,f
 
; IC1_LED3, 1,2,3,4,5,6,7
	movlw	B'00000001'
	andwf	IC1_LED3,f

; IC1_LED4, 0,1,2,3,4	
 	movlw	B'11100000'
	andwf	IC1_LED4,f

; extra unbunched bits
	bcf		IC1_LED4,7	; clear bit
	bcf		IC2_LED3,0	; clear bit 
	bcf		IC2_LED2,7	; clear bit

; check display mode (Dot/Bar)
	btfsc	OPTIONS,0	; bit 0 sets dot/bar
	goto	BAR_DRV
; dot drive
DOT_DRV
	movf	LED_VALUE,w	; stored value for discrete LED display (0-35)
	movwf	STO_LEDVAL	; 
	xorlw	D'00'		; lowest LED
	btfsc	STATUS,Z	; if equal
	bsf		IC1_LED4,4	; set bit
	movf	STO_LEDVAL,w	; LED display
	xorlw	D'01'		; next LED
	btfsc	STATUS,Z	; if equal
	bsf		IC1_LED4,3	; set bit
	movf	STO_LEDVAL,w	; LED display
	xorlw	D'02'		; next LED
	btfsc	STATUS,Z	; if equal
	bsf		IC1_LED4,2	; set bit
	movf	STO_LEDVAL,w	; LED display
	xorlw	D'03'		; next LED
	btfsc	STATUS,Z	; if equal
	bsf		IC1_LED4,1	; set bit
	movf	STO_LEDVAL,w	; LED display
	xorlw	D'04'		; next LED
	btfsc	STATUS,Z	; if equal
	bsf		IC1_LED4,0	; set bit
	movf	STO_LEDVAL,w	; LED display
	xorlw	D'05'		; next LED
	btfsc	STATUS,Z	; if equal
	bsf		IC1_LED3,7	; set bit
	movf	STO_LEDVAL,w	; LED display
	xorlw	D'06'		; next LED
	btfsc	STATUS,Z	; if equal
	bsf		IC1_LED3,6	; set bit
	movf	STO_LEDVAL,w	; LED display
	xorlw	D'07'		; next LED
	btfsc	STATUS,Z	; if equal
	bsf		IC1_LED3,1	; set bit
	movf	STO_LEDVAL,w	; LED display
	xorlw	D'08'		; next LED
	btfsc	STATUS,Z	; if equal
	bsf		IC1_LED3,2	; set bit
	movf	STO_LEDVAL,w	; LED display
	xorlw	D'09'		; next LED
	btfsc	STATUS,Z	; if equal
	bsf		IC1_LED3,3	; set bit
	movf	STO_LEDVAL,w	; LED display
	xorlw	D'10'		; next LED
	btfsc	STATUS,Z	; if equal
	bsf		IC1_LED3,4	; set bit
	movf	STO_LEDVAL,w	; LED display
	xorlw	D'11'		; next LED
	btfsc	STATUS,Z	; if equal
	bsf		IC1_LED3,5	; set bit
	movf	STO_LEDVAL,w	; LED display
	xorlw	D'12'		; next LED
	btfsc	STATUS,Z	; if equal
	bsf		IC2_LED2,7	; set bit
	movf	STO_LEDVAL,w	; LED display
	xorlw	D'13'		; next LED
	btfsc	STATUS,Z	; if equal
	bsf		IC2_LED3,0	; set bit
	movf	STO_LEDVAL,w	; LED display
	xorlw	D'14'		; next LED
	btfsc	STATUS,Z	; if equal
	bsf		IC2_LED2,6	; set bit
	movf	STO_LEDVAL,w	; LED display
	xorlw	D'15'		; next LED
	btfsc	STATUS,Z	; if equal
	bsf		IC2_LED2,5	; set bit
	movf	STO_LEDVAL,w	; LED display
	xorlw	D'16'		; next LED
	btfsc	STATUS,Z	; if equal
	bsf		IC2_LED2,4	; set bit
	movf	STO_LEDVAL,w	; LED display
	xorlw	D'17'		; next LED
	btfsc	STATUS,Z	; if equal
	bsf		IC2_LED2,3	; set bit
	movf	STO_LEDVAL,w	; LED display
	xorlw	D'18'		; next LED
	btfsc	STATUS,Z	; if equal
	bsf		IC2_LED2,2	; set bit
	movf	STO_LEDVAL,w	; LED display
	xorlw	D'19'		; next LED
	btfsc	STATUS,Z	; if equal
	bsf		IC2_LED2,1	; set bit
	movf	STO_LEDVAL,w	; LED display
	xorlw	D'20'		; next LED
	btfsc	STATUS,Z	; if equal
	bsf		IC2_LED2,0	; set bit
	movf	STO_LEDVAL,w	; LED display
	xorlw	D'21'		; next LED
	btfsc	STATUS,Z	; if equal
	bsf		IC2_LED1,6	; set bit
	movf	STO_LEDVAL,w	; LED display
	xorlw	D'22'		; next LED
	btfsc	STATUS,Z	; if equal
	bsf		IC2_LED1,5	; set bit
	movf	STO_LEDVAL,w	; LED display
	xorlw	D'23'		; next LED
	btfsc	STATUS,Z	; if equal
	bsf		IC2_LED1,4	; set bit
	movf	STO_LEDVAL,w	; LED display
	xorlw	D'24'		; next LED
	btfsc	STATUS,Z	; if equal
	bsf		IC2_LED1,3	; set bit
	movf	STO_LEDVAL,w	; LED display
	xorlw	D'25'		; next LED
	btfsc	STATUS,Z	; if equal
	bsf		IC2_LED1,2	; set bit
	movf	STO_LEDVAL,w	; LED display
	xorlw	D'26'		; next LED
	btfsc	STATUS,Z	; if equal
	bsf		IC2_LED1,1	; set bit
	movf	STO_LEDVAL,w	; LED display
	xorlw	D'27'		; next LED
	btfsc	STATUS,Z	; if equal
	bsf		IC2_LED1,0	; set bit
	movf	STO_LEDVAL,w	; LED display
	xorlw	D'28'		; next LED
	btfsc	STATUS,Z	; if equal
	bsf		IC1_LED4,7	; set bit
	movf	STO_LEDVAL,w	; LED display
	xorlw	D'29'		; next LED
	btfsc	STATUS,Z	; if equal
	bsf		IC1_LED5,0	; set bit
	movf	STO_LEDVAL,w	; LED display
	xorlw	D'30'		; next LED
	btfsc	STATUS,Z	; if equal
	bsf		IC1_LED5,1	; set bit
	movlw	D'31'		; LED display max
	subwf	STO_LEDVAL,w	; next LED
	btfsc	STATUS,C	; if positive then drive LED
	bsf		IC1_LED5,2	; set bit i.e. drive this LED for all values from 31 and above
	return

; bar drive
BAR_DRV
	incf	LED_VALUE,w	; stored value for discrete LED display (0-35)
	movwf	STO_LEDVAL	; 
	sublw	D'00'		; lowest LED
	btfss	STATUS,C	; if equal
	bsf		IC1_LED4,4	; set bit
	movf	STO_LEDVAL,w	; LED display
	sublw	D'01'		; next LED
	btfss	STATUS,C	; if equal
	bsf		IC1_LED4,3	; set bit
	movf	STO_LEDVAL,w	; LED display
	sublw	D'02'		; next LED
	btfss	STATUS,C	; if equal
	bsf		IC1_LED4,2	; set bit
	movf	STO_LEDVAL,w	; LED display
	sublw	D'03'		; next LED
	btfss	STATUS,C	; if equal
	bsf		IC1_LED4,1	; set bit
	movf	STO_LEDVAL,w	; LED display
	sublw	D'04'		; next LED
	btfss	STATUS,C	; if equal
	bsf		IC1_LED4,0	; set bit
	movf	STO_LEDVAL,w	; LED display
	sublw	D'05'		; next LED
	btfss	STATUS,C	; if equal
	bsf		IC1_LED3,7	; set bit
	movf	STO_LEDVAL,w	; LED display
	sublw	D'06'		; next LED
	btfss	STATUS,C	; if equal
	bsf		IC1_LED3,6	; set bit
	movf	STO_LEDVAL,w	; LED display
	sublw	D'07'		; next LED
	btfss	STATUS,C	; if equal
	bsf		IC1_LED3,1	; set bit
	movf	STO_LEDVAL,w	; LED display
	sublw	D'08'		; next LED
	btfss	STATUS,C	; if equal
	bsf		IC1_LED3,2	; set bit
	movf	STO_LEDVAL,w	; LED display
	sublw	D'9'		; next LED
	btfss	STATUS,C	; if equal
	bsf		IC1_LED3,3	; set bit
	movf	STO_LEDVAL,w	; LED display
	sublw	D'10'		; next LED
	btfss	STATUS,C	; if equal
	bsf		IC1_LED3,4	; set bit
	movf	STO_LEDVAL,w	; LED display
	sublw	D'11'		; next LED
	btfss	STATUS,C	; if equal
	bsf		IC1_LED3,5	; set bit
	movf	STO_LEDVAL,w	; LED display
	sublw	D'12'		; next LED
	btfss	STATUS,C	; if equal
	bsf		IC2_LED2,7	; set bit
	movf	STO_LEDVAL,w	; LED display
	sublw	D'13'		; next LED
	btfss	STATUS,C	; if equal
	bsf		IC2_LED3,0	; set bit
	movf	STO_LEDVAL,w	; LED display
	sublw	D'14'		; next LED
	btfss	STATUS,C	; if equal
	bsf		IC2_LED2,6	; set bit
	movf	STO_LEDVAL,w	; LED display
	sublw	D'15'		; next LED
	btfss	STATUS,C	; if equal
	bsf		IC2_LED2,5	; set bit
	movf	STO_LEDVAL,w	; LED display
	sublw	D'16'		; next LED
	btfss	STATUS,C	; if equal
	bsf		IC2_LED2,4	; set bit
	movf	STO_LEDVAL,w	; LED display
	sublw	D'17'		; next LED
	btfss	STATUS,C	; if equal
	bsf		IC2_LED2,3	; set bit
	movf	STO_LEDVAL,w	; LED display
	sublw	D'18'		; next LED
	btfss	STATUS,C	; if equal
	bsf		IC2_LED2,2	; set bit
	movf	STO_LEDVAL,w	; LED display
	sublw	D'19'		; next LED
	btfss	STATUS,C	; if equal
	bsf		IC2_LED2,1	; set bit
	movf	STO_LEDVAL,w	; LED display
	sublw	D'20'		; next LED
	btfss	STATUS,C	; if equal
	bsf		IC2_LED2,0	; set bit
	movf	STO_LEDVAL,w	; LED display
	sublw	D'21'		; next LED
	btfss	STATUS,C	; if equal
	bsf		IC2_LED1,6	; set bit
	movf	STO_LEDVAL,w	; LED display
	sublw	D'22'		; next LED
	btfss	STATUS,C	; if equal
	bsf		IC2_LED1,5	; set bit
	movf	STO_LEDVAL,w	; LED display
	sublw	D'23'		; next LED
	btfss	STATUS,C	; if equal
	bsf		IC2_LED1,4	; set bit
	movf	STO_LEDVAL,w	; LED display
	sublw	D'24'		; next LED
	btfss	STATUS,C	; if equal
	bsf		IC2_LED1,3	; set bit
	movf	STO_LEDVAL,w	; LED display
	sublw	D'25'		; next LED
	btfss	STATUS,C	; if equal
	bsf		IC2_LED1,2	; set bit
	movf	STO_LEDVAL,w	; LED display
	sublw	D'26'		; next LED
	btfss	STATUS,C	; if equal
	bsf		IC2_LED1,1	; set bit
	movf	STO_LEDVAL,w	; LED display
	sublw	D'27'		; next LED
	btfss	STATUS,C	; if equal
	bsf		IC2_LED1,0	; set bit
	movf	STO_LEDVAL,w	; LED display
	sublw	D'28'		; next LED
	btfss	STATUS,C	; if equal
	bsf		IC1_LED4,7	; set bit
	movf	STO_LEDVAL,w	; LED display
	sublw	D'29'		; next LED
	btfss	STATUS,C	; if equal
	bsf		IC1_LED5,0	; set bit
	movf	STO_LEDVAL,w	; LED display
	sublw	D'30'		; next LED
	btfss	STATUS,C	; if equal
	bsf		IC1_LED5,1	; set bit
	movlw	D'32'		; LED display max
	subwf	STO_LEDVAL,w	; next LED
	btfsc	STATUS,C	; if positive then drive LED
	bsf		IC1_LED5,2	; set bit i.e. drive this LED for all values from 31 and above
	return

; subroutine for 7-segment display
SEVEN_SEG1
; check if update time expired
	movf	START_FLG,w	; start count down counter
	btfsc	STATUS,Z	; when zero start
	goto	START_DISPLAY
	goto	CLR_REG		; clear 
START_DISPLAY
	movf	UPDATE_TM,w	; update counter
	btfss	STATUS,Z	; if zero update display
	retlw	H'01'		; set at 1 to show that update is bypassed
	movf	UPDATE_CT,w	; stored update value
	movwf	UPDATE_TM

; show update time on porta,3
	btfss	PORTA,3
	goto	SET_3
	bcf		PORTA,3
	goto	CLR_REG
SET_3
	bsf		PORTA,3
CLR_REG
	call	CLEAR_REG	; clear display registers

; divide to get average rpm  
	movlw	H'00'		; clear
	movwf	AARGB0		; numerator 0 
	movf	TOTAL0,w	; ms of total rpm
	movwf	AARGB1
	movf	TOTAL1,w	;
	movwf	AARGB2		; 
	movf	TOTAL2,w	;
	movwf	AARGB3

	clrf	BARGB0
	clrf	BARGB1
	clrf	BARGB2
	movf	TALLY_CNT,w	; average tally count
	movwf	BARGB3

	call	FXD3232U	; divide to get rpm

; clear tally values
	clrf	TOTAL0
	clrf	TOTAL1
	clrf	TOTAL2
	clrf	TALLY_CNT
	btfss	AARGB0,7	; if set clear AARGB2 and 3 (0/0 gives FFFF)
	goto	CHECK_GTR
	clrf	AARGB2
	clrf	AARGB3
CHECK_GTR
; if >9999 set 10000rpm flag
	movf	AARGB2,w	; ms of 16 bit answer
	movwf	AARGB0		; for comparison
	movf	AARGB3,w	; ls byte of 16 bit answer
	movwf	AARGB1

	movlw	H'27'		; 9999
	movwf	BARGB0
	movlw	H'0F'
	movwf	BARGB1

	call	D_SUB
	bcf		TEN_THOU,0
	btfss	AARGB0,7	; if set then under 9999
	bsf		TEN_THOU,0	; set the over 10000 flag

SET_BCD
; set to BCD
; first see if in start up mode
	movf	START_FLG,w	; start count down counter
	btfsc	STATUS,Z	; when zero start
	goto	USE_VALUES
	decf	START_FLG,f	; reduce till zero
	clrf	AARGB2
	clrf	AARGB3
USE_VALUES
	movf	AARGB2,w	; ms of 16 bit answer
	movwf	BIN_1
	movf	AARGB3,w	; ls byte of 16 bit answer
	movwf	BIN_0
	call	BCD			; convert to BCD
						; Subroutine to convert from 16-bit binary to 3-digit BCD (packed)
						; Binary value is in BIN0 & BIN1. BIN0 is low byte BIN1 is high byte
						; Result in BCD is in BCD0, BCD1 & BCD2.  
						; BCD0 is MSB, BCD2 is LSB
; check if settings mode
	btfsc	SETTINGS,0	; if set then bypass these options
	goto	RUN_DISPLAY
	
; check options
; fixed digits (bits 3 and 4. 00=no fixed digits, 01=1rpm fixed at 0,10=1rpm and 10rpm digits at 0)
	movf	OPTIONS,w	; options
	andlw	B'00011000'	; extract bits 3 and 4 for fixed digits
	movwf	OPTION_STO
	btfsc	STATUS,Z 	; zero
	goto	DIGIT_SHIFT	; no change

	movf	OPTION_STO,w; check next option for fixed digits
	xorlw	B'00001000'	; 01 for 1rpm digit fixed
	btfsc	STATUS,Z
	goto	DIGITS_1RPM

	movf	OPTION_STO,w; check next option for fixed digits
	xorlw	B'00010000'	; 10 for 10rpm digit fixed
	btfss	STATUS,Z
	goto 	DIGIT_SHIFT	
DIGITS_10RPM
	clrf	BCD_2		; 1rpm and 10rpm digits to 0
	goto 	DIGIT_SHIFT	

DIGITS_1RPM
	movlw	B'11110000'	; set 1rpm digit to 0
	andwf	BCD_2,f
	
; options for digits shift (bits 2 and 1)
; 00=0-9999 display
; 01=0-9.999 to 10.00 x 1000rpm (dp shift)
; 11=0-9.99 to 10.00 x 1000rpm (no dp shift)  
DIGIT_SHIFT
	movf	OPTIONS,w	; options
	andlw	B'00000110'	; extract bits 1 and 2 for arrangement
	movwf	OPTION_STO
	btfsc	STATUS,Z	; if zero no change
	goto	RUN_DISPLAY

	movf	OPTION_STO,w
	xorlw	B'00000010'	; bit 1 set
	btfsc	STATUS,Z
	goto	DP_SHIFT

	movf	OPTION_STO,w
	xorlw	B'00000100'	; bit 2 set
	btfsc	STATUS,Z
	goto	OVR_10
DP_SHIFT
	btfsc	TEN_THOU,0	; if under or over 10,000rpm
	goto	OVR_10
	bsf		IC1_LED2,5	; under 10,000 drive decimal point digit 1
	goto	RUN_DISPLAY

DP_NO_SHIFT				; same as over 10000rpm for shift dp mode
OVR_10
	bsf		IC1_LED2,0	; drive DP digits 2

	bcf		STATUS,C	; carry clear
	rrf		BCD_0,f		; shift BCD values across
	rrf		BCD_1,f
	rrf		BCD_2,f 
	bcf		STATUS,C	; carry clear
	rrf		BCD_0,f		; shift BCD values across
	rrf		BCD_1,f
	rrf		BCD_2,f 
	bcf		STATUS,C	; carry clear
	rrf		BCD_0,f		; shift BCD values across
	rrf		BCD_1,f
	rrf		BCD_2,f 
	bcf		STATUS,C	; carry clear
	rrf		BCD_0,f		; shift BCD values across
	rrf		BCD_1,f
	rrf		BCD_2,f 
	goto	START_BCD
RUN_DISPLAY
; check settings
	btfsc	SETTINGS,1	; if set shift 
	goto	DP_NO_SHIFT	; shift for >10000rpm display
START_BCD
	movf	BCD_1,w
	andlw	H'F0'		; ms bits
	movwf	TEMP
	xorlw	H'10'		; if a 1
	btfsc	STATUS,Z
	goto	SEVN1_DSP1	; display 1 show 1
	movf	TEMP,w
	xorlw	H'20'		; if a 2
	btfsc	STATUS,Z
	goto	SEVN2_DSP1	; display 1 show 2
	movf	TEMP,w
	xorlw	H'30'		; if a 3
	btfsc	STATUS,Z
	goto	SEVN3_DSP1	; display 1 show 3
	movf	TEMP,w
	xorlw	H'40'		; if a 4
	btfsc	STATUS,Z
	goto	SEVN4_DSP1	; display 1 show 4
	movf	TEMP,w
	xorlw	H'50'		; if a 5
	btfsc	STATUS,Z
	goto	SEVN5_DSP1	; display 1 show 5
	movf	TEMP,w
	xorlw	H'60'		; if a 6
	btfsc	STATUS,Z
	goto	SEVN6_DSP1	; display 1 show 6
	movf	TEMP,w
	xorlw	H'70'		; if a 7
	btfsc	STATUS,Z
	goto	SEVN7_DSP1	; display 1 show 7
	movf	TEMP,w
	xorlw	H'80'		; if a 8
	btfsc	STATUS,Z
	goto	SEVN8_DSP1	; display 1 show 8
	movf	TEMP,w
	xorlw	H'90'		; if a 9
	btfsc	STATUS,Z
	goto	SEVN9_DSP1	; display 1 show 9
SEVN0_DSP1 ; 0
; ms digit if zero then a blank
	goto	SEVEN_SEG2	; next digit
SEVN9_DSP1 ; 9 
	bsf		IC2_LED3,5	; for segment B
	bsf		IC1_LED2,6	; for segment C
	bsf		IC2_LED3,4	; for segment A
	bsf		IC1_LED2,7	; for segment D
	bsf		IC2_LED3,2	; for segment F
	bsf		IC2_LED3,1	; for segment G
	goto	SEVEN_SEG2	; next digit
SEVN8_DSP1 ; 8 
	bsf		IC2_LED3,5	; for segment B
	bsf		IC1_LED2,6	; for segment C
	bsf		IC2_LED3,4	; for segment A
	bsf		IC1_LED2,7	; for segment D
	bsf		IC2_LED3,2	; for segment F
	bsf		IC2_LED3,1	; for segment G
	bsf		IC1_LED3,0	; for segment E
	goto	SEVEN_SEG2	; next digit
SEVN7_DSP1 ; 7 
	bsf		IC1_LED2,6	; for segment C
	bsf		IC2_LED3,4	; for segment A
	bsf		IC2_LED3,5	; for segment B
	goto	SEVEN_SEG2	; next digit
SEVN6_DSP1 ; 6 
	bsf		IC1_LED2,6	; for segment C
	bsf		IC2_LED3,4	; for segment A
	bsf		IC1_LED2,7	; for segment D
	bsf		IC2_LED3,2	; for segment F
	bsf		IC2_LED3,1	; for segment G
	bsf		IC1_LED3,0	; for segment E
	goto	SEVEN_SEG2	; next digit
SEVN5_DSP1 ; 5 
	bsf		IC1_LED2,6	; for segment C
	bsf		IC2_LED3,4	; for segment A
	bsf		IC1_LED2,7	; for segment D
	bsf		IC2_LED3,2	; for segment F
	bsf		IC2_LED3,1	; for segment G
	goto	SEVEN_SEG2	; next digit
SEVN4_DSP1 ; 4
	bsf		IC1_LED2,6	; for segment C
	bsf		IC2_LED3,5	; for segment B
	bsf		IC2_LED3,2	; for segment F
	bsf		IC2_LED3,1	; for segment G
	goto	SEVEN_SEG2	; next digit
SEVN3_DSP1 ; 3
	bsf		IC1_LED2,6	; for segment C
	bsf		IC2_LED3,5	; for segment B
	bsf		IC2_LED3,4	; for segment A
	bsf		IC1_LED2,7	; for segment D
	bsf		IC2_LED3,1	; for segment G
	goto	SEVEN_SEG2	; next digit
SEVN2_DSP1	; 2
	bsf		IC2_LED3,1	; for segment G
	bsf		IC2_LED3,5	; for segment B
	bsf		IC2_LED3,4	; for segment A
	bsf		IC1_LED2,7	; for segment D
	bsf		IC1_LED3,0	; for segment E
	goto	SEVEN_SEG2	; next digit
SEVN1_DSP1	; 1
	bsf		IC1_LED2,6	; for segment C
	bsf		IC2_LED3,5	; for segment B
;	goto	SEVEN_SEG2	; next digit

SEVEN_SEG2
	movf	BCD_1,w
	andlw	H'0F'		; ls bits
	movwf	TEMP
	xorlw	D'01'		; if a 1
	btfsc	STATUS,Z
	goto	SEVN1_DSP2	; display 2 show 1
	movf	TEMP,w
	xorlw	D'02'		; if a 2
	btfsc	STATUS,Z
	goto	SEVN2_DSP2	; display 2 show 2
	movf	TEMP,w
	xorlw	D'03'		; if a 3
	btfsc	STATUS,Z
	goto	SEVN3_DSP2	; display 2 show 3
	movf	TEMP,w
	xorlw	D'04'		; if a 4
	btfsc	STATUS,Z
	goto	SEVN4_DSP2	; display 2 show 4
	movf	TEMP,w
	xorlw	D'05'		; if a 5
	btfsc	STATUS,Z
	goto	SEVN5_DSP2	; display 2 show 5
	movf	TEMP,w
	xorlw	D'06'		; if a 6
	btfsc	STATUS,Z
	goto	SEVN6_DSP2	; display 2 show 6
	movf	TEMP,w
	xorlw	D'07'		; if a 7
	btfsc	STATUS,Z
	goto	SEVN7_DSP2	; display 2 show 7
	movf	TEMP,w
	xorlw	D'08'		; if a 8
	btfsc	STATUS,Z
	goto	SEVN8_DSP2	; display 2 show 8
	movf	TEMP,w
	xorlw	D'09'		; if a 9
	btfsc	STATUS,Z
	goto	SEVN9_DSP2	; display 2 show 9
SEVN0_DSP2 ; 0
	movf	BCD_1,w
	andlw	H'F0'		; ms bits
	xorlw	H'00'		; if ms digit was a zero then blank this digit too
	btfsc	STATUS,Z
	goto	SEVEN_SEG3
	bsf		IC2_LED4,2	; for segment B
	bsf		IC1_LED2,1	; for segment C
	bsf		IC2_LED4,1	; for segment A
	bsf		IC1_LED2,3	; for segment D
	bsf		IC2_LED3,7	; for segment F
	bsf		IC1_LED2,4	; for segment E
	goto	SEVEN_SEG3	; next digit
SEVN9_DSP2 ; 9 
	bsf		IC2_LED4,2	; for segment B
	bsf		IC1_LED2,1	; for segment C
	bsf		IC2_LED4,1	; for segment A
	bsf		IC1_LED2,3	; for segment D
	bsf		IC2_LED3,7	; for segment F
	bsf		IC2_LED3,6	; for segment G
	goto	SEVEN_SEG3	; next digit
SEVN8_DSP2 ; 8 
	bsf		IC2_LED4,2	; for segment B
	bsf		IC1_LED2,1	; for segment C
	bsf		IC2_LED4,1	; for segment A
	bsf		IC1_LED2,3	; for segment D
	bsf		IC2_LED3,7	; for segment F
	bsf		IC2_LED3,6	; for segment G
	bsf		IC1_LED2,4	; for segment E
	goto	SEVEN_SEG3	; next digit
SEVN7_DSP2 ; 7 
	bsf		IC2_LED4,2	; for segment B
	bsf		IC1_LED2,1	; for segment C
	bsf		IC2_LED4,1	; for segment A
	goto	SEVEN_SEG3	; next digit
SEVN6_DSP2 ; 6 
	bsf		IC1_LED2,1	; for segment C
	bsf		IC2_LED4,1	; for segment A
	bsf		IC1_LED2,3	; for segment D
	bsf		IC2_LED3,7	; for segment F
	bsf		IC2_LED3,6	; for segment G
	bsf		IC1_LED2,4	; for segment E
	goto	SEVEN_SEG3	; next digit
SEVN5_DSP2 ; 5 
	bsf		IC1_LED2,1	; for segment C
	bsf		IC2_LED4,1	; for segment A
	bsf		IC1_LED2,3	; for segment D
	bsf		IC2_LED3,7	; for segment F
	bsf		IC2_LED3,6	; for segment G
	goto	SEVEN_SEG3	; next digit
SEVN4_DSP2 ; 4
	bsf		IC2_LED4,2	; for segment B
	bsf		IC1_LED2,1	; for segment C
	bsf		IC2_LED3,7	; for segment F
	bsf		IC2_LED3,6	; for segment G
	goto	SEVEN_SEG3	; next digit
SEVN3_DSP2 ; 3
	bsf		IC2_LED4,2	; for segment B
	bsf		IC1_LED2,1	; for segment C
	bsf		IC2_LED4,1	; for segment A
	bsf		IC1_LED2,3	; for segment D
	bsf		IC2_LED3,6	; for segment G
	goto	SEVEN_SEG3	; next digit
SEVN2_DSP2	; 2
	bsf		IC2_LED4,2	; for segment B
	bsf		IC2_LED4,1	; for segment A
	bsf		IC1_LED2,3	; for segment D
	bsf		IC2_LED3,6	; for segment G
	bsf		IC1_LED2,4	; for segment E
	goto	SEVEN_SEG3	; next digit
SEVN1_DSP2	; 1
	bsf		IC2_LED4,2	; for segment B
	bsf		IC1_LED2,1	; for segment C
	goto	SEVEN_SEG3	; next digit

SEVEN_SEG3	; next digit
	movf	BCD_2,w
	andlw	H'F0'		; ls bits ou
	movwf	TEMP
	xorlw	H'10'		; if a 1
	btfsc	STATUS,Z
	goto	SEVN1_DSP3	; display 3 show 1
	movf	TEMP,w
	xorlw	H'20'		; if a 2
	btfsc	STATUS,Z
	goto	SEVN2_DSP3	; display 3 show 2
	movf	TEMP,w
	xorlw	H'30'		; if a 3
	btfsc	STATUS,Z
	goto	SEVN3_DSP3	; display 3 show 3
	movf	TEMP,w
	xorlw	H'40'		; if a 4
	btfsc	STATUS,Z
	goto	SEVN4_DSP3	; display 3 show 4
	movf	TEMP,w
	xorlw	H'50'		; if a 5
	btfsc	STATUS,Z
	goto	SEVN5_DSP3	; display 3 show 5
	movf	TEMP,w
	xorlw	H'60'		; if a 6
	btfsc	STATUS,Z
	goto	SEVN6_DSP3	; display 3 show 6
	movf	TEMP,w
	xorlw	H'70'		; if a 7
	btfsc	STATUS,Z
	goto	SEVN7_DSP3	; display 3 show 7
	movf	TEMP,w
	xorlw	H'80'		; if a 8
	btfsc	STATUS,Z
	goto	SEVN8_DSP3	; display 3 show 8
	movf	TEMP,w
	xorlw	H'90'		; if a 9
	btfsc	STATUS,Z
	goto	SEVN9_DSP3	; display 3 show 9
SEVN0_DSP3 ; 0
	movf	BCD_1,w
	andlw	H'F0'		; ms bits
	xorlw	H'00'		; if ms digit was a zero then blank check next digit
	btfss	STATUS,Z
	goto	ZRO3
	movf	BCD_1,w
	andlw	H'0F'		; ls bits
	xorlw	D'00'		; if digit was a zero then blank check next digit
	btfsc	STATUS,Z
	goto	SEVEN_SEG4	; blank
ZRO3
	bsf		IC2_LED4,6	; for segment B
	bsf		IC1_LED1,4	; for segment C
	bsf		IC2_LED4,5	; for segment A
	bsf		IC1_LED1,6	; for segment D
	bsf		IC2_LED4,4	; for segment F
	bsf		IC1_LED1,7	; for segment E
	goto	SEVEN_SEG4	; next digit
SEVN9_DSP3 ; 9 
	bsf		IC2_LED4,6	; for segment B
	bsf		IC1_LED1,4	; for segment C
	bsf		IC2_LED4,5	; for segment A
	bsf		IC1_LED1,6	; for segment D
	bsf		IC2_LED4,4	; for segment F
	bsf		IC2_LED4,3	; for segment G
	goto	SEVEN_SEG4	; next digit
SEVN8_DSP3 ; 8 
	bsf		IC2_LED4,6	; for segment B
	bsf		IC1_LED1,4	; for segment C
	bsf		IC2_LED4,5	; for segment A
	bsf		IC1_LED1,6	; for segment D
	bsf		IC2_LED4,4	; for segment F
	bsf		IC2_LED4,3	; for segment G
	bsf		IC1_LED1,7	; for segment E
	goto	SEVEN_SEG4	; next digit
SEVN7_DSP3 ; 7 
	bsf		IC2_LED4,6	; for segment B
	bsf		IC1_LED1,4	; for segment C
	bsf		IC2_LED4,5	; for segment A
	goto	SEVEN_SEG4	; next digit
SEVN6_DSP3 ; 6 
	bsf		IC1_LED1,4	; for segment C
	bsf		IC2_LED4,5	; for segment A
	bsf		IC1_LED1,6	; for segment D
	bsf		IC2_LED4,4	; for segment F
	bsf		IC2_LED4,3	; for segment G
	bsf		IC1_LED1,7	; for segment E
	goto	SEVEN_SEG4	; next digit
SEVN5_DSP3 ; 5 
	bsf		IC1_LED1,4	; for segment C
	bsf		IC2_LED4,5	; for segment A
	bsf		IC1_LED1,6	; for segment D
	bsf		IC2_LED4,4	; for segment F
	bsf		IC2_LED4,3	; for segment G
	goto	SEVEN_SEG4	; next digit
SEVN4_DSP3 ; 4
	bsf		IC2_LED4,6	; for segment B
	bsf		IC1_LED1,4	; for segment C
	bsf		IC2_LED4,4	; for segment F
	bsf		IC2_LED4,3	; for segment G
	goto	SEVEN_SEG4	; next digit
SEVN3_DSP3 ; 3
	bsf		IC2_LED4,6	; for segment B
	bsf		IC1_LED1,4	; for segment C
	bsf		IC2_LED4,5	; for segment A
	bsf		IC1_LED1,6	; for segment D
	bsf		IC2_LED4,3	; for segment G
	goto	SEVEN_SEG4	; next digit
SEVN2_DSP3	; 2
	bsf		IC2_LED4,6	; for segment B
	bsf		IC2_LED4,5	; for segment A
	bsf		IC1_LED1,6	; for segment D
	bsf		IC2_LED4,3	; for segment G
	bsf		IC1_LED1,7	; for segment E
	goto	SEVEN_SEG4	; next digit
SEVN1_DSP3	; 1
	bsf		IC2_LED4,6	; for segment B
	bsf		IC1_LED1,4	; for segment C
	goto	SEVEN_SEG4	; next digit

SEVEN_SEG4	; next digit
	movf	BCD_2,w
	andlw	H'0F'		; ls bits
	movwf	TEMP
	xorlw	D'01'		; if a 1
	btfsc	STATUS,Z
	goto	SEVN1_DSP4	; display 4 show 1
	movf	TEMP,w
	xorlw	D'02'		; if a 2
	btfsc	STATUS,Z
	goto	SEVN2_DSP4	; display 4 show 2
	movf	TEMP,w
	xorlw	D'03'		; if a 3
	btfsc	STATUS,Z
	goto	SEVN3_DSP4	; display 4 show 3
	movf	TEMP,w
	xorlw	D'04'		; if a 4
	btfsc	STATUS,Z
	goto	SEVN4_DSP4	; display 4 show 4
	movf	TEMP,w
	xorlw	D'05'		; if a 5
	btfsc	STATUS,Z
	goto	SEVN5_DSP4	; display 4 show 5
	movf	TEMP,w
	xorlw	D'06'		; if a 6
	btfsc	STATUS,Z
	goto	SEVN6_DSP4	; display 4 show 6
	movf	TEMP,w
	xorlw	D'07'		; if a 7
	btfsc	STATUS,Z
	goto	SEVN7_DSP4	; display 4 show 7
	movf	TEMP,w
	xorlw	D'08'		; if a 8
	btfsc	STATUS,Z
	goto	SEVN8_DSP4	; display 4 show 8
	movf	TEMP,w
	xorlw	D'09'		; if a 9
	btfsc	STATUS,Z
	goto	SEVN9_DSP4	; display 4 show 9

SEVN0_DSP4 ; 0
	bsf		IC2_LED5,2	; for segment B
	bsf		IC1_LED1,0	; for segment C
	bsf		IC2_LED5,1	; for segment A
	bsf		IC1_LED1,1	; for segment D
	bsf		IC2_LED5,0	; for segment F
	bsf		IC1_LED1,2	; for segment E
	retlw	H'0'		; set at o to show it has updated display
SEVN9_DSP4 ; 9 
	bsf		IC2_LED5,2	; for segment B
	bsf		IC1_LED1,0	; for segment C
	bsf		IC2_LED5,1	; for segment A
	bsf		IC1_LED1,1	; for segment D
	bsf		IC2_LED5,0	; for segment F
	bsf		IC2_LED4,7	; for segment G
	retlw	H'0'		; set at o to show it has updated display
SEVN8_DSP4 ; 8 
	bsf		IC2_LED5,2	; for segment B
	bsf		IC1_LED1,0	; for segment C
	bsf		IC2_LED5,1	; for segment A
	bsf		IC1_LED1,1	; for segment D
	bsf		IC2_LED5,0	; for segment F
	bsf		IC2_LED4,7	; for segment G
	bsf		IC1_LED1,2	; for segment E
	retlw	H'0'		; set at o to show it has updated display
SEVN7_DSP4 ; 7 
	bsf		IC2_LED5,2	; for segment B
	bsf		IC1_LED1,0	; for segment C
	bsf		IC2_LED5,1	; for segment A
	retlw	H'0'		; set at o to show it has updated display
SEVN6_DSP4 ; 6 
	bsf		IC1_LED1,0	; for segment C
	bsf		IC2_LED5,1	; for segment A
	bsf		IC1_LED1,1	; for segment D
	bsf		IC2_LED5,0	; for segment F
	bsf		IC2_LED4,7	; for segment G
	bsf		IC1_LED1,2	; for segment E
	retlw	H'0'		; set at o to show it has updated display
SEVN5_DSP4 ; 5 
	bsf		IC1_LED1,0	; for segment C
	bsf		IC2_LED5,1	; for segment A
	bsf		IC1_LED1,1	; for segment D
	bsf		IC2_LED5,0	; for segment F
	bsf		IC2_LED4,7	; for segment G
	retlw	H'0'		; set at o to show it has updated display
SEVN4_DSP4 ; 4
	bsf		IC2_LED5,2	; for segment B
	bsf		IC1_LED1,0	; for segment C
	bsf		IC2_LED5,0	; for segment F
	bsf		IC2_LED4,7	; for segment G
	retlw	H'0'		; set at o to show it has updated display
SEVN3_DSP4 ; 3
	bsf		IC2_LED5,2	; for segment B
	bsf		IC1_LED1,0	; for segment C
	bsf		IC2_LED5,1	; for segment A
	bsf		IC1_LED1,1	; for segment D
	bsf		IC2_LED4,7	; for segment G
	retlw	H'0'		; set at o to show it has updated display
SEVN2_DSP4	; 2
	bsf		IC1_LED1,2	; for segment E
	bsf		IC2_LED5,1	; for segment A
	bsf		IC1_LED1,1	; for segment D
	bsf		IC2_LED5,2	; for segment B
	bsf		IC2_LED4,7	; for segment G
	retlw	H'0'		; set at o to show it has updated display
SEVN1_DSP4	; 1
	bsf		IC2_LED5,2	; for segment B
	bsf		IC1_LED1,0	; for segment C
	retlw	H'0'		; set at o to show it has updated display

DRIVE_5451
; subroutine to drive LED display driver
; RA1 is clock
; RA0 is Data input for IC2
; RB7 is Data input for IC1
; IC1_LED1 to IC1_LED5 for IC1
; IC2_LED1 to IC2_LED5 for IC2

	movlw	D'35'		; input data clock counter 
	movwf	CLK_CNT		; clock counter
	bcf		PORTA,1		; clock low
	call	FIVE_CYC	; slow clock
	bsf		PORTA,0		; start bit data high IC2
	bsf		PORTB,7		; start bit data high IC1
	call	FIVE_CYC	; slow clock rate
	bsf		PORTA,1		; clock high
	call	FIVE_CYC	; slow clock rate
	bcf		PORTA,1		; clock low
	call	FIVE_CYC
; load data for 35 outputs
; IC1 data
RECYCLE_DATA
	rrf		IC1_LED5,f	; shift bits right by 1
	rrf		IC1_LED4,f	; shift bits right by 1
	rrf		IC1_LED3,f	; shift bits right by 1
	rrf		IC1_LED2,f	; shift bits right by 1
	rrf		IC1_LED1,f	; shift bits right by 1
	btfss	STATUS,C	; if carry set set data high
	goto	SET1_LOW
	bsf		PORTB,7		; data bit high IC1
	goto	BY_HIGH1
SET1_LOW
	bcf		PORTB,7		; data bit low IC1
BY_HIGH1
; IC2 data
	rrf		IC2_LED5,f	; shift bits right by 1
	rrf		IC2_LED4,f	; shift bits right by 1
	rrf		IC2_LED3,f	; shift bits right by 1
	rrf		IC2_LED2,f	; shift bits right by 1
	rrf		IC2_LED1,f	; shift bits right by 1
	btfss	STATUS,C	; if carry set set data high
	goto	SET2_LOW
	bsf		PORTA,0		; data bit high IC2
	goto	BY_HIGH2
SET2_LOW
	bcf		PORTA,0		; data bit low IC2
BY_HIGH2
	call	FIVE_CYC
; clock data
	bsf		PORTA,1		; clock high
	call	FIVE_CYC	; slow clock
	bcf		PORTA,1		; clock low
	call	FIVE_CYC	; slow clock

	decfsz	CLK_CNT,f
	goto	RECYCLE_DATA; continue for all data bits
	return
FIVE_CYC
	nop
	nop
	nop
	nop
	return 

; clear registers for LED display
CLEAR_REG	
	clrf	IC1_LED1
	clrf	IC1_LED2
	clrf	IC1_LED3
	clrf	IC1_LED4
	clrf	IC1_LED5
	clrf	IC2_LED1
	clrf	IC2_LED2
	clrf	IC2_LED3
	clrf	IC2_LED4
	clrf	IC2_LED5
	return

; subroutine to read EEPROM memory

EEREAD
	bcf		INTCON,PEIE	; disable peripheral interrupts	
	bcf 	STATUS,RP0	; select memory bank 
	bsf		STATUS,RP1	; bank 2
	movwf 	EEADR		; indirect special function register
	bsf 	STATUS,RP0	; select memory bank 3
	bcf		EECON1,EEPGD; pointer for data memory
	bsf		EECON1,RD	; read EEPROM
	bcf 	STATUS,RP0	; select memory bank 2
	movf	EEDATA,W	; EEPROM value in w
	bcf		STATUS,RP1	; select bank 0
	bsf		INTCON,PEIE	; enable peripheral interrupts
	return

; subroutine to write to EEPROM

EWRITE
	bcf		INTCON,PEIE	; disable peripheral interrupts
	bsf	    STATUS,RP1	; select bank 
	bcf 	STATUS,RP0	; select memory bank 2
	movwf	EEDATA		; data register
	bsf 	STATUS,RP0	; select memory bank 3
	bcf		EECON1,EEPGD; pointer for data memory
	bsf		EECON1,WREN	; enable write
	movlw	0x55		; place 55H in w for write sequence
	movwf 	EECON2 		; write 55H to EECON2
	movlw 	0xAA		; AAH to w
	movwf	EECON2		; write AA to EECON2
	bsf		EECON1,WR	; set WR bit and begin write sequence
	bcf		EECON1,WREN	; clear WREN bit
WRITE	
	btfsc	EECON1,WR	; skip if write complete WR=0 when write complete
	goto 	WRITE		; not written yet
	bcf		EECON1,EEIF	; clear write interrupt flag
	bcf		STATUS,RP0	; bank select
	bcf 	STATUS,RP1	; select memory bank 0 
	bsf		INTCON,PEIE	; enable peripheral interrupts
	return				; value written 

; Subroutine to convert from 16-bit binary to 3-digit BCD (packed)
; Binary value is in BIN0 & BIN1. BIN0 is low byte BIN1 is high byte
; Result in BCD is in BCD0, BCD1 & BCD2.  
; BCD0 is MSB, BCD2 is LSB

BCD	
	bcf		STATUS,C	; clear carry bit
	movlw	D'16'
	movwf	CNT_16		; 16 in count
	clrf	BCD_0
	clrf	BCD_1		; set BCD registers to 0 
	clrf	BCD_2
	

LOOPBCD
	rlf		BIN_0,f
	rlf		BIN_1,f		; LSB shift left binary registers
	rlf		BCD_2,f		; LSB shift left BCD registers
	rlf		BCD_1,f
	rlf		BCD_0,f

	decfsz	CNT_16,f	; reduce count value return when 0
	goto	DECADJ		; continue decimal adjust
	return				; completed decimal to BCD operation

; subroutine decimal adjust

DECADJ
	movlw	BCD_2		; BCD LSB address
	movwf	FSR			; pointer for BCD2
	call	ADJBCD		; subroutine to adjust BCD
	movlw	BCD_1
	movwf	FSR
	call 	ADJBCD
	movlw	BCD_0		; BCD MS address
	movwf	FSR			; pointer for BCD_0
	call	ADJBCD
	goto	LOOPBCD

; subroutine adjust BCD

ADJBCD
	movlw	H'03'		; w has 03 
	addwf	INDF,w		; add 03 to BCDx register (x is 0-2)
	movwf	TEMP		; store w
	btfsc	TEMP,3		; test if >7
	movwf	INDF		; save as LS digit
	movlw	H'30'		; 3 for MSbyte
	addwf	INDF,w		; add 30 to BCDx register
	movwf	TEMP		; store w
	btfsc	TEMP,7		; test if >7
	movwf	INDF		; save as MS digit
	return				; end subroutine

DELAY1
	movlw	D'1'
	goto	DELAY_1
DELAY
	movlw	D'50'		; number of delay cycles
DELAY_1	
	movwf	DELCNT

DELAY_M
	movlw	D'255'		; set delay period 
	movwf	VALUE_1		; VALUE_1 = w
LP_1
	movlw	D'255'		; set delay period value 2 
	movwf	VALUE_2		; VALUE_2 = w
LP_2
	decfsz	VALUE_2,f	; decrease VALUE_2, skip if zero
	goto 	LP_2
	decfsz	VALUE_1,f	; decrease VALUE_1, skip if zero
	goto	LP_1
	decfsz	DELCNT,f
	goto	DELAY_M
	return	

DELAYX
	movlw	D'02'
	movwf	VALUE_2
X_LOOP1
	movlw	D'140'
	movwf	VALUE_1
X_LOOP
	decfsz	VALUE_1,f
	goto	X_LOOP	
	decfsz	VALUE_2,f
	goto	X_LOOP1
	return

; subroutine subtract AARGB0 AARGB1 - BARGB0 BARGB1 = AARGB0 AARGB1
	
D_SUB
	call	NEG_A		; complement of A

	movf	BARGB1,w 
	addwf	AARGB1,f 	; add lsb
	btfsc	STATUS,C	; add carry
	incf	AARGB0,f 
	movf	BARGB0,w 
	addwf	AARGB0,f 
	return

NEG_A
	comf	BARGB1,f 
	incf	BARGB1,f 
	btfsc	STATUS,Z
	decf	BARGB0,f 
	comf	BARGB0,f 
	return	

;**********************************************************************************************

; 32/32 Bit Unsigned Fixed Point Divide 32/32 -> 32.32
; Input: 32 bit unsigned fixed point dividend in AARGB0, AARGB1,AARGB2,AARGB3
; 32 bit unsigned fixed point divisor in BARGB0, BARGB1, BARGB2, BARGB3
; Use: CALL FXD3232U
; Output: 32 bit unsigned fixed point quotient in AARGB0, AARGB1,AARGB2,AARGB3
; 32 bit unsigned fixed point remainder in REMB0, REMB1, REMB2, REMB3
; Result: AARG, REM <-- AARG / BARG
; Max Timing: 4+1025+2 = 1031 clks
; Max Timing: 4+981+2 = 987 clks
; PM: 4+359+1 = 364 DM: 13
FXD3232U
	CLRF 	REMB0
	CLRF	REMB1
	CLRF 	REMB2
	CLRF 	REMB3
	call	UDIV3232L
	return

UDIV3232L 
; Max Timing: 24+6*32+31+31+6*32+31+31+6*32+31+31+6*32+31+16 = 1025 clks
; Min Timing: 24+6*31+30+30+6*31+30+30+6*31+30+30+6*31+30+3 = 981 clks
; PM: 359 DM: 13
	CLRF 	TEMP
	RLF 	AARGB0,W
	RLF 	REMB3,F
	MOVF 	BARGB3,W
	SUBWF 	REMB3,F
	MOVF 	BARGB2,W
	BTFSS 	STATUS,C
	INCFSZ 	BARGB2,W
	SUBWF 	REMB2,F
	MOVF 	BARGB1,W
	BTFSS 	STATUS,C
	INCFSZ 	BARGB1,W
	SUBWF 	REMB1,F
	MOVF 	BARGB0,W
	BTFSS 	STATUS,C
	INCFSZ 	BARGB0,W
	SUBWF 	REMB0,F
	CLRW
	BTFSS 	STATUS,C
	MOVLW 	H'1'
	SUBWF 	TEMP,F
	RLF 	AARGB0,F
	MOVLW 	H'7'
	MOVWF 	LOOPCOUNT

LOOPU3232A 
	RLF 	AARGB0,W
	RLF 	REMB3,F
	RLF 	REMB2,F
	RLF 	REMB1,F
	RLF 	REMB0,F
	RLF 	TEMP,F
	MOVF 	BARGB3,W
	BTFSS 	AARGB0,0
	GOTO 	UADD22LA
	SUBWF 	REMB3,F
	MOVF 	BARGB2,W
	BTFSS 	STATUS,C
	INCFSZ 	BARGB2,W
	SUBWF 	REMB2,F
	MOVF 	BARGB1,W
	BTFSS	STATUS,C
	INCFSZ	BARGB1,W
	SUBWF 	REMB1,F
	MOVF 	BARGB0,W
	BTFSS 	STATUS,C
	INCFSZ 	BARGB0,W
	SUBWF 	REMB0,F
	CLRW
	BTFSS 	STATUS,C
	MOVLW 	H'1'
	SUBWF 	TEMP,F
	GOTO 	UOK22LA

UADD22LA 
	ADDWF 	REMB3,F
	MOVF 	BARGB2,W
	BTFSC 	STATUS,C
	INCFSZ 	BARGB2,W
	ADDWF 	REMB2,F
	MOVF 	BARGB1,W
	BTFSC	STATUS,C
	INCFSZ 	BARGB1,W
	ADDWF 	REMB1,F
	MOVF 	BARGB0,W
	BTFSC 	STATUS,C
	INCFSZ 	BARGB0,W
	ADDWF 	REMB0,F
	CLRW
	BTFSC 	STATUS,C
	MOVLW 	H'1'
	ADDWF 	TEMP,F

UOK22LA 
	RLF		AARGB0,F
	DECFSZ 	LOOPCOUNT,F
	GOTO 	LOOPU3232A
	RLF 	AARGB1,W
	RLF 	REMB3,F
	RLF 	REMB2,F
	RLF 	REMB1,F
	RLF 	REMB0,F
	RLF 	TEMP,F
	MOVF 	BARGB3,W
	BTFSS 	AARGB0,0
	GOTO 	UADD22L8
	SUBWF 	REMB3,F
	MOVF 	BARGB2,W
	BTFSS 	STATUS,C
	INCFSZ 	BARGB2,W
	SUBWF 	REMB2,F
	MOVF 	BARGB1,W
	BTFSS 	STATUS,C
	INCFSZ 	BARGB1,W
	SUBWF 	REMB1,F
	MOVF 	BARGB0,W
	BTFSS 	STATUS,C
	INCFSZ 	BARGB0,W
	SUBWF 	REMB0,F
	CLRW
	BTFSS 	STATUS,C
	MOVLW 	H'1'
	SUBWF 	TEMP,F
	GOTO 	UOK22L8

UADD22L8 
	ADDWF 	REMB3,F
	MOVF 	BARGB2,W
	BTFSC 	STATUS,C
	INCFSZ 	BARGB2,W
	ADDWF 	REMB2,F
	MOVF 	BARGB1,W
	BTFSC 	STATUS,C
	INCFSZ 	BARGB1,W
	ADDWF 	REMB1,F
	MOVF 	BARGB0,W
	BTFSC 	STATUS,C
	INCFSZ 	BARGB0,W
	ADDWF 	REMB0,F
	CLRW
	BTFSC 	STATUS,C
	MOVLW 	H'1'
	ADDWF 	TEMP,F

UOK22L8 
	RLF 	AARGB1,F
	MOVLW 	H'7'
	MOVWF 	LOOPCOUNT

LOOPU3232B 
	RLF 	AARGB1,W
	RLF 	REMB3,F
	RLF 	REMB2,F
	RLF 	REMB1,F
	RLF 	REMB0,F
	RLF 	TEMP,F
	MOVF 	BARGB3,W
	BTFSS 	AARGB1,0
	GOTO 	UADD22LB
	SUBWF 	REMB3,F
	MOVF 	BARGB2,W
	BTFSS 	STATUS,C
	INCFSZ 	BARGB2,W
	SUBWF 	REMB2,F
	MOVF 	BARGB1,W
	BTFSS 	STATUS,C
	INCFSZ 	BARGB1,W
	SUBWF 	REMB1,F
	MOVF 	BARGB0,W
	BTFSS 	STATUS,C
	INCFSZ 	BARGB0,W
	SUBWF 	REMB0,F
	CLRW
	BTFSS 	STATUS,C
	MOVLW 	H'1'
	SUBWF 	TEMP,F
	GOTO 	UOK22LB

UADD22LB 
	ADDWF 	REMB3,F
	MOVF 	BARGB2,W
	BTFSC 	STATUS,C
	INCFSZ 	BARGB2,W
	ADDWF 	REMB2,F
	MOVF 	BARGB1,W
	BTFSC 	STATUS,C
	INCFSZ 	BARGB1,W
	ADDWF 	REMB1,F
	MOVF 	BARGB0,W
	BTFSC 	STATUS,C
	INCFSZ 	BARGB0,W
	ADDWF 	REMB0,F
	CLRW
	BTFSC 	STATUS,C
	MOVLW 	H'1'
	ADDWF 	TEMP,F

UOK22LB 
	RLF 	AARGB1,F
	DECFSZ 	LOOPCOUNT,F
	GOTO 	LOOPU3232B
	RLF 	AARGB2,W
	RLF 	REMB3,F
	RLF 	REMB2,F
	RLF 	REMB1,F
	RLF 	REMB0,F
	RLF 	TEMP,F
	MOVF 	BARGB3,W
	BTFSS	AARGB1,0
	GOTO 	UADD22L16
	SUBWF 	REMB3,F
	MOVF 	BARGB2,W
	BTFSS 	STATUS,C
	INCFSZ 	BARGB2,W
	SUBWF 	REMB2,F
	MOVF 	BARGB1,W
	BTFSS	STATUS,C
	INCFSZ 	BARGB1,W
	SUBWF 	REMB1,F
	MOVF 	BARGB0,W
	BTFSS 	STATUS,C
	INCFSZ 	BARGB0,W
	SUBWF 	REMB0,F
	CLRW
	BTFSS 	STATUS,C
	MOVLW 	H'1'
	SUBWF 	TEMP,F
	GOTO 	UOK22L16

UADD22L16 	
	ADDWF 	REMB3,F
	MOVF 	BARGB2,W
	BTFSC 	STATUS,C
	INCFSZ 	BARGB2,W
	ADDWF 	REMB2,F
	MOVF 	BARGB1,W
	BTFSC 	STATUS,C
	INCFSZ 	BARGB1,W
	ADDWF 	REMB1,F
	MOVF 	BARGB0,W
	BTFSC 	STATUS,C
	INCFSZ 	BARGB0,W
	ADDWF 	REMB0,F
	CLRW
	BTFSC 	STATUS,C
	MOVLW 	H'1'
	ADDWF	TEMP,F

UOK22L16
	RLF		AARGB2,F
	MOVLW 	H'7'
	MOVWF 	LOOPCOUNT

LOOPU3232C 
	RLF 	AARGB2,W
	RLF 	REMB3,F
	RLF 	REMB2,F
	RLF 	REMB1,F
	RLF 	REMB0,F
	RLF 	TEMP,F
	MOVF 	BARGB3,W
	BTFSS 	AARGB2,0
	GOTO 	UADD22LC
	SUBWF 	REMB3,F
	MOVF 	BARGB2,W
	BTFSS 	STATUS,C
	INCFSZ 	BARGB2,W
	SUBWF 	REMB2,F
	MOVF 	BARGB1,W
	BTFSS	STATUS,C
	INCFSZ 	BARGB1,W
	SUBWF 	REMB1,F
	MOVF 	BARGB0,W
	BTFSS 	STATUS,C
	INCFSZ 	BARGB0,W
	SUBWF 	REMB0,F
	CLRW
	BTFSS 	STATUS,C
	MOVLW 	H'1'
	SUBWF 	TEMP,F
	GOTO 	UOK22LC

UADD22LC
	ADDWF 	REMB3,F
	MOVF 	BARGB2,W
	BTFSC 	STATUS,C
	INCFSZ 	BARGB2,W
	ADDWF 	REMB2,F
	MOVF 	BARGB1,W
	BTFSC 	STATUS,C
	INCFSZ 	BARGB1,W
	ADDWF 	REMB1,F
	MOVF 	BARGB0,W
	BTFSC 	STATUS,C
	INCFSZ 	BARGB0,W
	ADDWF 	REMB0,F
	CLRW
	BTFSC 	STATUS,C
	MOVLW 	H'1'
	ADDWF 	TEMP,F

UOK22LC 
	RLF 	AARGB2,F
	DECFSZ 	LOOPCOUNT,F
	GOTO 	LOOPU3232C
	RLF 	AARGB3,W
	RLF 	REMB3,F
	RLF 	REMB2,F
	RLF 	REMB1,F
	RLF 	REMB0,F
	RLF 	TEMP,F
	MOVF 	BARGB3,W
	BTFSS 	AARGB2,0
	GOTO 	UADD22L24
	SUBWF 	REMB3,F
	MOVF 	BARGB2,W
	BTFSS 	STATUS,C
	INCFSZ 	BARGB2,W
	SUBWF 	REMB2,F
	MOVF 	BARGB1,W
	BTFSS 	STATUS,C
	INCFSZ 	BARGB1,W
	SUBWF 	REMB1,F
	MOVF 	BARGB0,W
	BTFSS 	STATUS,C
	INCFSZ 	BARGB0,W
	SUBWF 	REMB0,F
	CLRW
	BTFSS 	STATUS,C
	MOVLW 	H'1'
	SUBWF 	TEMP,F
	GOTO 	UOK22L24

UADD22L24 
	ADDWF 	REMB3,F
	MOVF 	BARGB2,W
	BTFSC 	STATUS,C
	INCFSZ 	BARGB2,W
	ADDWF 	REMB2,F
	MOVF 	BARGB1,W
	BTFSC 	STATUS,C
	INCFSZ 	BARGB1,W
	ADDWF 	REMB1,F
	MOVF 	BARGB0,W
	BTFSC 	STATUS,C
	INCFSZ 	BARGB0,W
	ADDWF 	REMB0,F
	CLRW
	BTFSC 	STATUS,C
	MOVLW 	H'1'
	ADDWF 	TEMP,F

UOK22L24 
	RLF 	AARGB3,F
	MOVLW 	H'7'
	MOVWF 	LOOPCOUNT

LOOPU3232D 
    RLF  	AARGB3,W
    RLF    	REMB3,F
    RLF    	REMB2,F
    RLF    	REMB1,F
    RLF    	REMB0,F
    RLF    	TEMP,F
    MOVF   	BARGB3,W
 	BTFSS  	AARGB3,0
   	GOTO   	UADD22LD

    SUBWF  	REMB3,F
  	MOVF   	BARGB2,W
    BTFSS   STATUS,C
    INCFSZ  BARGB2,W
    SUBWF   REMB2,F
    MOVF    BARGB1,W
    BTFSS   STATUS,C
    INCFSZ  BARGB1,W
    SUBWF   REMB1,F
    MOVF    BARGB0,W
    BTFSS   STATUS,C
    INCFSZ  BARGB0,W
    SUBWF   REMB0,F
    CLRW
    BTFSS   STATUS,C
    MOVLW   H'1'
    SUBWF   TEMP,F
    GOTO    UOK22LD

UADD22LD      
	ADDWF   REMB3,F
    MOVF    BARGB2,W
    BTFSC   STATUS,C
    INCFSZ  BARGB2,W
    ADDWF   REMB2,F
    MOVF    BARGB1,W
    BTFSC   STATUS,C
    INCFSZ  BARGB1,W
    ADDWF   REMB1,F
    MOVF    BARGB0,W
    BTFSC   STATUS,C
    INCFSZ  BARGB0,W
    ADDWF   REMB0,F
    CLRW
    BTFSC   STATUS,C
    MOVLW   H'1'
    ADDWF   TEMP,F
        
UOK22LD
	RLF     AARGB3,F

   	DECFSZ  LOOPCOUNT, F
    GOTO    LOOPU3232D

    BTFSC   AARGB3,0
    GOTO    UOK22L
    MOVF    BARGB3,W
	ADDWF   REMB3,F
    MOVF    BARGB2,W
    BTFSC   STATUS,C
    INCFSZ  BARGB2,W
    ADDWF   REMB2,F
    MOVF    BARGB1,W
    BTFSC   STATUS,C
    INCFSZ  BARGB1,W
    ADDWF   REMB1,F
    MOVF    BARGB0,W
    BTFSC   STATUS,C
    INCFSZ  BARGB0,W
    ADDWF   REMB0,F

UOK22L

	RETURN

; ###############################################################################
; settings mode
; allows the settings to be changed
; press UP switch at power up to initiate this routine

; set at page 1
	org		H'800'		; page 1
	
WAIT_OPEN
	movlw	D'5'		; delay for debounce switch
	bcf		PCLATH,3	; page 0
	call	DELAY_1
	movlw	H'22'
	movwf	AARGB2		; display value ms byte write 8888 to test displays
	movlw	H'B8'
	movwf	AARGB3		; ls byte 
	bsf		PORTA,2		; label LED on
	bcf		PORTB,1		; Setting LED off
	call	CLEAR_REG	; clear display registers
	call	USE_VALUES	; SET_BCD and load 7-segment displays
	bsf		IC1_LED2,5	; drive decimal point digit 1
	bsf		IC1_LED2,0	; drive decimal point digit 2
	bsf		PCLATH,3	; page 1

; also scan LED bargraph display
	movf	LED_VALUE,w
	sublw	D'32'		; if negative light shift light
	btfsc	STATUS,C
	goto	BY_TEST_SET
LITE_SHIFT_TEST
	bsf		NO_BAR,0
	clrf	LED_VALUE	; back to 0

; if NO_BAR,0 set then drive Shift light
BY_TEST_SET
	btfss	NO_BAR,0
	goto 	END_SHFT
	bsf		IC2_LED1,7	; shift light test
	clrf	NO_BAR
	goto	BY_DOT
END_SHFT
	bcf		PCLATH,3	; page 0
	call	DOT_DRV		; dot drive test
	movlw	D'1'		; delay 
	call	DELAY_1
	incf	LED_VALUE,f	; next LED
BY_DOT
	bcf		PCLATH,3	; page 0
	call	DRIVE_5451	; send values to M5451s
	bsf		PCLATH,3	; page 1

	btfss	PORTB,5		; wait till open
	goto	WAIT_OPEN
	movlw	D'5'		; delay for switch opening
	bcf		PCLATH,3	; page 0
	call	DELAY_1
	bsf		PCLATH,3	; page 1
	bsf		SETTINGS,0	; if set then display runs for settings 
	
; read switches and change settings accordingly
; toggle switch changes diplay from Label to setting value (LEDs show selection)
; changes are stored in EEPROM
; if (settings bit1) set then display is shifted to show >9999
; settings bit 2 selects settings or label display	

; display values
; Labels
; 1: Cylinder number 1,2,3,4,5,6,8,10,12
; 2: No. red LEDs 0 to 10
; 3: Red Line rpm 
; 4; rpm/LED
; 5: Shift Light rpm
; 6; limit rpm 
; 7: Hysteresis 0 to 255rpm
; 8: Update period for segment display 0 to 255 1=2ms, 100=200ms
; 9: Display format 0:9999, 1:9.999 to 10.00 2:9.99 to 10.99
; 10: Fixed digits (0, 1rpm, 10rpm)
; 11: Dot or Bar graph
; 12: limit sense
; 13: limit timer
  		
DISPLAY_VALUES
	btfsc	SETTINGS,2	; if clear then label display
	goto	DISPLAY_SETTINGS
	incf	LABEL,w		; current label value
	movwf	AARGB3		; display value ls byte
	clrf	AARGB2		; ms byte clear
	bsf		PORTA,2		; label LED on
	bcf		PORTB,1		; Setting LED off
SET_ARRANGE
	bcf		SETTINGS,1	; display not shifted
SET_ARRANGE_SHIFT
	bcf		PCLATH,3	; page 0
	call	CLEAR_REG	; clear display registers
	call	USE_VALUES	; SET_BCD and load 7-segment displays
	call	DRIVE_5451	; send values to M5451s
	bsf		PCLATH,3	; page 1
	btfss	DELAY_FLG,0	; if set add delay
	goto	CHECK_SW	
	movlw	D'13'		; delay 
	bcf		PCLATH,3	; page 0
	call	DELAY_1
	bsf		PCLATH,3	; page 1
	clrf	DELAY_FLG	; delay flag off
	goto	CHECK_SW	; check switches
; Settings
DISPLAY_SETTINGS
	bcf		PORTA,2		; label LED off
	bsf		PORTB,1		; Setting LED on
	incf	LABEL,w		; get current label setting
	xorlw	H'01'		; cylinder number
	btfsc	STATUS,Z 
	goto	CYLINDER
	incf	LABEL,w		; get current label setting
	xorlw	H'02'		; red LEDs number
	btfsc	STATUS,Z 
	goto	RED_LED
	incf	LABEL,w		; get current label setting
	xorlw	H'03'		; red line rpm
	btfsc	STATUS,Z 
	goto	RED_LINE
	incf	LABEL,w		; get current label setting
	xorlw	H'04'		; rpm/LED
	btfsc	STATUS,Z 
	goto	RPM_LED		; rpm/LED value
	incf	LABEL,w		; get current label setting
	xorlw	H'05'		; shift light rpm
	btfsc	STATUS,Z 
	goto	SHIFT_LITE
	incf	LABEL,w		; get current label setting
	xorlw	H'06'		; limit rpm
	btfsc	STATUS,Z 
	goto	LIMIT_SET
	incf	LABEL,w		; get current label setting
	xorlw	H'07'		; Hysteresis rpm
	btfsc	STATUS,Z 
	goto	HYSTER_DSP
	incf	LABEL,w		; get current label setting
	xorlw	H'08'		; Update period
	btfsc	STATUS,Z 
	goto	UPDATE_DSP
	incf	LABEL,w		; get current label setting
	xorlw	H'09'		; display format
	btfsc	STATUS,Z 
	goto	FORMAT_DSP
	incf	LABEL,w		; get current label setting
	xorlw	D'10'		; fixed digits
	btfsc	STATUS,Z 
	goto	FIXED_DSP
	incf	LABEL,w		; get current label setting
	xorlw	D'11'		; dot/bar
	btfsc	STATUS,Z 
	goto	DOT_BAR_DSP
	incf	LABEL,w		; get current label setting
	xorlw	D'12'		; limit sense
	btfsc	STATUS,Z 
	goto	LIMIT_SENSE_0
	incf	LABEL,w		; get current label setting
	xorlw	D'13'		; limit timer
	btfsc	STATUS,Z 
	goto	LIMIT_TIME
CYLINDER				; write cylinder value
	movf	CYL_SET,w	
LOAD_AARGB
	movwf	AARGB3
	clrf	AARGB2
	goto	SET_ARRANGE	; show value
RED_LED
	movf	RED_LEDS,w	; red LEDs count
	goto	LOAD_AARGB
RED_LINE		
	movf	RED_LINE1,w	; get values
	movwf	AARGB2
	movf	RED_LINE2,w
	movwf	AARGB3
	bsf		SETTINGS,1	; display shifted
	goto	SET_ARRANGE_SHIFT
RPM_LED
	movf	TACHO_CAL1,w; get values
	movwf	AARGB2
	movf	TACHO_CAL2,w
	movwf	AARGB3
	goto	SET_ARRANGE
SHIFT_LITE
	movf	SHIFT1,w	; get values
	movwf	AARGB2
	movf	SHIFT2,w
	movwf	AARGB3
	bsf		SETTINGS,1	; display shifted
	goto	SET_ARRANGE_SHIFT
LIMIT_SET
	movf	LIMIT1,w	; get values
	movwf	AARGB2
	movf	LIMIT2,w
	movwf	AARGB3
	bsf		SETTINGS,1	; display shifted
	goto	SET_ARRANGE_SHIFT
HYSTER_DSP
	movf	HYSTERESIS,w
	goto	LOAD_AARGB
UPDATE_DSP
	movf	UPDATE_CT,w
	movwf	AARGB3
	clrf	AARGB2
	bcf		STATUS,C	; carry cleared
	rlf		AARGB3,f	; mult by 2	
	btfsc	STATUS,C	; if carry set set bit 0 in ms byte
	bsf		AARGB2,0 
	goto	SET_ARRANGE	; show value
FORMAT_DSP
	movlw	H'00'		; start at 0
	btfsc	OPTIONS,1	; options bit 1 
	movlw	H'01'		; load 1 if bit 1 set
	btfsc	OPTIONS,2	; bit 2 check
	movlw	H'02'		; 2 if bit 2 set
	goto	LOAD_AARGB
FIXED_DSP
	movlw	H'00'		; zero to start
; options bits 3 and 4
	btfsc	OPTIONS,3
	movlw	H'1'		; 1 rpm
	btfsc	OPTIONS,4
	movlw	D'10'		; 10 rpm
	goto	LOAD_AARGB	
DOT_BAR_DSP
	movlw	H'00'		; start at 0
	btfsc	OPTIONS,0	; dot bar select
	movlw	H'01'
	goto	LOAD_AARGB	; 0 for dot 1 for bar
LIMIT_SENSE_0
	movlw	H'00'		; start at 0
	btfsc	LIMIT_SENSE,0	; sense
	movlw	H'01'
	goto	LOAD_AARGB	; 0 for low (high to limit) 1 for high (low to limit)
LIMIT_TIME	
	movf	LIMIT_ON,w
	movwf	AARGB3
	clrf	AARGB2
	bcf		STATUS,C	; carry cleared
	rlf		AARGB3,f	; mult by 2	
	btfsc	STATUS,C	; if carry set set bit 0 in ms byte
	bsf		AARGB2,0 
	goto	SET_ARRANGE	; show value 

; check switches (if any of RB2,3,4 or 5 are low then pressed)
CHECK_SW
	movf	PORTB,w		
	andlw	B'00111100'	; keep switch bits
	xorlw	B'00111100'	; if all high switches are off
	btfsc	STATUS,Z
	goto	DISPLAY_VALUES	; no switch closed

; switch closed check which one
	btfss	PORTB,2		; if toggle switch
	goto	TOGGLE
	btfss	PORTB,5		; Up switch
	goto	UP_SW
	btfss	PORTB,4		; Down switch
	goto	DOWN_SW
	goto	DISPLAY_VALUES

; toggle label/settings
TOGGLE
	btfss	SETTINGS,2	; if clear then set
	goto	SET_SET
	bcf		SETTINGS,2	; clear
	goto	CLEARED_LABEL
SET_SET
	bsf		SETTINGS,2	; set
CLEARED_LABEL
	bsf		DELAY_FLG,0	; set flag to add delay
	goto	DISPLAY_VALUES

; UP/DN switches. Check if label or settings mode
; if label then increase or decrease LABEL value from 0 to 8 (shown as 1 to 9) 
; if settings then change with up/dn switches	
UP_SW
	btfsc	SETTINGS,2	; if clear then label display
	goto	UP_SETTINGS
	movf	LABEL,w
	sublw	D'11'		; stop at 13
	btfss	STATUS,C	; if negative stop any increase
	goto	CLR_LABEL
	incf	LABEL,f
	bsf		DELAY_FLG,0	; set flag to add delay
	goto	DISPLAY_VALUES
CLR_LABEL
	clrf	LABEL
	bsf		DELAY_FLG,0	; set flag to add delay
	goto	DISPLAY_VALUES
UP_SETTINGS
		
	incf	LABEL,w		; get current label setting
	xorlw	H'01'		; cylinder number
	btfsc	STATUS,Z 
	goto	UP_CYLINDER
	incf	LABEL,w		; get current label setting
	xorlw	H'02'		; red LEDs number
	btfsc	STATUS,Z 
	goto	UP_RED_LED
	incf	LABEL,w		; get current label setting
	xorlw	H'03'		; red line rpm
	btfsc	STATUS,Z 
	goto	UP_RED_LINE
	incf	LABEL,w		; get current label setting
	xorlw	H'05'		; shift light rpm
	btfsc	STATUS,Z 
	goto	UP_SHIFT_LITE
	incf	LABEL,w		; get current label setting
	xorlw	H'06'		; Limit rpm
	btfsc	STATUS,Z 
	goto	UP_LIMIT_SET
	incf	LABEL,w		; get current label setting
	xorlw	H'07'		; Hysteresis rpm
	btfsc	STATUS,Z 
	goto	UP_HYSTER_DSP
	incf	LABEL,w		; get current label setting
	xorlw	H'08'		; Update period
	btfsc	STATUS,Z 
	goto	UP_UPDATE_DSP
	incf	LABEL,w		; get current label setting
	xorlw	H'09'		; display format
	btfsc	STATUS,Z 
	goto	UP_FORMAT_DSP
	incf	LABEL,w		; get current label setting
	xorlw	D'10'		; fixed digits
	btfsc	STATUS,Z 
	goto	UP_FIXED_DSP
	incf	LABEL,w		; get current label setting
	xorlw	D'11'		; dot/bar
	btfsc	STATUS,Z 
	goto	UP_DOT_BAR_DSP
	incf	LABEL,w		; get current label setting
	xorlw	D'12'		; limit sense
	btfsc	STATUS,Z 
	goto	UP_LIMIT_DSP
	incf	LABEL,w		; get current label setting
	xorlw	D'13'		; limit time
	btfsc	STATUS,Z 
	goto	UP_LIMIT_TM
	goto	DISPLAY_VALUES	; bypass up/dn if mode 4 (rpm/LED)

UP_CYLINDER				; set next cylinder value
	movf	CYL_SET,w	; cylinder setting (1-12)
	sublw	D'11'
	btfss	STATUS,C	; if 12 change to 1
	goto	DISPLAY_VALUES	; no change if at 12
	incf	CYL_SET,f
CYLINDER_WRITE			; write to cylinder EEPROM
	movlw	EEPROM5		; cylinder setting
	bcf		PCLATH,3	; page 0
	call	EEREAD		; sets EEADR
	movf	CYL_SET,w
	call	EWRITE		; write to EEPROM
	bsf		PCLATH,3	; page 1
	bsf		DELAY_FLG,0	; set to add delay
	goto	DISPLAY_VALUES
	
UP_RED_LED				; set RED LEDs
	movf	RED_LEDS,w	; No. red LEDS (0-10)
	sublw	D'9'
	btfss	STATUS,C	; if 10 
	goto	DISPLAY_VALUES	; no change if at 10
	incf	RED_LEDS,f
RED_LED_WRITE			; write to cylinder EEPROM
	movlw	EEPROM2		; cylinder setting
	bcf		PCLATH,3	; page 0
	call	EEREAD		; sets EEADR
	movf	RED_LEDS,w
	call	EWRITE		; write to EEPROM
	bsf		PCLATH,3	; page 1
	bsf		DELAY_FLG,0	; set to add delay

; calculate new rpm/LED RED_LINE1, RED_LINE2/(32-No.red LEDs)
; subtract red LEDs from 32
CALC_NEW_RPM_LED
	clrf	AARGB0
	clrf	BARGB0		; ms bytes cleared
	movf	RED_LEDS,w	; No. red LEDS
	movwf	BARGB1		; ls byte
	movlw	D'32'		; total LEDs
	movwf	AARGB1
	bcf		PCLATH,3	; page 0
	call	D_SUB		; subtract 32-RED LEDs

; divide to get rpm/LED	
	movf	AARGB1,w	; result
	movwf	BARGB3		; denominator
	clrf	BARGB2		; cleared
	clrf	BARGB1
	clrf	BARGB0
	clrf	AARGB0
	clrf	AARGB1
	movf	RED_LINE1,w	; ms redline rpm
	movwf	AARGB2
	movf	RED_LINE2,w	; ls redline rpm
	movwf	AARGB3
	call	FXD3232U	; divide to get rpm/LED
	bsf		PCLATH,3	; page 1
	movf	AARGB2,w	; ms byte
	movwf	TACHO_CAL1
	movf	AARGB3,w
	movwf	TACHO_CAL2

	movlw	EEPROM3		; ms rpm/LED
	bcf		PCLATH,3	; page 0
	call	EEREAD		; sets EEADR
	movf	TACHO_CAL1,w
	call	EWRITE		; write to EEPROM
	movlw	EEPROM4		; ls rpm/LED
	call	EEREAD		; sets EEADR
	movf	TACHO_CAL2,w
	call	EWRITE		; write to EEPROM
	bsf		PCLATH,3	; page 1
	goto	DISPLAY_VALUES

UP_RED_LINE
	movf	RED_LINE1,w	; check value
	sublw	D'98'
	btfss	STATUS,C	; if 99
	goto	DISPLAY_VALUES	; no change if at 99
	movlw	D'100'		; add 100rpm each time
	addwf	RED_LINE2,f	; add 100
	btfsc	STATUS,C	; if carry set increase ms byte
	incf	RED_LINE1,f	; increase ms byte
; write to EEPROM
UP_RED_LINE_WRITE
	bsf		DELAY_FLG,0	; set flag to add delay
	movlw	EEPROM0		; ms RPM red line
	bcf		PCLATH,3	; page 0
	call	EEREAD		; sets EEADR
	movf	RED_LINE1,w
	call	EWRITE		; write to EEPROM
	movlw	EEPROM1		; ls rpm
	call	EEREAD		; sets EEADR
	movf	RED_LINE2,w
	call	EWRITE		; write to EEPROM
	bsf		PCLATH,3	; page 1
; recalculate rpm/LED
	goto	CALC_NEW_RPM_LED

UP_SHIFT_LITE
	movf	SHIFT1,w	; check value
	sublw	D'98'
	btfss	STATUS,C	; if 99
	goto	DISPLAY_VALUES	; no change if at 99
	movlw	D'100'		; add 100rpm each time
	addwf	SHIFT2,f	; add 100
	btfsc	STATUS,C	; if carry set increase ms byte
	incf	SHIFT1,f	; increase ms byte
; write to EEPROM
UP_SHIFT_LITE_WRITE
	bsf		DELAY_FLG,0	; set flag to add delay
	movlw	EEPROM6		; ms RPM shift
	bcf		PCLATH,3	; page 0
	call	EEREAD		; sets EEADR
	movf	SHIFT1,w
	call	EWRITE		; write to EEPROM
	movlw	EEPROM7		; ls rpm
	call	EEREAD		; sets EEADR
	movf	SHIFT2,w
	call	EWRITE		; write to EEPROM
	bsf		PCLATH,3	; page 1
	goto	DISPLAY_VALUES
UP_LIMIT_SET
	movf	LIMIT1,w	; check value
	sublw	D'98'
	btfss	STATUS,C	; if 99
	goto	DISPLAY_VALUES	; no change if at 99
	movlw	D'100'		; add 100rpm each time
	addwf	LIMIT2,f	; add 100
	btfsc	STATUS,C	; if carry set increase ms byte
	incf	LIMIT1,f	; increase ms byte
; write to EEPROM
UP_LIMIT_SET_WRITE
	bsf		DELAY_FLG,0	; set flag to add delay
	movlw	EEPROMB		; ms limit rpm
	bcf		PCLATH,3	; page 0
	call	EEREAD		; sets EEADR
	movf	LIMIT1,w
	call	EWRITE		; write to EEPROM
	movlw	EEPROMC		; ls rpm
	call	EEREAD		; sets EEADR
	movf	LIMIT2,w
	call	EWRITE		; write to EEPROM
	bsf		PCLATH,3	; page 1
	goto	DISPLAY_VALUES

UP_HYSTER_DSP
	movf	HYSTERESIS,w; HYSTERESIS 0 to 255 rpm
	sublw	D'254'
	btfss	STATUS,C	; if 255
	goto	DISPLAY_VALUES	; no change if at 12
	incf	HYSTERESIS,f
HYSTERESIS_WRITE		; write to EEPROM
	movlw	EEPROMA		;  setting
	bcf		PCLATH,3	; page 0
	call	EEREAD		; sets EEADR
	movf	HYSTERESIS,w
	call	EWRITE		; write to EEPROM
	bsf		PCLATH,3	; page 1
	bsf		DELAY_FLG,0	; set to add delay
	goto	DISPLAY_VALUES

UP_UPDATE_DSP
	movf	UPDATE_CT,w	; UPDATE period 0 to 255 (ms x 2) eg 100=200ms
	sublw	D'254'
	btfss	STATUS,C	; if 255
	goto	DISPLAY_VALUES	; no change if at 255
	incf	UPDATE_CT,f
UP_DATE_WRITE			; write to EEPROM
	movlw	EEPROM9		;  setting
	bcf		PCLATH,3	; page 0
	call	EEREAD		; sets EEADR
	movf	UPDATE_CT,w
	call	EWRITE		; write to EEPROM
	bsf		PCLATH,3	; page 1
	bsf		DELAY_FLG,0	; set delay
	goto	DISPLAY_VALUES

UP_FORMAT_DSP
; format bits 2 and 1 (00,01 and 10 valid)
	btfsc	OPTIONS,2	; if set clear (ie 10 to 00)
	goto	CLR_OPTIONS_1_2	
	btfsc	OPTIONS,1	; if set clear bit1 and set bit 2
	goto	CLR_SET_OPTIONS_1_2	
	bsf		OPTIONS,1
	bcf		OPTIONS,2
	goto	OPTIONS_WRITE
CLR_SET_OPTIONS_1_2
	bcf		OPTIONS,1
	bsf		OPTIONS,2
	goto	OPTIONS_WRITE
CLR_OPTIONS_1_2	
	bcf		OPTIONS,2	; bit 2 cleared
	bcf		OPTIONS,1	; bit 1 cleared
	goto	OPTIONS_WRITE

UP_FIXED_DSP
; fixed bits 3 and 4 (00,01 and 10 valid)	
	btfsc	OPTIONS,4	; if set clear (ie 10 to 00)
	goto	CLR_OPTIONS_3_4	
	btfsc	OPTIONS,3	; if set clear bit 3 and set bit 4
	goto	CLR_SET_OPTIONS_3_4	
	bsf		OPTIONS,3
	bcf		OPTIONS,4
	goto	OPTIONS_WRITE
CLR_SET_OPTIONS_3_4
	bcf		OPTIONS,3
	bsf		OPTIONS,4
	goto	OPTIONS_WRITE
CLR_OPTIONS_3_4	
	bcf		OPTIONS,4	; bit 4 cleared
	bcf		OPTIONS,3	; bit 3 cleared
	goto	OPTIONS_WRITE

UP_DOT_BAR_DSP
; bit 0 (0 or 1)
	btfss	OPTIONS,0	; if set clear
	goto	SET_OPTIONS_0
	bcf		OPTIONS,0	; clear
	goto	OPTIONS_WRITE
SET_OPTIONS_0
	bsf		OPTIONS,0	; set
OPTIONS_WRITE
	movlw	EEPROM8		;  setting
	bcf		PCLATH,3	; page 0
	call	EEREAD		; sets EEADR
	movf	OPTIONS,w
	call	EWRITE		; write to EEPROM
	bsf		PCLATH,3	; page 1
	bsf		DELAY_FLG,0	; set delay
	goto	DISPLAY_VALUES	

UP_LIMIT_DSP
; bit 0 (0 or 1)
	btfss	LIMIT_SENSE,0	; if set clear
	goto	SET_LIMIT_0
	bcf		LIMIT_SENSE,0	; clear
	goto	LIMIT_WRITE
SET_LIMIT_0
	bsf		LIMIT_SENSE,0	; set
LIMIT_WRITE
	movlw	EEPROMD		;  setting
	bcf		PCLATH,3	; page 0
	call	EEREAD		; sets EEADR
	movf	LIMIT_SENSE,w
	call	EWRITE		; write to EEPROM
	bsf		PCLATH,3	; page 1
	bsf		DELAY_FLG,0	; set delay
	goto	DISPLAY_VALUES	

UP_LIMIT_TM
	movf	LIMIT_ON,w	; limit period 0 to 255 (ms x 2) eg 100=200ms
	sublw	D'254'
	btfss	STATUS,C	; if 255
	goto	DISPLAY_VALUES	; no change if at 255
	incf	LIMIT_ON,f
UP_DATE_LIMIT_TM		; write to EEPROM
	movlw	EEPROME		; time setting
	bcf		PCLATH,3	; page 0
	call	EEREAD		; sets EEADR
	movf	LIMIT_ON,w
	call	EWRITE		; write to EEPROM
	bsf		PCLATH,3	; page 1
	bsf		DELAY_FLG,0	; set delay
	goto	DISPLAY_VALUES

; down switch
DOWN_SW
	btfsc	SETTINGS,2	; if clear then label display
	goto	DN_SETTINGS
	movf	LABEL,w
	btfsc	STATUS,Z	; if zero set at 13
	goto	SET_LABEL
	decf	LABEL,f
	bsf		DELAY_FLG,0	; set flag to add delay
	goto	DISPLAY_VALUES
SET_LABEL
	movlw	D'12'
	movwf	LABEL
	bsf		DELAY_FLG,0	; set flag to add delay
	goto	DISPLAY_VALUES
DN_SETTINGS
	incf	LABEL,w		; get current label setting
	xorlw	H'01'		; cylinder number
	btfsc	STATUS,Z 
	goto	DN_CYLINDER
	incf	LABEL,w		; get current label setting
	xorlw	H'02'		; red LEDs number
	btfsc	STATUS,Z 
	goto	DN_RED_LED
	incf	LABEL,w		; get current label setting
	xorlw	H'03'		; red line rpm
	btfsc	STATUS,Z 
	goto	DN_RED_LINE
	incf	LABEL,w		; get current label setting
	xorlw	H'05'		; shift light rpm
	btfsc	STATUS,Z 
	goto	DN_SHIFT_LITE
	incf	LABEL,w		; get current label setting
	xorlw	H'06'		; limit rpm
	btfsc	STATUS,Z 
	goto	DN_LIMIT_SET
	incf	LABEL,w		; get current label setting
	xorlw	H'07'		; Hysteresis rpm
	btfsc	STATUS,Z 
	goto	DN_HYSTER_DSP
	incf	LABEL,w		; get current label setting
	xorlw	H'08'		; Update period
	btfsc	STATUS,Z 
	goto	DN_UPDATE_DSP
	incf	LABEL,w		; get current label setting
	xorlw	H'09'		; display format
	btfsc	STATUS,Z 
	goto	DN_FORMAT_DSP
	incf	LABEL,w		; get current label setting
	xorlw	D'10'		; fixed digits
	btfsc	STATUS,Z 
	goto	DN_FIXED_DSP
	incf	LABEL,w		; get current label setting
	xorlw	D'11'		; dot/bar
	btfsc	STATUS,Z 
	goto	DN_DOT_BAR_DSP
	incf	LABEL,w		; get current label setting
	xorlw	D'12'		; limit sense
	btfsc	STATUS,Z 
	goto	DN_LIMIT_DSP
	incf	LABEL,w		; get current label setting
	xorlw	D'13'		; limit time
	btfsc	STATUS,Z 
	goto	DN_LIMIT_TM
	goto	DISPLAY_VALUES

DN_CYLINDER
	movf	CYL_SET,w	; cylinder setting (1-12)
	xorlw	D'01'		; if 1 keep value
	btfsc	STATUS,Z	; if 1
	goto	DISPLAY_VALUES	; no change if at 1
	decf	CYL_SET,f
	goto	CYLINDER_WRITE	; write to EEPROM

DN_RED_LED
	movf	RED_LEDS,w	; RED_LEDS (0-10)
	xorlw	D'00'		; if 0 keep value
	btfsc	STATUS,Z	; if 0
	goto	DISPLAY_VALUES	; no change if at 0
	decf	RED_LEDS,f
	goto	RED_LED_WRITE	; write to EEPROM

DN_RED_LINE
; subtract 100rpm using AARGB0,1 - BARGB0,1 = AARGB0,1	
	clrf	BARGB0		; ms bytes cleared
	movlw	D'100'		; 
	movwf	BARGB1		; ls byte
	movf	RED_LINE1,w	; ms byte
	movwf	AARGB0
	movf	RED_LINE2,w	; ls byte
	movwf	AARGB1
	bcf		PCLATH,3	; page 0
	call	D_SUB		; subtract 100 rpm
	bsf		PCLATH,3	; page 1
; check for 0 not decreased past 0
	btfsc	AARGB0,7	; if set then <0 so leave values as is
	goto	DISPLAY_VALUES	
	movf	AARGB0,w	; result
	movwf	RED_LINE1
	movf	AARGB1,w
	movwf	RED_LINE2
; write to EEPROM
	goto	UP_RED_LINE_WRITE

DN_SHIFT_LITE
; subtract 100rpm using AARGB0,1 - BARGB0,1 = AARGB0,1	
	clrf	BARGB0		; ms bytes cleared
	movlw	D'100'		; 
	movwf	BARGB1		; ls byte
	movf	SHIFT1,w	; ms byte
	movwf	AARGB0
	movf	SHIFT2,w	; ls byte
	movwf	AARGB1
	bcf		PCLATH,3	; page 0
	call	D_SUB		; subtract 100 rpm
	bsf		PCLATH,3	; page 1
; check for 0 not decreased past 0
	btfsc	AARGB0,7	; if set then <0 so leave values as is
	goto	DISPLAY_VALUES	
	movf	AARGB0,w	; result
	movwf	SHIFT1
	movf	AARGB1,w
	movwf	SHIFT2
; write to EEPROM
	goto	UP_SHIFT_LITE_WRITE

DN_LIMIT_SET
; subtract 100rpm using AARGB0,1 - BARGB0,1 = AARGB0,1	
	clrf	BARGB0		; ms bytes cleared
	movlw	D'100'		; 
	movwf	BARGB1		; ls byte
	movf	LIMIT1,w	; ms byte
	movwf	AARGB0
	movf	LIMIT2,w	; ls byte
	movwf	AARGB1
	bcf		PCLATH,3	; page 0
	call	D_SUB		; subtract 100 rpm
	bsf		PCLATH,3	; page 1
; check for 0 not decreased past 0
	btfsc	AARGB0,7	; if set then <0 so leave values as is
	goto	DISPLAY_VALUES	
	movf	AARGB0,w	; result
	movwf	LIMIT1
	movf	AARGB1,w
	movwf	LIMIT2
; write to EEPROM
	goto	UP_LIMIT_SET_WRITE

DN_HYSTER_DSP
	movf	HYSTERESIS,w; hysteresis setting 
	xorlw	D'00'		; if 0 keep value
	btfsc	STATUS,Z	; if 0
	goto	DISPLAY_VALUES	; no change if at 1
	decf	HYSTERESIS,f
	goto	HYSTERESIS_WRITE; write to EEPROM

DN_UPDATE_DSP
	movf	UPDATE_CT,w	; Updated period
	xorlw	D'00'		; if 0 keep value
	btfsc	STATUS,Z	; if 0
	goto	DISPLAY_VALUES	; no change if at 1
	decf	UPDATE_CT,f
	goto	UP_DATE_WRITE	; write to EEPROM

DN_FORMAT_DSP
; format bits 2 and 1 (00,01 and 10 valid)
	btfsc	OPTIONS,2	; if set clear bit 2 set bit 1
	goto	DN_CLR_OPTIONS_1_2	
	btfsc	OPTIONS,1	; if set clear bit1 and bit 2
	goto	DN_CLR_SET_OPTIONS_1_2	
	bcf		OPTIONS,1
	bsf		OPTIONS,2
	goto	OPTIONS_WRITE
DN_CLR_SET_OPTIONS_1_2
	bcf		OPTIONS,1
	bcf		OPTIONS,2
	goto	OPTIONS_WRITE
DN_CLR_OPTIONS_1_2	
	bcf		OPTIONS,2	; bit 2 cleared
	bsf		OPTIONS,1	; bit 1 set
	goto	OPTIONS_WRITE

DN_FIXED_DSP
; fixed bits 3 and 4 (00,01 and 10 valid)	
	btfsc	OPTIONS,4	; if set 
	goto	DN_CLR_OPTIONS_3_4	
	btfsc	OPTIONS,3	; if set clear bit 3 and bit 4
	goto	DN_CLR_SET_OPTIONS_3_4	
	bcf		OPTIONS,3
	bsf		OPTIONS,4
	goto	OPTIONS_WRITE
DN_CLR_SET_OPTIONS_3_4
	bcf		OPTIONS,3
	bcf		OPTIONS,4
	goto	OPTIONS_WRITE
DN_CLR_OPTIONS_3_4	
	bcf		OPTIONS,4	; bit 4 cleared
	bsf		OPTIONS,3	; bit 3 set
	goto	OPTIONS_WRITE

DN_LIMIT_DSP
	goto	DN_LIMIT_DSP

DN_DOT_BAR_DSP
	goto	UP_DOT_BAR_DSP	; same as up as toggle bit 0 only
	
DN_LIMIT_TM
	movf	LIMIT_ON,w	; Updated period
	xorlw	D'00'		; if 0 keep value
	btfsc	STATUS,Z	; if 0
	goto	DISPLAY_VALUES	; no change if at 1
	decf	LIMIT_ON,f
	goto	UP_DATE_LIMIT_TM; write to EEPROM

	end
