; -----------------------------------
; Belichter.asm
;
; Controller for a PCB exposure unit
;
; Controls the exposure time of an PCB exposure unit which is equipped with UV-LEDs.
; Time is set with a ratary encoder, whose pushbutton is used to start or cancel the countdown.
; The last set time is saved within the controller internal EEPROM.
; Display is an 1x16 alphanumeric LCD.
; Security feature through a lid sitch - avoids unwanted exposure to eyes.
;
; (c) Stephan Asmus 12/2019
; info@sasmus.de
;
; the software or parts of it may be used for private, non-commercial use
; the original author has to be named in such a case, however
;
; Das Programm oder Teile davon dürfen für private, nicht-kommerzielle
; Anwendungen weiterverwendet werden.
; Der ursprüngliche Autor ist dabei zu erwaehnen
; -----------------------------------
; PIC 16F690
; -----------------------------------
; Log:
; 30.11.2019 Start
; 08.12.2019 running, 1st release
;
;
; Used Controller: PIC 16F690
; Pins & Ports:
;
;   Port A:
;   2: Display Enable
;   4: Display RS
;   Port B:
;   4: encoder phase A
;   5: encoder phase B
;   6: encoder pushbutton
;   7: Lid switch
;   Port C:
;   0: Display Data 0
;   1: Display Data 1
;   2: Display Data 2
;   3: Display Data 3
;   4: LED
;   5: Driver output
;
; see schematic for more Details
;
; Fosc=4MHz internal

	LIST   P=PIC16F690

	#include <p16f690.inc>

    errorlevel  -302		;No bank select warnings
    errorlevel  -306		;No page select warnings

	__config (_INTOSCIO & _WDT_OFF & _PWRTE_OFF & _MCLRE_OFF & _CP_OFF & _BOD_OFF & _IESO_OFF & _FCMEN_OFF)
;----------------------------------------------------------------
;variables
	cblock 0x20
	w_tmp		; used for context saving Register "W"
	status_tmp	; used for context saving Register "Status"
	pclath_tmp	; used for context saving Register "PCLATH"
	pclath_save	; used to save pclath within computed gotos

	d1				;Delay-Variable 1
	d2				;Delay-Variable 2
	
	look_hi
	look_lo			;used for string adressing
	
	tmp				;general temp variables
	tmp1
	
	asciiO			;holds Ascii Values from conversion
	asciiT
	asciiH

	auxint			;variables for rotation encoder
	encod
	
    tickcounter		;counter für ISR loop

    keydata			;holds pressed key
	
	Dispdata			;holds Data to display
	
	min				;set timer
	sec
	min_curr			;current timer
	sec_curr

    flags           ;holds diverse flags (see definitions)

	eprom_adr		;eeprom Adress tmp
	eprom_dat		;eeprom data tmp

	endc
;----------------------------------------------------------------
;constants & definitions
#define keyA		PORTB,4	;Encoder A
#define keyB		PORTB,5	;Encoder B
#define keyPush	PORTB,6	;Encoder pushbutton
#define keyLid	PORTB,7	;Lid Key
#define DispE		PORTA,2
#define DispRS	PORTA,4
#define DISPPort	PORTC
#define LED		PORTC,4
#define Driver	PORTC,5
#define running	flags,0 ;countdown is runnung
#define newtime	flags,1	;new time... 1 sec over
#define over		flags,2	;countdown over
#define cancel	flags,3	;set if countdown was cancelled
#define start		flags,4	;set at start of countdown
#define enc_run	flags,5	;set on ist pulse of encoder, cleared at 2nd ....
#define newconf	flags,6	;set if time was changed to indicate that the display has to be updated
#define saveconf	flags,7	;set if config was changed and has to be saved at next start
;----------------------------------------------------------------
;macro definitions
;----------------------------------------------------------------
;set to Register Bank 0
SET_BANK0 MACRO
	bcf STATUS, RP0
	bcf STATUS, RP1
	ENDM
;set to Register Bank 1
SET_BANK1 MACRO
	bsf	STATUS, RP0
	bcf	STATUS, RP1
	ENDM
;set to Register Bank 2
SET_BANK2 MACRO
	bcf	STATUS, RP0
	bsf	STATUS, RP1
	ENDM
;strout Macro to output string on display
strout	macro	stringaddr		
		movlw	high stringaddr	;save high byte 
		movwf	look_hi			
		movlw	low stringaddr	;save low byte
		movwf	look_lo
		call		Disp_string		;output it
		endm
; **********************************************************************
;Program Start
; **********************************************************************
	org 0
	goto    INIT
	
	ORG		0x004           ; interrupt vector location
	movwf	w_tmp          ; save off current W register contents
	swapf	STATUS,W        ; move status register into W register
	clrf		STATUS          ; select Bank 0
	movwf	status_tmp     ; save off contents of STATUS register
	movf		PCLATH,w
	movwf	pclath_tmp
	clrf		PCLATH

	btfsc   INTCON,T0IF     ; If Timer 0 caused the interrupt, handle it.
	call    Timer0_ISR		; 
	btfss	INTCON,RABIE		;if not enabled, dont goto subroutine (cause iIF is set even if Enable is cleared)
	goto		no_RABIE
	btfsc	INTCON,RABIF		;if interrupt on change on Port B happend...
	call		RABI_ISR
no_RABIE
	
	movf		pclath_tmp,w
	movwf	PCLATH
	swapf   status_tmp,w     ; retrieve copy of STATUS register
	movwf   STATUS            ; restore pre-isr STATUS register contents
	swapf   w_tmp,f
	swapf   w_tmp,w          ; restore pre-isr W register contents
	retfie                    ; return from interrupt

; *********************************************
; Port Change Interrupt handler.
; Port B has changed
; *********************************************
RABI_ISR						
	call		Delay100us
	call		keycheck			;clear mismatch condition and get key
	;call		Delay100ms		;debounce
	movf		keydata,w		;fetch status of keys 
	andlw	b'01000000'		;mask pushbutton
	btfsc	STATUS,Z
	goto		RABI_ISR_2

	btfsc	running			;if already running...
	bsf		cancel			;then indicate cancel
	bsf		start			;set start on 1st and following pushes
	call		keycheck			;and wait until release of key
	andlw	b'01000000'		;mask pushbutton
	btfss	STATUS,Z
	goto		$-3
	call		Delay100ms		;debounce
	goto		RABI_ISR_end

RABI_ISR_2
	btfsc	running			;if already running...
	goto		RABI_ISR_end		;then ignore rotation
	
	movf		keydata,w		;fetch status of keys 
	andlw	b'00110000'		;mask pushbutton
	btfsc	STATUS,Z
	goto		RABI_ISR_end

	; Encoder read
    clrf    auxint     ;  Clears auxiliar input var.
    btfsc   keydata,4       ; Gets bits 'encx' and 'ency' (encoder bits)
    bsf     auxint,0   ; in auxint (bits 0 and 1)
    btfsc   keydata,5
    bsf     auxint,1

    movf    auxint,W   ;  Xor's actual and previous encoder
    xorwf   encod,F    ; states. Results in encod.

	rrf     auxint,F   ;  Save's actual encoder state (and rotates it)
    rlf     encod,F    ; in encod, for the next time.
    rrf     auxint,F
    rlf     encod,F
	; Right now, bits 2 and 3 of encod keep the encoder's rotate direction:
    movlw	0x00			;check if both bits are set, which would be an error
	btfsc	encod,2
	iorlw	b'00000001'
	btfsc	encod,3
	iorlw	b'00000010'
	xorlw	b'00000011'
	btfsc	STATUS,Z
	goto		RABI_ISR_end	;error detected, so end & ignore
	btfss	enc_run		;1st pulse of encoder?
	goto		RABI_1strun	;yes, than only set flag (cause encoder sends 2 pulses per indent
	bcf		enc_run		;was set in 1st run, now clear again (2nd pulse)
	
	bsf		newconf		;config has changed
	movlw	d'5'			;prepare 5sec imcrement
	btfsc	encod,2		;rotation in one direction
	addwf	sec,f		;then add
	btfsc	encod,3		;rotation in the other direction
	subwf	sec,f		;then decrement
	;now adapt min:sec
	movf		sec,w		;check if 60
	xorlw	d'60'
	btfss	STATUS,Z
	goto		RABI_dec1
	clrf		sec				;then rollover to min
	incf		min,f
RABI_dec1
	movf		sec,w		;check if -5
	xorlw	0x00 - d'5'
	btfss	STATUS,Z
	goto		RABI_dec3
	movf		min,w
	btfsc	STATUS,Z		;min already 0?
	goto		RABI_dec2		;yes, then only set sec to zero
	decf		min,f		;else decrement mins by 1
	movlw	d'55'		;and set sec to 1min - 5sec
	movwf	sec
	goto		RABI_dec3
RABI_dec2
	clrf		sec
RABI_dec3
	movf		min,w		;limit to 15min
	xorlw	d'15'
	btfsc	STATUS,Z
	clrf		sec
	goto		RABI_ISR_end
RABI_1strun
	bsf		enc_run
RABI_ISR_end
	movf		PORTB,w			;last chance to clear mismatch condition
	bcf		INTCON,RABIF		;clear interrupt flag
	return
; *********************************************
; Timer 0 Interrupt handler.
; Timer 0 has overflowed
; *********************************************
Timer0_ISR
	btfss	running			;only do something if running is the current status
	goto		tmr0end
	movlw	d'12'			;tmr0 reload value (256*(256-12)*16* 1us = ca. 1sec)
	movwf	TMR0
	
    incf    tickcounter,f     ;increment tickcounter (16 ticks ca. 1sec)
	movf		tickcounter,w
	andlw	0x0f				;16 ticks over ? (1sec)
	btfss	STATUS,Z
	goto		tmr0end			;no, then go on
	bsf		newtime			;else indicate that one sec is over
	decf		sec_curr
	movf		sec_curr,w				;check if min & sec are both 0
	btfss	STATUS,Z
	goto		tmr0_0
	movf		min_curr,w
	btfsc	STATUS,Z
	goto		tmr0_1
tmr0_0
	movlw	0xff
	xorwf	sec_curr,w
	btfss	STATUS,Z			;if secs was 0 before (now 0xff)
	goto		tmr0end
	movf		min_curr,w
	btfsc	STATUS,Z
	goto		tmr0_1
	decf		min_curr
	movlw	d'59'
	movwf	sec_curr
	goto		tmr0end
	
tmr0_1	;time over...
	bcf		running
	bsf		over
	clrf		sec_curr
	
tmr0end
	BCF 	INTCON,T0IF		; Clear Timer0 flag and continue.
    return
;------------------------------------------------------------------
;initializes Processor
;------------------------------------------------------------------
INIT
	SET_BANK1	 		;select Register Page 1
    clrf    TRISA				;Port A all output (RA3 always input)
	movlw	0xf0
    movwf	TRISB			;Port B all input
	clrf    TRISC				;Port C all output
    SET_BANK2
    ;configure analog I/O
	clrf 	ANSEL		;all digital I/O
	clrf		ANSELH
	movlw	0xf0			;weak pull up on Port B
	movwf	WPUB
	movlw	b'01110000'			;interrupt on change Port B, lid sensor excluded (is just polled)
	movwf	IOCB
	SET_BANK0
    ;initialise Timer 0
	;we are in Bank 0...
	clrwdt				;Routine from Datasheet Microchip
	clrf		TMR0
	SET_BANK1
	movlw	b'00000111'	;Pullup enable, internal clock, Prescaler to TMR0, Prescaler 1:256
	movwf   OPTION_REG
	movlw	b'01100001'	;4 MHz		
	movwf	OSCCON
	SET_BANK0
	;----now set reasonable values to variables
    clrf    tickcounter
    clrf    flags
	clrf		encod
    call		load_prefs

	call		Delay100ms
	call		Disp_Init
	strout	msg_welcome
	movlw	0x0a			;wait 1sec
	movwf	tmp
	call		Delay100ms
	decfsz	tmp
	goto		$-2
	
	;---
	SET_BANK0
	clrf 	TMR0
	clrf		INTCON			;initialize Interrupts
	bsf		INTCON,T0IE		;enable Timer0 interrupts
	bsf		INTCON,RABIE		;enable IR on change for Port B
	bsf		INTCON,GIE		;enable global interrupts
							;now timer 0 fires

;#############################################################################
;here to start main routine###################################################
;#############################################################################
main			
	call		Disp_clear
	strout	msg_start			;start-message on Dsiplay
main1	
	movf		min,w
	movwf	min_curr
	movf		sec,w
	movwf	sec_curr	

	call		disp_update		;current timer
	btfsc	start			;wait for 1st start
	goto		start_run
	btfss	newconf
	goto		$-3
	bcf		newconf
	bsf		saveconf
	goto		main1
start_run
	btfsc	keyLid			;clear=switch closed=lid cosed
	call		main_lidopen
	btfsc	saveconf
	call		save_prefs
	bcf		saveconf

	bsf		running
	clrf		tickcounter
	call		Disp_clear
	strout	msg_run			;start-message on Dsiplay
	call		disp_update		;current timer
mainloop	
	btfsc	running
	call		main_running
	btfsc	cancel
	goto		main_cancel
	btfsc	over
	goto		main_over
	goto		mainloop

main_running	;normal countdown
	btfsc	keyLid			;clear=switch closed=lid cosed
	call		main_lidopen
	bsf		LED
	bsf		Driver
	btfss	newtime
	return
	call		disp_update
	bcf		newtime
	return
	
main_cancel	;user cancelled
	bcf		LED
	bcf		Driver
	bcf		running
	bcf		cancel
	bcf		start
	call		Disp_clear
	strout	msg_cancel
	call		wait_for_pushbutton
	goto		main
	
main_over		;one countdown over...
	bcf		LED
	bcf		Driver
	bcf		running
	bcf		over
	bcf		start
	call		Disp_clear
	strout	msg_ready
	call		wait_for_pushbutton
	goto		main					;and start from beginning

main_lidopen	;lid is open
	bcf		running				;stop running
	bcf		LED
	bcf		Driver
	call		Disp_clear
	strout	msg_lidopen
	call		Delay100ms
	btfsc	keyLid
	goto		$-1
	call		Delay100ms
	call		Disp_clear
	strout	msg_run
	call		disp_update
	bsf		running				;start running again
	bsf		LED
	bsf		Driver
	return

;---------------------------------------------------------------
;load Prefs
;loads Preferences from internal eeprom if valid config is saved
;in eeprom. Set to default values otherwise
;---------------------------------------------------------------
load_prefs
	clrf		eprom_adr		;read pos 0 =valid-check
	call		eprom_read
	xorlw	0x55
	skpz					;go on if config is valid
	goto		load_prefs_def	;set to defaults otherwise
	;config is valid, now load them
	call		read_it
	movwf	min
	call		read_it
	movwf	sec
	return

load_prefs_def			;set default to prefs
	movlw	d'1'			
	movwf	min
	movlw	d'0'
	movwf	sec
	return

read_it
	incf	eprom_adr,f		;next
	call	eprom_read
	return
;---------------------------------------------------------------
;save_Prefs
; save Preferences to internal eeprom
;---------------------------------------------------------------
save_prefs
	clrf		eprom_adr		;begin saving at pos 0
	movlw	0x55			;valid config marker
	movwf	eprom_dat
	call		eprom_write

	movf		min,w
	call		save_it
	movf		sec,w
	call		save_it	

	return
save_it
	movwf	eprom_dat
	incf		eprom_adr,f
	call		eprom_write
	return
;---------------------------------------------------------------
;EEPROM handling routines
;---------------------------------------------------------------
;eprom read: Address in eprom_adr, return value in w
;---------------------------------------------------------------
eprom_read
	bcf		PIR2, EEIF		;clear interrupt flag (necessary?)
	movf		eprom_adr,w		;Set adress of read
	banksel	EEADR
	movwf	EEADR

	banksel	EECON1
	bcf		EECON1,EEPGD	;we want to read data mem
	bsf		EECON1,RD		;init read
	banksel	EEDATA
	movf		EEDATA,w
	bcf		STATUS,RP0		;back to bank 0 (our standard)
	bcf		STATUS,RP1
	return
;-------------------------------------------------------------------------
;eprom write Address in eprom_adr, data in eprom_dat returns when finished
;-------------------------------------------------------------------------
eprom_write
	bcf		PIR2, EEIF		;clear interrupt (to be sure)
	movf		eprom_adr,w		;load Adress
	banksel	EEADR
	movwf	EEADR
	banksel	0x00
	movf		eprom_dat,w	;load value
	banksel	EEDATA
	movwf	EEDATA
	banksel	EECON1
	bcf		EECON1,EEPGD	;we want to write data mem
	bsf		EECON1,WREN		;enable write

	bcf		INTCON,GIE		;we don't want interrupts now
	btfsc	INTCON,GIE		;make sure it is really cleared
	goto		$-2
	movlw	0x55			;see datasheet, required sequence
	movwf	EECON2
	movlw	0xaa
	movwf	EECON2
	bsf		EECON1,WR		;set write bit to begin write
	bsf		INTCON,GIE		;re-enable global interrupts

	banksel	0x00			;back to Bank0 (our default)
	btfss	PIR2,EEIF		;wait for flag to be set (polling)
	goto	$-1
	bcf		PIR2,EEIF		;clear it, write complete

	banksel	EECON1
	bcf		EECON1,WREN		;clear write enable
	banksel	0x00

	return
;---------------------------------------------------------------
;key handling
;returns status of keys in w
;0= nothing pressed
;8= key pressed
;---------------------------------------------------------------
;doesn't wait for anything, just checks current status and returns values in keydata (1 in keydata = 0 on port)
keycheck
	movf		PORTB,w
    andlw   0xf0			;mask bit 4..7
    xorlw   0xf0			;inverse
    movwf   keydata
	return

wait_for_pushbutton
	bcf		INTCON,RABIE			;disable interrupt on change

	call		keycheck				;wait for push
	andlw	b'01000000'			;mask pushbutton
	btfsc	STATUS,Z
	goto		$-3					;wait for pushbutton
	call		Delay100ms			;debounce
	call		Delay100ms			;debounce
	call		keycheck				;wait for push release
	andlw	b'01000000'			;mask pushbutton
	btfss	STATUS,Z
	goto		$-3					;wait for pushbutton
	call		Delay100ms			;debounce
	call		Delay100ms			;debounce
	call		keycheck				;clear mismatch condition

	bcf		INTCON,RABIF			;clear interrupt flag
	bsf		INTCON,RABIE			;enable interrupt on change
	return
;---------------------------------------------------------------	
;String Routines for using the LCD Display
;---------------------------------------------------------------
;------------------------------------------------------------------------
; disp_update (updates only time xx:xx)
;------------------------------------------------------------------------
disp_update
	movf		min_curr,w
	call		bin2asc
	movlw	0x80				;set cursor to position 0 (start of mins)
	call		Disp_send_conf
	movlw	0x04				;only for my non standard display, change to 0 if using a standard one
	subwf	asciiT,w
	call		Disp_send_data
	movlw	0x04				;only for my non standard display, change to 0 if using a standard one
	subwf	asciiO,w
	call		Disp_send_data
	movf		sec_curr,w
	call		bin2asc
	movlw	0x83				;set cursor to position 3 (start of secs)
	call		Disp_send_conf
	movlw	0x04				;only for my non standard display, change to 0 if using a standard one
	subwf	asciiT,w
	call		Disp_send_data
	movlw	0x04				;only for my non standard display, change to 0 if using a standard one
	subwf	asciiO,w
	call		Disp_send_data
	
	return
;disp_string
;sends string at look_hi/look_lo to display at current cursor position
;ends at 0x00 (end criteria)
Disp_string
	call 	lookup			;char of string to w
    movwf	tmp             ;save returned char
    movlw	high $          ;make sure we're in the right pgm page (cause strings could be in pgm page 0 now)
    movwf	PCLATH
    movf		tmp,w
	andlw	0xff			;set Z-Flag if zero
	skpnz					;if zero (last char)
	return					;end routine
	call		Disp_send_data
	goto		Disp_string

;lookup
;jump to address in look_hi/look_lo which is a RETLW
;increment pointer afterwards
lookup
	movf		look_hi,w		;set PCLATH
	movwf	PCLATH
	movf		look_lo,w		;and get PCL
	incf		look_lo,f		;next position
	skpnz
	incf		look_hi,f		;also if overflow
	movwf	PCL				;now jump
;---------------------------------------------------------------	
;Display Routines for using the LCD Display
;---------------------------------------------------------------
;clear display and return cursor home
Disp_clear
	movlw	b'00000001'		;Clear Display
	call 	Disp_send_conf
	call		Delay10ms
	return
;Initialize Display	
Disp_Init
	call 	Delay100ms		;Wait for Display to be ready (first Start)
	bcf		DispRS
	nop
	movlw	b'00000011'		;Init to 8-Bit Mode
	movwf	DISPPort
	nop
	bsf		DispE	;pulse Enable
	nop
	bcf		DispE	
	call		Delay10ms
	;once more...
	movlw	b'00000011'		;Init to 8-Bit Mode
	movwf	DISPPort
	nop
	bsf		DispE	;pulse Enable
	nop
	bcf		DispE	
	call 	Delay10ms
	;once more...
	movlw	b'00000011'		;Init to 8-Bit Mode
	movwf	DISPPort
	nop
	bsf		DispE	;pulse Enable
	nop
	bcf		DispE	
	call 	Delay10ms
	;once more...
	movlw	b'00000010'		;Init to 4-Bit Mode 
	movwf	DISPPort
	nop
	bsf		DispE	;pulse Enable
	nop
	bcf		DispE	
	call 	Delay10ms
	
	movlw	b'00101000'		;Display Init one row (now in 4-Bit Mode)
	call 	Disp_send_conf
	call		Delay10ms
	movlw	b'00001100'		;Display on, Cursor off, No Blinking
	call 	Disp_send_conf
	call 	Delay10ms
	movlw	b'00000001'		;Clear Display
	call 	Disp_send_conf
	call		Delay10ms
	movlw	b'00000110'		;cursor auto-increment
	call		Disp_send_conf
	call		Delay10ms

	return
;----------------------------------	
;Send Config-Data to Display (RS=0)
Disp_send_conf
	bcf		INTCON,GIE		;we don't want interrupts now
	btfsc	INTCON,GIE		;make sure it is really cleared
	goto	$-2

	bcf		DispRS			;clear RS
	movwf	Dispdata			;save w
	movlw	0xf0				;this is because we need to retain status of upper nubble
	andwf	DISPPort,f		;mask upper nibble, set lower nibble to 0
	swapf	Dispdata,w		;first we send upper nibble
	andlw	0x0f			;mask it
	iorwf	DISPPort,f		;output it
	nop
	bsf		DispE	;pulse Enable
	nop
	bcf		DispE
	movlw	0xf0
	andwf	DISPPort,f		;mask upper nibble, set lower nibble to 0
	movf		Dispdata,w		;and once again with lower nibble
	andlw	0x0f
	iorwf	DISPPort,f
	nop
	bsf		DispE
	nop
	bcf		DispE
	call 	Delay100us
	bsf		INTCON,GIE
	return
;--------------------------
;Send Data to Display (RS=1)
Disp_send_data
	bcf		INTCON,GIE		;we don't want interrupts now
	btfsc	INTCON,GIE		;make sure it is really cleared
	goto	$-2

	bsf		DispRS		;RS=high for Data write
	movwf	Dispdata		;save w
	movlw	0xf0			;this is because we need to retain status of upper nibble 
	andwf	DISPPort,f		;mask upper nibble, set lower nibble to 0
	swapf	Dispdata,w		;first we send upper nibble
	andlw	0x0f			;mask it
	iorwf	DISPPort,f		;output it
	nop
	bsf		DispE	;pulse Enable
	nop
	bcf		DispE
	movlw	0xf0			;this is because we need to retain status of upper nibble
	andwf	DISPPort,f		;mask upper nibble, set lower nibble to 0
	movf		Dispdata,w		;and once again with lower nibble
	andlw	0x0f
	iorwf	DISPPort,f
	nop
	bsf		DispE
	nop
	bcf		DispE
	call 	Delay100us
	bsf		INTCON,GIE
	return	
;--------------------------------------------------------------------
;Conversion routines
;--------------------------------------------------------------------
;---------------------------------------------------------------
;bin2asc
;converts 8-bit value in w to 3-digit ascii value
;value is in global variables asciiO to asciiH
;---------------------------------------------------------------
bin2asc
	movwf	asciiO		;start with value in asciiO
	movlw	a'0'
	movwf	asciiT
	movwf	asciiH
do100s
	movlw	d'100'
	subwf	asciiO,w
	bnc		do10s
	movwf	asciiO
	incf	asciiH,f
	goto	do100s
do10s
	movlw	d'10'
	subwf	asciiO,w
	bnc		adjust
	movwf	asciiO
	incf	asciiT,f
	goto	do10s
adjust
	movlw	a'0'
	addwf	asciiO,f
	return
;--------------------------------------------------------------------
;Delay-Subroutines (for fosc=4 MHz!!!)
;--------------------------------------------------------------------
Delay100us					;Delays ca. 100us
	movlw	0x1F
	movwf	d1
Delay100us_1
	decfsz	d1, f
	goto	Delay100us_1
	goto	$+1
	return
;-----
Delay10ms					;Delays ca.10ms
	movlw	0xCE
	movwf	d1
	movlw	0x08
	movwf	d2
Delay10ms_1
	decfsz	d1, f
	goto	$+2
	decfsz	d2, f
	goto	Delay10ms_1
	goto	$+1
	nop
	return
;-----
Delay100ms					;Delays ca.100ms
	movlw	0x1E
	movwf	d1
	movlw	0x4F
	movwf	d2
Delay100ms_1
	decfsz	d1, f
	goto	$+2
	decfsz	d2, f
	goto	Delay100ms_1
	goto	$+1
	nop
	return
;########################################################################
	org	0x800	;define next in memory Page 1 (so we have space in Page 0)
;########################################################################
;---------------------------------------------------------
;Definitions for Display
;Table is short enough to ensure that no rollover from 0xff to 0x00 happens
;within this table - otherwise the code above has to be modified

;Notice: the prototype used an LCD with non standard charset - therefore the messages are encoded as below.
;If you are using a standard LCD, uncomment the definitions below the table and clear the upper non-standard version.
;Additionally, you have to change the "movlw	0x04	" to "movlw	0x00" within subroutine "disp_update" (4 positions)
;But: you have to use an 1x16 display, which is organised 1x16 and NOT 2x8 - otherwise there are more changes necessary
;alternative: use a 2x16 display - the 2nd line will not be used.
;
msg_welcome
	dt	0x48,0x3b,0x3a,0x20,0x3a,0x57,0x5c,0x5a,0x55,0x59,0x62,0x57,0x60,0x20,0x20,0x20,0x00	;PCB Belichter
msg_start
	dt	0x2c,0x2c,0x36,0x2c,0x2c,0x20,0x5d,0x5a,0x5e,0x20,0x20,0x4b,0x62,0x53,0x60,0x62,0x00	;xx:xx min  Start
msg_run
	dt	0x2c,0x2c,0x36,0x2c,0x2c,0x20,0x5d,0x5a,0x5e,0x20,0x20,0x4a,0x4d,0x46,0x20,0x20,0x00	;xx:xx min  RUN  
msg_ready
	dt	0x2c,0x2c,0x36,0x2c,0x2c,0x20,0x5d,0x5a,0x5e,0x20,0x20,0x4a,0x57,0x53,0x56,0xfa,0x00	;00:00 min  Ready
msg_cancel
	dt	0xa1,0xa1,0xa1,0x55,0x53,0x5e,0x55,0x57,0x5c,0x5c,0x57,0x56,0xa1,0xa1,0xa1,0x20,0x00	;***cancelled***
msg_lidopen
	dt	0xa1,0xa1,0xa1,0x55,0x5c,0x5f,0x61,0x57,0x20,0x20,0x5c,0x5a,0x56,0xa1,0xa1,0xa1,0x00	;***close  lid***

;definitios if using a standard dsiplay:
;msg_welcome
;	dt	"PCB Belichter   ",0x00
;msg_start
;	dt	"xx:xx min  Start",0x00
;msg_run
;	dt	"xx:xx min  RUN  ",0x00 
;msg_ready
;	dt	"00:00 min  Ready",0x00
;msg_cancel
;	dt	"***cancelled*** ",0x00
;msg_lidopen
;	dt	"***close  lid***",0x00
    end



