;***************************************************************************
;                                                                     
;	BINARY to DECIMAL CONVERSION for LCD-Display for PIC 16XXX V1.02
;	================================================================
;
;	written by Peter Luethi, 21.01.1999, Dietikon, Switzerland
;	http://www.electronic-engineering.ch
;	last update: 20.08.2004
;
;	V1.02:	Changed labels such as to be able to use both, m_lcdv08.asm
;		and m_lcdv16.asm simultaneously (24.06.2004)
;	V1.01:	Replaced register with #define statement for flag
;		(16.02.2003)
;	V1.00:	Initial release (21.01.1999)
;
;	This code and accompanying files may be distributed freely and
;	modified, provided this header with my name and this notice remain
;	intact. Ownership rights remain with me.
;	You may not sell this software without my approval.
;
;	This software comes with no guarantee or warranty except for my
;	good intentions. By using this code you agree to indemnify me from
;	any liability that might arise from its use.
;
;	
;	SPECIFICATIONS:
;	===============
;	Processor:		Microchip PIC 16XXX
;	Decimal Range:		0 - 65'535 unsigned
;	Binary Range:		16 Bit	   unsigned
; 
;
;	DESCRIPTION:
;	============
;	Developed and tested on PIC 16C84, but executeable on all PICs.
;	Evaluates from 16 bit Binary Data in HI,LO the equivalent
;	decimal output for the LCD-Display. Preceeding zeros are
;	not displayed.
;
;	Call of implemented procedure with:
;		"LCDval_16", value in HI & LO
;
;	LO & HI are NOT altered or cleared during operation and are
;	still valid after termination of this routine.
;	During the whole routine, LO_TEMP, HI_TEMP & BCflag must NOT
;	be used by other routines !			    ========
;	TEMP1 - TEMP3 can be used by the LCD routine during conversion
;	(call of LCDw), because they will be re-defined again.
;
;
;	DECLARATIONS needed in MAIN PROGRAM :
;	=====================================
;	CONSTANT BASE = 0x0C	; Base address of user file registers
;	LO	equ	BASE+?
;	HI	equ	BASE+?
;	LO_TEMP	set	BASE+?
;	HI_TEMP	set	BASE+?
;	#define	BCflag	<reg_name>,0x00	; blank checker for preceeding zeros
;			; <reg_name> can be any register, containing also
;			; other flags
;
;
;	REQUIRED MEMORY:
;	================
;	3 registers: @ BASE+0 - BASE+2 (temporary registers)
;       4 registers: LO, LO_TEMP, HI, HI_TEMP
;	1 flag: BCflag
;	needs itself 2 stack levels, but LCDw needs some more
;
;***************************************************************************

;***** INCLUDE FILES *****

	IFNDEF	M_LCD_ID
	  ERROR "Missing include file: m_lcd.asm or similar"
	ENDIF
	
;***** REGISTER DECLARATION *****

	IFNDEF	BASE
	  ERROR "ModuleError: Declare BASE (Base address of user file registers) in MAIN PROGRAM"
	ENDIF
	IFNDEF	LO
	  ERROR "ModuleError: Declare LO in MAIN PROGRAM"
	ENDIF
	IFNDEF	HI
	  ERROR "ModuleError: Declare HI in MAIN PROGRAM"
	ENDIF
	IFNDEF	LO_TEMP
	  ERROR "ModuleError: Declare LO_TEMP in MAIN PROGRAM"
	ENDIF
	IFNDEF	HI_TEMP
	  ERROR "ModuleError: Declare HI_TEMP in MAIN PROGRAM"
	ENDIF
	IFNDEF	BCflag
	  ERROR "ModuleError: #define BCflag FLAGreg,0x05 (Blank checker) in MAIN PROGRAM"
	ENDIF

   ; *** Universal Temporary Register ***
	TEMP1	set	BASE+d'0'	; counter
	TEMP2	set	BASE+d'1'	; Sub-LO
	TEMP3	set	BASE+d'2'	; Sub-HI

;***** MACROS *****
	
LCDval_16 macro
	call	LCDval16
	endm
	
;***** SUB-ROUTINES *****

LCDval16
	movfw	LO		; LO -> LO_TEMP
	movwf	LO_TEMP		
	movfw	HI		; HI -> HI_TEMP
	movwf	HI_TEMP
	bcf	BCflag		; Blank checker for preceeding zeros
	
	movlw	b'00010000'	; check amount of 10000s
	movwf	TEMP2		; Sub-LO
	movlw	b'00100111'
	movwf	TEMP3		; Sub-HI	
	call	_VALcnv16	; call conversion sub-routine
	LCDw			; call LCD sub-routine with value stored in w
	
	movlw	b'11101000'	; check amount of 1000s
	movwf	TEMP2		; Sub-LO
	movlw	b'00000011'
	movwf	TEMP3		; Sub-HI	
	call	_VALcnv16	; call conversion sub-routine
	LCDw			; call LCD sub-routine with value stored in w

	movlw	b'01100100'	; check amount of 100s
	movwf	TEMP2		; Sub-LO
	clrf	TEMP3		; Sub-HI is zero
	call	_VALcnv16	; call conversion sub-routine
	LCDw			; call LCD sub-routine with value stored in w

	movlw	b'00001010'	; check amount of 10s
	movwf	TEMP2		; Sub-LO
	clrf	TEMP3		; Sub-HI is zero
	call	_VALcnv16	; call conversion sub-routine
	LCDw			; call LCD sub-routine with value stored in w

	movlw	b'00000001'	; check amount of 1s
	movwf	TEMP2		; Sub-LO
	clrf	TEMP3		; Sub-HI is zero	
	bsf	BCflag		; remove blank checker in case of zero
	call	_VALcnv16	; call conversion sub-routine
	LCDw			; call LCD sub-routine with value stored in w
	RETURN
	
_VALcnv16
	clrf	TEMP1		; clear counter
_V16_1	movfw	TEMP3
	subwf	HI_TEMP,w	; TEST: HI_TEMP-TEMP3 >= 0 ?
	skpc			; skip, if true
	goto	_V16_LCD	; result negativ, exit
	bnz	_V16_2		; test zero, jump if result > 0
	movfw	TEMP2		; Precondition: HI-TEST is zero
	subwf	LO_TEMP,w	; TEST: LO_TEMP-TEMP2 >= 0 ?
	skpc			; skip, if true
	goto	_V16_LCD	; result negativ, exit
_V16_2	
	movfw	TEMP3
	subwf	HI_TEMP,f	; STORE: HI_TEMP = HI_TEMP - TEMP3
	movfw	TEMP2
	subwf	LO_TEMP,f	; STORE: LO_TEMP = LO_TEMP - TEMP2
	skpc			; skip, if true
	decf	HI_TEMP,f	; decrement HI
	incf	TEMP1,f		; increment counter
	bsf	BCflag		; invalidate flag
	goto	_V16_1
_V16_LCD
	movlw	'0'		; writes number to LCD
	addwf	TEMP1,w		; '0' is ascii offset, add counter
	btfss	BCflag		; check flag
	movlw	' '		; clear preceeding zeros
	; return with data in w
	RETURN

