;************************************************************
;--------------Lambda-Anzeige mit LCD-Display---------------
;		    V1.0 beta, 4.4.2001
;
; AVR 90S2313, 8 MHz
; Eingang Lambda-Sonde auf PIN B1
; LCD mit 16 Stellen/1 Zeilen im 4bit Betrieb an PORT D
; RS an PORT D6, RW an PORT D5, Enable an PORT D4
; RC-Glied 100k, 10nF
;
;      (c) 2001 MDvP                   mailto:MDvP@gmx.de
;************************************************************
; .nolist
.include "2313def.inc"
; .list
 ;-LCD Display control bits
.equ	rs	=6		; RS
.equ	rw	=5		; RW
.equ	e	=4		; enable
.equ	bf	=3		; busyflag

.equ	ld	=2		;load capacitor

;-----------------------------------------------------------
.def	temp	=r16		; Scratch register
.def	result	=r17		; Result of A/D
.def	sum	=r18		; sum of A/D
.def	Ad	=r19		; Counter for A/D
.def	c0	=r20		; Counter delay loop
.def	c1	=r21		; counter inner delay loop
.def	c2	=r22		; counter inner delay loop
.def	fbin	=r23		; 8-bit binary value
.def	tBCDL	=r23		; ASCII result   1
.def	tBCDM	=r24		; ASCII result  10
.def	tBCDH	=r25		; ASCII result 100
.def	lcd	=r26		; LCD data output register


.cseg
 .org $0000
	rjmp RESET		; Reset handle
 .org OVF0addr
	rjmp ANA_COMP		; Timer0 overflow
 .org ACIaddr
	rjmp ANA_COMP  		; Analog comparator

 .org $000b
;---------------------------------------
.macro	delay				; 0,125 ms delay
	ldi 	c0,@0
d1:	ldi 	c1,249
d2:	nop
	dec 	c1
	brne 	d2
	dec 	c0
	brne 	d1
.endmacro
;------------------------------------
.macro lcd_pos
		ldi	lcd,@0
		ori	lcd,$80
		rcall	lcd_cmd
.endmacro
.macro lcd_chr
		ldi	lcd,@0
		rcall	lcd_wrt
.endmacro
;---------------------------------------
ANA_COMP:       in      result,TCNT0    ; Load timer value
		dec	result		; -1
	        clr     temp    	; Stop timer0
		out     TCCR0,temp         
		cbi     PORTB,ld	; Start discharge
		set			; Set conversion complete flag
		reti
;---------------------------------------
AD_convert:	clr     temp   		;Clear counter
		out     TCNT0,temp
		clt			; Clear conversion complete flag (t)
		ldi	temp,$02	; Start timer0 with prescaling 8
		out     TCCR0,temp    
		sbi     PORTB,ld	; Start charging of capacitor
		ret
;---------------------------------------
RESET:		ldi 	temp,low(RAMEND)
		out 	SPL,temp	; initiate Stack-pointer
		ldi	temp,0b11111100 ; PortB 0,1 Input (comparator)
		out	DDRB,temp
		ser	temp		; PortD output (LCD-Data)
		out	DDRD,temp
		clr 	temp
		out	PORTB,temp	; off
		out	PORTD,temp	; off
		out	WDTCR,temp	; disable Watchdog
		ldi     temp,$0B   	; Initiate comparator
		out     ACSR,temp 	; and enable comparator interrupt
		ldi     temp,$02      	; Enable timer interrupt
		out     TIMSK,temp
		rcall	lcd_init	; initialize LCD-diplay
		sei			; Enable global interrupt
Main:		clr	zl
		clr	zh
		clr	Ad		; integrate 256 times
L0:		delay	16		; 2 ms delay
		rcall	AD_convert	; Start conversion
Wait:		brtc	Wait		; Wait until conversion is complete
		add	zh,result	; Sum of result
		adc	zl,temp
		dec	Ad
		tst	Ad
		brne	L0
		clr	zh
		lsl	zl		; *2
		rol	zh
		subi	zl,low(-2*daten); data address
		sbci	zh,high(-2*daten)
		lpm			; load Lambda
		mov	fbin,r0
		rcall	b2ASCII		; convert to ASCII
		rcall	lcd_1
		mov	lcd,tBCDH	; 1. Digit
		rcall	lcd_wrt
		lcd_chr	','
		mov	lcd,tBCDM	; 2. Digit
		rcall	lcd_wrt
		mov	lcd,tBCDL	; 3. Digit
		rcall	lcd_wrt
		lcd_chr	$20
		lcd_chr	$00
		lcd_chr	$20
		lcd_chr	$20
		adiw	zl,1
		lpm			; load Voltage
		mov	fbin,r0
		rcall	b2ASCII		; convert to ASCII
		rcall	lcd_2		; 2. line
		lcd_chr	$20
		lcd_chr	$20
		mov	lcd,tBCDH	; 1. Digit
		rcall	lcd_wrt
		lcd_chr	','
		mov	lcd,tBCDM	; 2. Digit
		rcall	lcd_wrt
		mov	lcd,tBCDL	; 3. Digit
		rcall	lcd_wrt
		lcd_chr	$20
		lcd_chr	'V'
		rjmp	Main		;Repeat conversion
;------------------------------------------
b2ASCII:	clr	tBCDH			;clear result 100
		clr	tBCDM			;clear result  10
b_1:		subi	fbin,10			;input = input - 10
		brmi	b_2			;abort if minus
		inc	tBCDM			;inc 10
		rjmp	b_1			;loop again
b_2:		subi	fbin,-10		;compensate extra subtraction
b_3:		subi	tBCDM,10		;input = input - 10
		brmi	b_4			;abort if minus
		inc	tBCDH			;inc 100
		rjmp	b_3			;loop again
b_4:		subi	tBCDM,-58		;compensate extra subtraction
		subi	tBCDL,-48		;to ASCII
		subi	tBCDH,-48		;to ASCII
		ret
;---------LCD-Routines-------------------------------------
.macro pause				; 0,5 盜
		ldi	c0,@0
pau1:		nop
		dec	c0
		brne	pau1
.endmacro
.macro lcd_set				; pulse LCD-enable line
		nop
		nop
		sbi	PORTD,e
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		cbi	PORTD,e
.endmacro
;---------------------------------
lcd_init:	ldi	lcd,0b0011	; 8bit
		out	PORTD,lcd
		delay	160		; 20 ms delay
		lcd_set			; Function set
		delay	50		; 6 ms
		lcd_set			; Function set
		delay	2		; 250 盜
		lcd_set			; Function set
		delay	2		; 250 盜
		ldi	lcd,0b0010	; 4bit
		out	PORTD,lcd
		lcd_set			; Function set
		delay	1
		ldi	lcd,0b00101000	; 4 bit, 2 row
		rcall	lcd_cmd
		ldi	lcd,0b00001100	; Display on, Cursor off, Blink off
		rcall	lcd_cmd
		ldi	lcd,0b00000001	; clear display
		rcall	lcd_cmd
		ldi	lcd,0b00000110	; entry mode
		rcall	lcd_cmd
		ldi	lcd,0b00000010	; home
		rcall	lcd_cmd
		rcall	lcd_copy
		rcall	lcd_lambda
		ldi	lcd,0b00000010	; home
		rcall	lcd_cmd
		ldi	temp,250
li1:		delay	160
		dec	temp		;= 5 s
		brne	li1
		ret
;------------------------------------
lcd_home:	ldi	lcd,0b00000010		; cursor home
		rcall	lcd_cmd
		ret
;------------------------------------
lcd_clear:	ldi	lcd,0b00000001		; clear display
		rcall	lcd_cmd
		ret
;------------------------------------
lcd_1:		ldi	lcd,0b10000000		; set dd-ram 1.Zeile
		rcall	lcd_cmd
		ret
lcd_2:		ldi	lcd,0b11000000		; set dd-ram 2.Zeile
		rcall	lcd_cmd
		ret
;------------------------------------
lcd_wrt:	clr	temp
		out	PORTD,temp
		sbi	PORTD,rs
		sbrc	lcd,4		; upper nibble first
		sbi	PORTD,0
		sbrc	lcd,5
		sbi	PORTD,1
		sbrc	lcd,6
		sbi	PORTD,2
		sbrc	lcd,7
		sbi	PORTD,3
		lcd_set
		out	PORTD,temp	; clr Port
		sbi	PORTD,rs
		sbrc	lcd,0		; lower nibble
		sbi	PORTD,0
		sbrc	lcd,1
		sbi	PORTD,1
		sbrc	lcd,2
		sbi	PORTD,2
		sbrc	lcd,3
		sbi	PORTD,3
		lcd_set
		delay	10
		ret
;--------------------------------------
lcd_cmd:	clr	temp
		out	PORTD,temp
		sbrc	lcd,4
		sbi	PORTD,0
		sbrc	lcd,5
		sbi	PORTD,1
		sbrc	lcd,6
		sbi	PORTD,2
		sbrc	lcd,7
		sbi	PORTD,3
		lcd_set
		out	PORTD,temp
		sbrc	lcd,0
		sbi	PORTD,0
		sbrc	lcd,1
		sbi	PORTD,1
		sbrc	lcd,2
		sbi	PORTD,2
		sbrc	lcd,3
		sbi	PORTD,3
		lcd_set
		delay	20
		ret
;--------------------------------------
lcd_copy:	rcall	lcd_1
		lcd_chr	'L'
		lcd_chr	'a'
		lcd_chr	'm'
		lcd_chr	'b'
		lcd_chr	'd'
		lcd_chr	'a'
		lcd_chr	' '
		lcd_chr	'('
		rcall	lcd_2
		lcd_chr	'c'
		lcd_chr	')'
		lcd_chr	' '
		lcd_chr	'M'
		lcd_chr	'D'
		lcd_chr	'v'
		lcd_chr	'P'
		ret
;----------------------------------------------
.macro lcd_CG
		ldi	lcd,@0
		rcall	lcd_cmd
		ldi	lcd,@1
		rcall	lcd_wrt
.endmacro
lcd_lambda:	
		lcd_CG	$40,$00
		lcd_CG	$41,$08
		lcd_CG	$42,$04
		lcd_CG	$43,$04
		lcd_CG	$44,$0A
		lcd_CG	$45,$0A
		lcd_CG	$46,$11
		lcd_CG	$47,$00
		ret
;------------------------------------------
daten:
.include "L_U.dat"