;*****************************************************************************
; 	All rights reserved by Dipl.-Ing (FH) Andreas Hoeger
;	Ditzenbrunner Str. 64, 71254 Ditzingen, Germany
;	Telefon: (+497156)490980	Telefax: (+497156)490981
;	E-Mail: ingbuero@andreas-hoeger.de
;*****************************************************************************
;
;       8051- Programm fuer ATMEL Flash- Mikrocontroller AT89S53
;	
;	Teilprogramm, wird durch INCLUDE eingebunden
;
;       Autor: Andreas Hoeger
;       Datum: 24.09.2000
;
;	Aenderungen:
;	24_09_00: Routinen fuer Sonderzeichen eingebunden
;       27_10_00: Sonderzeichen "Pfeil aufwaerts" auf Nummer 1 neu dazu
;	14_11_00: Sonderzeichen "Menuecursor" auf Nummer 2 neu dazu
;	06_03_02: Bugfix fuer LED an P2.7: seither mit Null ueberschrieben
;			
;*****************************************************************************

	IF LCD_2x20_4x20		; nur wenn LCD- Modul
					; 20 Zeichen pro Zeile
					; mit 2 oder 4 Zeilen

        ;*********************************************************************
        ; Unterprogramm Initialisierung LCD-Modul
        ;*********************************************************************

ini_lcd:	
	mov	A,#01H			; LSB setzen, andere loeschen 
	mov	C,ACC.1			; Carry loeschen und damit
	mov	LCD_E,C			; strobe loeschen

	call	zehn_ms			; Wartezeit > 15 ms
	call	zehn_ms			;	

	;****** 1. bis 3. Befehl LCD Init ************************************

	mov	A,#LCD_IX		; Befehl LCD Init 1 bis 3
	call	lcd_out			; Portausgabe mit enable
	call	zehn_ms			; Wartezeit > 4.1 ms	

	mov	A,#LCD_IX		; Befehl LCD Init 1 bis 3
	call	lcd_out			; Portausgabe mit enable
	call	ein_ms			; Wartezeit > 100us
	
	mov	A,#LCD_IX		; Befehl LCD Init 1 bis 3
	call	lcd_out			; Portausgabe mit enable
	call	zehn_ms			; Wartezeit > 4.1 ms	

	;******	4. Befehl LCD Init *******************************************
	
	mov	A,#LCD_I4		
	call	lcd_out			; setze 4-Bit-Mode
	call	us_50			; Wartezeit > 40 us

	;******	5. Befehl LCD Init *******************************************
	
	mov	A,#LCD_I5		
	call	lcd_out			; setze Matrixformat 5*8 oder 5*11
	mov	A,#LCD_I5A		
	call	lcd_out			
	call	us_50			; Wartezeit > 40 us

	;******	6. Befehl LCD Init *******************************************
	
	mov	A,#LCD_I6		
	call	lcd_out			; display off, cursor off, blink off 
	mov	A,#LCD_I6A		
	call	lcd_out			
	call	us_50			; Wartezeit > 40 us

	;******	7. Befehl LCD Init *******************************************
	
	mov	A,#LCD_I7		
	call	lcd_out			; display on, cursor off, no blink
	mov	A,#LCD_I7A		
	call	lcd_out			
	call	us_50			; Wartezeit > 40 us

	;******	8. Befehl LCD Init *******************************************
	
	mov	A,#LCD_I8		
	call	lcd_out			; cursor move right, no shift
	mov	A,#LCD_I8A		
	call	lcd_out			
	call	us_50			; Wartezeit > 40 us

	;******	Programmierung Sonderzeichen *********************************
	
	mov	DPTR, #MSC000		; Sonderzeichen Pfeil abwaerts
	mov	A,#00H			; Sonderzeichen Nummer 0
					; soll es werden
	call	prog_custom		; Routine zur Programmierung des 	
					; Sonderzeichens ins CGRAM

	mov	DPTR, #MSC001		; Sonderzeichen Pfeil aufwaerts
	mov	A,#01H			; Sonderzeichen Nummer 1
					; soll es werden
	call	prog_custom		; Routine zur Programmierung des 	
					; Sonderzeichens ins CGRAM
	
	mov	DPTR, #MSC002		; Sonderzeichen Menuecursor
	mov	A,#02H			; Sonderzeichen Nummer 2
					; soll es werden
	call	prog_custom		; Routine zur Programmierung des 	
					; Sonderzeichens ins CGRAM
	ret

	ENDIF				; ENDIF LCD_2x20_4x20

        ;*********************************************************************
        ; Unterprogramm fuer Byteausgabe an LCD-Port
        ;*********************************************************************
	; direkt verwendbar zu Beginn der Initialisierung (8 Bit Mode)
	; danach Aufruf nur noch durch char_out- bzw. instr_out-Routine, die
	; das Byte zuvor in zwei Byte spaltet und nacheinander sendet
lcd_out:

	rlc	A			; MSB vom Akku beibehalten !!
	mov	C,LED			; !! LED ist Port 2.7 und darf nicht 
	rrc	A			; ausversehen veraendert werden

	mov	P2,A			; Befehl in A auf Port ausgeben
	call	us_50			; Einschwing-Wartezeit
	setb	LCD_E			; strobe setzen
	call	us_50			; Mindestwartezeit 450 ns
	clr	LCD_E			; strobe loeschen

	ret

        ;*********************************************************************
        ; Unterprogramme fuer Textausgabe auf LCD- Anzeige
        ;*********************************************************************
	; Ausgabe einer kompletten Textzeile
	; DPTR muss vorher auf den Text gesetzt werden: mov DPTR,#TEXTx
	; als Endemarkierung wird 16 verwendet
	
print_lcd:
	mov	A,#0			; Akku loeschen
	movc	A,@A+DPTR		; einen Buchstaben holen
	inc	DPTR
	cjne	A,#16,pr_1		; Ende der Textzeile ?
	sjmp	pr_2

pr_1:	
	call	char_out		; An LCD senden
	sjmp	print_lcd
pr_2:
	ret

        ;*********************************************************************
	; Ausgabe eines Daten- zeichens im 4-Bit-Mode:
	; zuerst high nibble, dann low nibble ausgeben
	; Ausgabe erfolgt beidesmal ueber LSBs des Ports !
	; Datenuebergabe hierher im Akku
	; Unterschied zu instr_out: RS=1 bei Daten

char_out:
	push	acc			; Byte sichern
	
	swap	a			
	anl	a,#HIGH_MASK		; obere Bits loeschen
	orl	a,#RS_MASK		; setze RS=1 (high = dataregister)
	call	lcd_out			; High nibble ausgeben (in LSBs!)

	pop	acc			
	anl	a,#HIGH_MASK
	orl	a,#RS_MASK		; setze RS=1 (high = dataregister)
	call	lcd_out			; Low nibble ausgeben (in LSBs!)

	call	us_50			; Wartezeit > 40 us bis
					; naechster Buchstabe weil LCD
					; im Write-Only-Mode ohne Busy Flag
	ret

        ;*********************************************************************
	; Ausgabe eines Befehles im 4-Bit-Mode: 
	; zuerst high nibble, dann low nibble ausgeben
	; Ausgabe erfolgt jedoch ueber LSBs des Ports !
	; Datenuebergabe hierher im Akku

instr_out:
	push	acc			; Byte sichern
	
	swap	a			
	anl	a,#HIGH_MASK		; obere Bits loeschen
	call	lcd_out			; High nibble ausgeben (in LSBs!)

	pop	acc			
	anl	a,#HIGH_MASK
	call	lcd_out			; Low nibble ausgeben (in LSBs!)

	call	us_50			; Wartezeit > 40 us bis
					; naechster Befehl weil LCD
					; im Write-Only-Mode ohne Busy Flag
	ret

        ;*********************************************************************
	; Erstellung eines Sonderzeichens waehrend Init
	; DPTR zeigt auf die Bytes des Sonderzeichens;
	; in A wird uebergeben, welche Sonderzeichennummer programmiert
	; werden soll (von 0 bis 7, jedes Zeichen hat 8 Bytes im CGRAM)

prog_custom:
	
	mov 	MERK,#08H		; 8 Bytes sind ein Sonderzeichen

					; Beispiel:	000 01110
					;		000 10101
					;		000 10101
					;		000 10101
					;		000 10101
					;		000 10101
					;   		000 01110
					;		000 00000

	rl	A			; 1. Zeichen hat 8 Bytes 0..7
	rl	A			; 2. Zeichen hat 8 Bytes 8..15
	rl	A			; ...
					; 7. Zeichen hat 8 Bytes 56..63
					; um von der Zeichennummer  (0 bis 7)
					; zur Startadresse zu kommen: *8
	orl	A,#CG_ADDR		; oberste Bits zu 01 setzen
					; damit wird's eine CGRAM Adresse
	call	instr_out

PG_1:	mov	A,#0			; Akku löschen
	movc	A,@A+DPTR		; Reihe holen
	inc	DPTR
	call	char_out		; An LCD senden
	
	call	us_50			; Wartezeit extra
	call	us_50			; Wartezeit extra

	djnz	MERK, PG_1		; Schleife, 8 Reihen programmieren
					; bis ein Zeichen fertig ist
	ret

;*****************************************************************************
; ENDE DES QUELLTEXTES
;*****************************************************************************

