Programm

 

 

 


dESµ    DCF 77 - Funkuhrempfänger


 

 

 


LCD77.INC – der LCD-Treiber









An diesem Treiber wird noch gearbeitet. Er soll so umgeschrieben werden, dass ein Tor für den Betrieb der LCD-Anzeige ausreicht. Das bedingt dann einen 4Bit Datenbus zur LCD.
Der hier vorliegende Treiber benutzt 8Bit für den Datenbus zur LCD und drei Steuerbits eines zweiten Tores.
Der LCD-Treiber besteht aus zwei Programmteilen. Der erste Teil organisiert die Textstringausgaben zur LCD-Anzeige, der zweite Teil, der mit LCD.INC überschrieben ist, betrifft die physikalische Übertragung der Signale von und zur LCD-Anzeige über den 8Bit Datenbus. Er soll neu organisiert werden.






; LCD77.INC
; ----------  Version 220995  (für Funkuhr DCF77)

;             (c) 95 Schwarzer,
;             BBS Winsen, Bürgerweide 20, 21243 Winsen/L

; benutzt R7 als Zähler für LogoTime und in Zeile zeichen

LogoTime   EQU     3          ; Zeit in Sekunden für Logo
AlrmTime   EQU     45         ; Zeit in Sekunden für Alarm

dChr1      equ     0A0h       ; Zeichen 0 aus CG-Ram
dChr2      equ     0A1h       ;   "     1
dChr3      equ     0A2h       ;   "     2
dChr4      equ     0A3h       ;   "     3
dChr5      equ     0A4h       ;   "     4
dChr6      equ     0A5h       ;   "     5
dChr7      equ     0A6h       ;   "     6
dChr8      equ     0A7h       ;   "     7



LCD_BIT   SEGMENT BIT         ; DatenSegment mit 1 Byte
LCD_Disp  SEGMENT CODE

          RSEG    LCD_BIT
ResFlg:   DBIT 1
ResetFlg: DBIT 1
RTextFlg: DBIT 1
ATextFlg: DBIT 1
MCuhrFlg: DBIT 1
DCuhrFlg: DBIT 1

          RSEG    LCD_Disp
                
; Name: LCD_init
; Typ:    Unterprogramm  LCD-Ausgabe
; Soft-Reset des LCD-Moduls, Anzeige löschen, Cursor aus,
; Scrolling aus setzt Zeichensatz und schreibt den Starttext
LCD_init: call    dinit           ; Display initialisieren
          clr     ScrlFlg         ; Anzeige-Scrolling aus
          mov     A, #00000001b   ; LCD löschen
          call    dIout
          mov     A, #00001100b   ; LCD Cursor aus
          call    dIout
          call    dsetDefCG       ; Standard-CG-Tabelle
          mov     DPTR, #dUhrLogo ; Kopfzeile schreiben
          call    dstroutc
          mov     R7, #LogoTime   ; Zeit des Logos setzen
          clr     ResetFlg        ; Reset Aktiv
          clr     RTextFlg
          clr     ATextFlg
          ret

dUhrLogo: db    '  ¡¢£ MC-80535  ¡¢£ '
          db    ' ------------------ '
          db    'BBS im LdKrs Harburg'
          db    ' (c) 95.1 Schwarzer ',0

; Name: LCDout
; Typ:  Unterprogramm  LCD-Ausgaben
; gibt die Uhrzeit und die Statuszeichen zur LCD-Anzeige
; aus. 
; Werden Statuszeichen angezeigt, dann ist die Funkuhr in
; Betrieb.
; Anzeige: +1 UTC+1Std = MEZ.  Anzeige: +11 UTC+2Std = MESZ

LCDout:   jb   Sync_RES, NoLogo
          mov  A, R7
          jz   NoLogo
          dec  R7                ; LogoZeit vermindern
          ret

NoLogo:   call DCFtimeOut        ; Zeitstring ausgeben

          jnb  DCFTIME,  LCDo1
          setb AlarmSet
          jmp  DCFuhr            ;  --> DCF-Uhr aktiv
LCDo1:    jnb  Sync_RES, LCDo2
          setb AlarmSet
          jmp  MCuhr             ;  --> MC _Uhr aktiv

LCDo2:    clr  MCuhrFlg          ;  --> nach dem Reset
          clr  DCuhrFlg

          jb   ResetFlg, ResTxt0
          setb ResetFlg
          mov  A, #0
          mov  DPTR, #ChrTabD    ; Zeichentabelle DCF setzen
          call dsetCGramNr
          mov  A, #80h
          call line
          mov  A, #94h
          call line

ResTxt0:  jnb  ST4, ResTxt1      ; Wird bei Erkennung des
          mov  dSEK, #0          ; Minutensignal durchlaufen
          mov  dMIN, #0
          mov  dSTD, #0
          mov  A, #6
          mov  DPTR, #ChrTabR2   ; Text ausgeben
          call dsetCGramNr
          mov  DPTR, #TxtReset2
          setb RTextFlg
          jmp  ResTxtOut

ResTxt1:  jb   ResFlg, ResTxt2
          mov  A, #6
          mov  DPTR, #ChrTabR0   ; Text im Wechsel ausgeben
          call dsetCGramNr
          jb   RTextFlg, ResTxt11
          mov  DPTR, #TxtReset0
          setb ResFlg
          jmp  ResTxtOut
ResTxt11: mov  DPTR, #TxtReset01
          setb ResFlg
          jmp  ResTxtOut

ResTxt2:  mov  A, #6
          mov  DPTR, #ChrTabR1
          call dsetCGramNr
          jb   RTextFlg, ResTxt21
          mov  DPTR, #TxtReset1
          clr  ResFlg
          jmp  ResTxtOut
ResTxt21: mov  DPTR, #TxtReset11
          clr  ResFlg
          jmp  ResTxtOut

ResTxtOut: mov A, #0
           mov B, #1
          call dgotoXY
          call dstroutc
          jmp  LCDalrm

; -------------------------------------------------------
; Programmteil wird durchlaufen, wenn die interne Uhr aktiv
; ist. Setzt einmalig den Bildkopf und reaktiviert ihn nach
; der Meldung, eines Alarms

MCuhr:    jb      MCuhrFlg, MCuhre
          clr     DCuhrFlg
          clr     ResetFlg
          setb    MCuhrFlg
          mov     DPTR, #ChrTabM  ; neue Zeichentab. setzen
          clr     A
          call    dsetCGramNr
          call    line2
          mov     A, #80h
          call    dIout
          mov     DPTR, #TxtMCuhr ; MC -Uhr ist aktiv
          call    dstroutc
MCuhre:   jmp     LCDalrm



; ---------------------------------------------------------
; Programmteil wird durchlaufen, wenn die DCF-77 Uhr aktiv
; ist. Er setzt einmalig den Bildkopf und bei jedem
; Durchlauf den Schriftzug Sommer- bzw. Winterzeit. Es sei
; denn, ein Alarm macht gerade seine Ausgaben 

DCFuhr:   jb   DCuhrFlg, DCFuhra  ; DCF -Uhr ist aktiv
          setb DCuhrFlg
          clr  MCuhrFlg
          clr  ResetFlg
          mov  DPTR, #ChrTabD     ; neue Zeichentab.setzen
          clr  A
          call dsetCGramNr
          call line2
          mov  A, #80h
          call dIout
          mov  DPTR, #TxtDCuhr
          call dstroutc

DCFuhra:  jb   ATextFlg, LCDalrm
          mov  A, #89h
          call dIout

          jb   MEZ,DCFmez
          mov  DPTR, #Txtmesz
          call dstroutc
          jmp  LCDalrm

DCFmez:   mov  DPTR, #Txtmez
          call dstroutc

LCDalrm:  jnb  AlarmSet, LCDend
          call AlarmHandle
LCDend:   ret


; sieht nach, ob zu der momentanen Zeit eine Alarm ange-
; geben ist, wenn ja, wird ein zugeordneter Text ausgegeben.
: Ist ein Text ausgegeben, wird die Standzeit des Textes
; in R7 vermindert bis 0, sonst Rückkehr zur Haupt-
; warteschleife

AlarmHandle:
          lcall Alarm             ; Alarmzeiten durchsehen
          jnz   nxtA0             ; A=0 war nix
          jnb   ATextFlg, nxtAret
          dec   R7                ; Standzeit vermindern
          cjne  R7, #0, nxtAret
          clr   ATextFlg          ; Standzeit Alarm abgel.
          clr   MCuhrFlg          ; Text für MC oder DCF-Uhr
          clr   DCuhrFlg          ; muß neu ausgeg. werden
nxtAret:  ret

nxtA0:    cjne  A, #1, nxtA1      ; A!=0 es ist ein Alarm
          mov   DPTR, #AText1     ; erreicht
          ljmp  ATextOut
nxtA1:    cjne  A, #2, nxtA2
          mov   DPTR, #AText2
          ljmp  ATextOut
nxtA2:    cjne  A, #3, nxtA3
          mov   DPTR, #AText3
          ljmp  ATextOut
nxtA3:    cjne  A, #4, nxtA4
          mov   DPTR, #AText4
          ljmp  ATextOut
nxtA4:    cjne  A, #5, nxtA5
          mov   DPTR, #AText5
          ljmp  ATextOut
nxtA5:    cjne  A, #6, nxtA6
          mov   DPTR, #AText6
          ljmp  ATextOut
nxtA6:    cjne  A, #7, nxtA7
          mov   DPTR, #AText6
          ljmp  ATextOut
nxtA7:    cjne  A, #8, nxtA8
          mov   DPTR, #AText8
          ljmp  ATextOut
nxtA8:    cjne  A, #9, nxtA9
          mov   DPTR, #AText9
          ljmp  ATextOut
nxtA9:    cjne  A, #10, nxtAA
          mov   DPTR, #ATextA
          ljmp  ATextOut
nxtAA:    cjne  A, #11, nxtAB
          mov   DPTR, #ATextB
          ljmp  ATextOut
nxtAB:    cjne  A, #12, nxtAC
          mov   DPTR, #ATextC
          ljmp  ATextOut
nxtAC:    cjne  A, #13, nxtAend
          mov   DPTR, #ATextD
          ljmp  ATextOut
nxtAend:  ret

; Löscht die gesamte Anzeige auf ein schwarzes Feld und
; gibt dann den Text, auf den der DPTR zeigt aus.
ATextOut: setb  ATextFlg
          push  DPL
          push  DPH
          mov   A, #080h
          call  dIout
          mov   R7, #80
_TxtOLop: mov   A, #0FFh
          call  dDout
          dec   R7
          cjne  R7, #0, _TxtOLop
          mov   A, #0C0h
          call  dIout
          pop   DPH
          pop   DPL
          call  dstroutc
          mov   R7, #AlrmTime
          ret
; ---------------------------------------------------------
AText1:     db      'ÿÿ  Guten Morgen  ÿÿ',0
AText2:     db      'ÿÿ PAUSE bis 9.35 ÿÿ',0
AText3:     db      'ÿÿ  1.Pause Ende  ÿÿ',0
AText4:     db      'ÿ PAUSE bis  11.25 ÿ',0
AText5:     db      'ÿÿ  2.Pause Ende  ÿÿ',0
AText6:     db      'ÿÿ Ende der 6.Std ÿÿ',0
AText7:     db      'ÿ Beginn der 7.Std ÿ',0
AText8:     db      'ÿÿ Ende der 7.Std ÿÿ',0
AText9:     db      'ÿÿ Ende der 8.Std ÿÿ',0
ATextA:     db      'ÿÿ Ende der 1.Std ÿÿ',0
ATextB:     db      'ÿÿ Ende der 3.Std ÿÿ',0
ATextC:     db      'ÿÿ Ende der 5.Std ÿÿ',0
ATextD:     db      'ÿÿ   Feierabend   ÿÿ',0
; ---------------------------------------------------------
TxtReset0:  db    ' suche Tr„gersignal ',0
TxtReset1:  db    '    DCF 77,5 kHz    ',0
TxtReset01: db    '-  ..decodiere..   -',0
TxtReset11: db    '~  Zeit-Protokoll  ',0
TxtReset2:  db    '|  Minutentrigger  |',0

TxtMCUhr:   db    'ÿ ¡¢£ÿ  interne Zeit',0
TxtDCUhr:   db    'ÿ ¡¢ÿ££ÿ            ',0
Txtmez:     db    ' Normalzeit',0
Txtmesz:    db    ' Sommerzeit',0

; ---------------------------------------------------------

ChrTabR0:   db 10000000b    ; Code:    04 od. 0C  (A4h)
            db 10011111b    ; Zeichen: Kringel klein
            db 10010001b
            db 10010001b
            db 10010001b
            db 10010001b
            db 10011111b
            db 10000000b

            db 10000000b    ; Code:    05 od. 0D  (A5h)
            db 10011111b    ; Zeichen: Kringel groá
            db 10001110b
            db 10011111b
            db 10001110b
            db 10000100b
            db 10011111b
            db 10000000b
            db 0

ChrTabR1:   db 10000000b    ; Code:    05 od. 0D  (A5h)
            db 10011111b    ; Zeichen: Kringel groß
            db 10000000b
            db 10000000b
            db 10000000b
            db 10000000b
            db 10011111b
            db 10000000b

            db 10000000b    ; Code:    04 od. 0C  (A4h)
            db 10011111b    ; Zeichen: Kringel klein
            db 10000100b
            db 10001110b
            db 10011111b
            db 10001110b
            db 10011111b
            db 10000000b
            db 0

ChrTabM:    db 10011111b    ; Code:    00 od. 08  (A0h)
            db 10011101b    ; Zeichen: Logo d
            db 10011101b
            db 10010001b
            db 10010101b
            db 10010001b
            db 10011111b
            db 10011111b

            db 10011111b    ; Code:     01 od. 09 (A1h)
            db 10010001b    ; Zeichen:  Logo E
            db 10010111b
            db 10010011b
            db 10010111b
            db 10010001b
            db 10011111b
            db 10011111b

            db 10011111b    ; Code:     02 od. 0A (A2h)
            db 10010001b    ; Zeichen:  Logo S
            db 10010111b
            db 10010001b
            db 10011101b
            db 10010001b
            db 10011111b
            db 10011111b

            db 10011111b    ; Code:    03 od. 0B  (A3h)
            db 10011111b    ; Zeichen: Logo æ
            db 10011111b
            db 10010101b
            db 10010101b
            db 10010001b
            db 10010111b
            db 10010111b

            db 10000000b    ; Code:    04 od. 0C  (A4h)
            db 10000000b    ; Zeichen: Unterstrich
            db 10000000b
            db 10000000b
            db 10000000b
            db 10011111b
            db 10010101b
            db 10011111b

            db 10011111b    ; Code:    05 od. 0D  (A5h)
            db 10011111b    ; Zeichen: =
            db 10000000b
            db 10011111b
            db 10000000b
            db 10000000b
            db 10000000b
            db 10000000b

            db 10011111b    ; Code:    06 od. 0E  (A6h)
            db 10010001b    ; Zeichen: I Antenne
            db 10011011b
            db 10011011b
            db 10010001b
            db 10011111b
            db 10000000b
            db 10000000b

            db 10011111b    ; Code:    07 od. 0F  (A7h)
            db 10011011b    ; Zeichen: A Alarm
            db 10010101b
            db 10010001b
            db 10010101b
            db 10011111b
            db 10000000b
            db 10000000b
            db 0

ChrTabD:    db 10011111b    ; Code:    00 od. 08  (A0h)
            db 10010011b    ; Zeichen: Logo D
            db 10010101b
            db 10010101b
            db 10010101b
            db 10010011b
            db 10011111b
            db 10011111b

            db 10011111b    ; Code:     01 od. 09 (A1h)
            db 10010001b    ; Zeichen:  Logo C
            db 10010111b
            db 10010111b
            db 10010111b
            db 10010001b
            db 10011111b
            db 10011111b

            db 10011111b    ; Code:     02 od. 0A (A2h)
            db 10010001b    ; Zeichen:  Logo F
            db 10010111b
            db 10010011b
            db 10010111b
            db 10010111b
            db 10011111b
            db 10011111b

            db 10011111b    ; Code:    03 od. 0B  (A3h)
            db 10010001b    ; Zeichen: Logo 7
            db 10011101b
            db 10011011b
            db 10010111b
            db 10010111b
            db 10011111b
            db 10011111b

            db 10000000b    ; Code:    04 od. 0C  (A4h)
            db 10000000b    ; Zeichen: Strich1
            db 10000000b
            db 10000000b
            db 10000000b
            db 10011111b
            db 10011111b
            db 10011111b

            db 10011111b    ; Code:    05 od. 0D  (A5h)
            db 10011111b    ; Zeichen: Strich2
            db 10000000b
            db 10011111b
            db 10000000b
            db 10000000b
            db 10000000b
            db 10000000b

 ChrTabR2:  db 10000000b    ; Code:    06 od. 0E  (A6h)
            db 10011111b    ; Zeichen: frei
            db 10001010b
            db 10011111b
            db 10011111b
            db 10001010b
            db 10011111b
            db 10000000b

            db 10000000b    ; Code:    07 od. 0F  (A7h)
            db 10011111b    ; Zeichen: frei
            db 10001010b
            db 10011111b
            db 10011111b
            db 10001010b
            db 10011111b
            db 10000000b
            db 0

; Gibt mit den CG-Zeichen 6 und 7 eine Zeile von 20 Zeichen
; beginnend bei der Adresse in A aus

line:       call dIout
            mov  R7, #10
_linelop:   mov  A,  #6
            call dDout
            mov  A,  #7
            call dDout
            dec  R7
            cjne R7, #0, _linelop
            ret

line2:      mov  A, #0C0h
            call dIout
            mov  R7, #20
_l2lop1:    mov  A,  #4
            call dDout
            dec  R7
            cjne R7, #0, _l2lop1
            mov  A,  #094h
            call dIout
            mov  R7, #20
_l2lop2:    mov  A,  #5
            call dDout
            dec  R7
            cjne R7, #0, _l2lop2
            ret

; Gibt den Zeitstring auf Position 0|3 direkt zur LCD-
; Anzeige aus. Der Zeitstring steht im direkt adressier-
; baren Datenspeicher des Controllers und wird indirekt
; über R0 adressiert.

DCFtimeOut: mov  A, #0D4h
           lcall dIout
;           mov  A, #0
;           mov  B, #3
;           call dgotoXY    ; Cursoposition 0|3

            mov  R0, #TimeBuf
_timeolop:  mov  A, @R0     ; Zeichen auf d.R0 zeigt nach A
            jz   _timeoend  ; wenn A= 0 dann Ende
            lcall dDout     ; Zeichen direkt zur LCD
            inc  R0         ; R0= R0+1
            jmp _timeolop
_timeoend:  ret





Allgemeiner LCD-Treiber
Die nachfolgenden Programmteile können als selbstängiges Treiberprogramm für LCD-Textanzeigen der angegebenen Typen verwendet werden. Dieser Treiber geht davon aus, dass die Anzeige mit einer Datenbusbreite von 8Bit über ein Tor des MC80515 versorgt wird. Die Steuersignale bezieht die Anzeige von einem zweiten Tor des Microcontrollers. Die verwendeten Tor können im Quelltext bestimmt werden.






; LCD.INC        Version 29.08.95
; -------
;               (c) 1995 Schwarzer,
;               BBS Winsen, Bürgerweide 20, 21423 Winsen/L
; --------------------------------------------------------
; Basistreiber-Programme für LCD-Anzeigen der Typen..

;  DMC20481-LY von OPTEX
;  Sony LM044L
;  Batron BT42005
;  Epson EA-D20040 ....... usw.

; diese Anzeigen besitzten 4 Zeilen und 20 Spalten pro Zeile
; und können mit 4 oder 8 Bit Datenbusbreite betrieben
; werden. Einige besitzen eine Beleuchtung. 

; Die vorliegenden Treiber gehen von einem direkten Betrieb
; der Anzeige an Toren des MC 80535 aus. Die Torvorgaben
; müssen bei veränderter Hardware ebenfalls geändert werden.

Daten       EQU    P4    ;Datentor
RS          EQU    P5.2  ;Befehl od. Daten zur LCD-Anzeige
RW          EQU    P5.1  ;Lese/Schreibsignal der Anzeige
CS          EQU    P5.0  ;Freigabesignal der Anzeige

; in ein Programm eingebunden, stehen die nachfolgenden
; Unterprogramme zur Verfügung.

;PUBLIC dstroutd      ; nullterm.String (Datensp) ausgeben
;PUBLIC dstroutc      ; nullterm.String (Codesp)  ausgeben
;PUBLIC dcout         ; Zeichen ausgeben  CR = CR + LF
;PUBLIC dcdout        ; Zeichen ausgeben  CR = CR

;PUBLIC dgetxy        ; momentane Cursorposition holen
;PUBLIC dgotoxy       ; Cursor auf Position  x,y setzen
;PUBLIC dcurpos1      ; Cursor auf Position  1,y
;PUBLIC dcurende      ; Cursor auf Position 19,y
;PUBLIC dcurbildu     ; Cursor auf Position  x,1
;PUBLIC dcurbildd     ; Cursor auf Position  x,4

;PUBLIC dadjr         ; C eine Spalte rechts bis Zeilenend
;PUBLIC dadjrs        ; C eine Spalte rechts mit Scrolling
;PUBLIC dadjl         ; C eine Spalte links  bis Zeilenend
;PUBLIC dadjls        ; C eine Spalte links  mit Scrolling
;PUBLIC dcurdn        ; C eine Zeile  runter ohne Scroll
;PUBLIC dcurdns       ; C eine Zeile  runter mit  Scroll
;PUBLIC dcurup        ; C eine Zeile  hoch   ohne Scroll
;PUBLIC dcurups       ; C eine Zeile  hoch   mit  Scroll

;PUBLIC dclr          ; Anzeige löschen
;PUBLIC dclreos       ; vom Cursor bis Anzeigenende löschen
;PUBLIC dclrln        ; Zeile löschen
;PUBLIC dclreol       ; vom Cursor bis Zeilenende löschen

;PUBLIC dcurson       ; Cursor einschalten
;PUBLIC dcursoff      ; Cursor ausschalten

;PUBLIC dnxtln        ; C nächste Zeile erste Pos,   scroll
;PUBLIC dvorl         ; C vorheri.Zeile letzte Pos,  scroll
;PUBLIC dscrolld      ; Scrolling nach unten
;PUBLIC dscrollu      ; Scrolling nach oben

;PUBLIC dSetDefCG     ; Voreingestellte Zeichen setzen
;PUBLIC dSetCGram     ; Benutzerdefinierte Zeichen setzen



; Die obigen Programmteile basieren auf den folgenden
; Basistreiberprogrammen

;PUBLIC dDin          ; Daten von der LCD_Anz holen
;PUBLIC dIout         ; Befehl zur LCD_Anz senden
;PUBLIC dDout         ; Daten  zur LCD_Anz senden
;PUBLIC dinit         ; Initialisiert die LCD Karte





                RSEG    LCD_BIT
ScrlFlg:        DBIT 1
; Daten der LCD - Anzeige:
; ------------------------
; an diesen Setzungen sollten nur dann Änderungen vorge-
; nommen werden, wenn eine andere LCD-Anzeige angeschlossen
; wurde. Besitzt diese mehr als 8 Zeilen, muß die
; Zeilentabelle im Programmteil '_gtze' ergänzt werden.

       _AZ      EQU   4    ; Anzahl Zeilen = 4
       _ZL      EQU  20    ; Anzahl Zeichen pro Zeile = 20

       _Z1e     EQU  093h  ; Endadressen der Zeilen
       _Z2e     EQU  0D3h
       _Z3e     EQU  0A7h
       _Z4e     EQU  0E7h
       _Z5e     EQU  0
       _Z6e     EQU  0
       _Z7e     EQU  0
       _Z8e     EQU  0





                RSEG    LCD_Disp

; Display_String_Out (Codespeicher)
; Gibt einen String aus, auf den DPTR zeigt. Der String muß
; nullterminiert sein. Er muß im Codespeicher stehen.

; Übergabe:  DPTR  AnfangsAdresse des String
; Verändert: A=0, DPTR= Adr. der 0
dstroutc:
          clr  A             ; A= 0
          movc A, @A+DPTR    
          jz   _dstec        ; wenn A= 0 dann Ende
          call dcout         ; Zeichen zur LCD
          inc  DPTR          ; DPTR= DPTR+1
          jmp  dstroutc
_dstec:   ret


; Display_String_Out (Datenspeicher)
; Gibt einen String aus, auf den DPTR zeigt. Der String muß
; nullterminiert sein. Er muß im Datenspeicher stehen.

; Übergabe: DPTR  Anfangs-Adresse
;                 des String
; Verändert: A=0, DPTR= Adr. der 0
dstroutd:
          movx A, @DPTR  
          jz   _dstes        ; wenn A= 0 dann Ende
          call dcout         ; Zeichen zur LCD
          inc  DPTR          ; DPTR= DPTR+1
          jmp  dstroutd
_dstes:   ret


; Display_Goto_XY (AB)
; Setzt den Cursor auf eine X-Y (Spalte-Zeile) Position bei
; der LCD-Anzeige. Ungültige Werte werden ignoriert.

; Übergabe: A  X-Position 0-19
;           B  Y-Position 0- 3
; Verändert: keine Register
dgotoxy:
          push DPL
          push DPH           ; Register A,B, DPTR sichern
          push B
          push ACC
          cjne A, #_ZL,_grgl0
_grgl0:   jnc  _gotoxye
          xch  A, B
          cjne A, #_AZ,_grgl1
_grgl1:   xch  A, B
          jnc  _gotoxye
          call dsetxy        ; Cursorposition setzen
_gotoxye: pop  ACC
          pop  B
          pop  DPH           ; Register A,B,DPTR vom Stack
          pop  DPL           ; holen
          ret

; Display_Character_Out
; Unterprogramm gibt das Zeichen in A über 'dcdout' aus,
; übersetzt aber ein CR in LF und bewirkt dadurch einen
; Zeilenvorschub und einen Wagenrücklauf
dcout:
          cjne A, #0Dh, _dce
          mov  A, #0Ah
_dce:     call dcdout
          ret

; Display_Character_out
; Gibt das Zeichen in A zur LCD-Anzeige aus. Ist die letzte
; Position der Anzeige erreicht, tritt ein Scrolling des
; angezeigten Textes ein. Das Programm entspricht dem
; Zeichenausgabeprogramm 'scout', das Zeichen zur seriellen
; Schnittstelle ausgibt.

; Übergabe:   A Ausgabezeichen
; Verändert:  keine Register
dcdout:
          push DPL
          push DPH           ; Register sichern
          push B
          push ACC

          jnb  ACC.7, _istz  ; Zeichen >= 128 ?
_ada5C:   call _dadapt       ; Zeichen ggf. umwandeln
          jmp  _cout         ; und ausgeben

_istz:    cjne A, #5Ch, _not5C
          jmp  _ada5C
_not5C:   cjne A, #20h, _pstz ; Zeichen ein SPC ?
_pstz:    jnc  _cout          ; Zeichen größer als SPC ?
          call _dstz         ; nein, ist Steuerzeichen
          jmp  _coute

_cout:    call dDout         ; Zeichen ist Ausgabezeichen
          call _dadj         ; Cursorposition ggf. anpassen
_coute:   pop  ACC
          pop  B
          pop  DPH           ; Register holen
          pop  DPL
          ret


; Display_Adjust
; Cursorkontrolle nach der Ausgabe eines Zeichens. Durch
; die Ausgabe des Zeichens wurde der Cursor bereits auf die
; nächste (rechte) Spalte gesetzt. In A steht noch die
; Position des ausgegebenen Zeichens.
; Das Programm prüft, ob der Cursor danach auf der richti-
; gen Zeile steht.
_dadj:
          mov  B, #(_AZ)     ;Anzahl der Zeilen nach B
          mov  DPL, A        ;momentane Position sichern
lopx:     mov  A, B
          jnz  lopx1         ;Zähler auf 0?
          call dbusy         ;ja, keine Endposition
          ret

lopx1:    dec  B
          mov  A, B
          call _gtze         ;letzte Zeilenposition holen
          cjne A, DPL, lopx  ;mit mom. Position vergleichen
          call dIout         ;Position des letzten Zeichens
          jmp  dnxtln        ;setzen und neue Zeile


; Tabelle der Steuerzeichen
; weist bei der Ausgabefunktion 'dcout' einigen Steuer-
; zeichen besondere Bedeutungen zu. Die Tabelle entspricht
; bis auf den Code 0Dh (CR) der des Terminalsteuerprogramms
; zur Ansteuerung des Bildschirms
_dstz:
          cjne A, #00h, _dstz0 ;0 keine Wirkung
          ret
_dstz0:   cjne A, #07h, _dstz1 ;(ctrl G)BELL (keine Wirkung)
          ret
_dstz1:   cjne A, #08h, _dstz2 ;(ctrl H)(BS) Cursor links
          ljmp dadjlb
_dstz2:   cjne A, #09h, _dstz3 ;(ctrl-I) horiz. Tabulat.
          ret
_dstz3:   cjne A, #0Ah, _dstz4 ;(ctrl-J (LF)
          ljmp dnxtln
_dstz4:   cjne A, #0Bh, _dstz5 ;(ctrl K)(VT) Cursor hoch
          ljmp dcurup
_dstz5:   cjne A, #0Ch, _dstz6 ;(ctrl L)(FF) Cursor rechts
          ljmp dadjr
_dstz6:   cjne A, #0Dh, _dstz7 ;(ctrl M)(CR)
          ljmp dcurpos1
_dstz7:   cjne A, #14h, _dstz8 ;(ctrl T)   "
          ljmp dadjr
_dstz8:   cjne A, #17h, _dstz9 ;(ctrl W) lösch bis Anz.Ende
          ljmp dclreos
_dstz9:   cjne A, #18h, _dstzA ;(ctrl X) lösch bis Zeil.Ende
          ljmp dclreol
_dstzA:   cjne A, #19h, _dstzB ;(ctrl Y) lösche Zeile
          ljmp dclrln
_dstzB:   cjne A, #1Ah, _dstzC ;(ctrl-Z) Bildschirm löschen
          ljmp dclr
_dstzC:   cjne A, #1Ch, _dstzD ;(ctrl ™)(FS) Curs.runt (x|4)
          ljmp dcurdn
_dstzD:   cjne A, #1Dh, _dstzE ;(ctrl Ž) Cursor HOME
          ljmp dcurbildu
_dstzE:   cjne A, #1Eh, _dstzF ;(ctrl ) (RS) Curs.hoch (x|0)
          ljmp dcurup
_dstzF:   cjne A, #1Fh, _dstzG ;(ctrl š)(US)Curs.links(0|x)
          ljmp dadjl
_dstzG:   ret

;...,....|....,....|....,....|....,....|....,....|....,....


; Display_Adaptieren
; Die LCD-Anzeige besitzt einige Zeichen, die auch im IBM-
; Zeichensatz vorkommen, jedoch besitzen sie hier einen
; anderen Aufrufcode. Zudem sind die Umlaute ä und ö nicht
; vorhanden. Dieser Programmteil sucht für den in A
; übergebenen IBM-Code den entsprechenden Code der Anzei-
; ge heraus. Damit die Umlaute bereitstehen, müssen sie vor
; der Benutzung dieses Programms im freien Zeichenram der
; Anzeige definiert worden sein. (s. dSetCGram)
; Durch dieses Programm werden die 8 Zeichen im CG-Ram
; unter den Codes A0h - A7h erreichbar

; Übergabe:   IBM -Code in A
; Rückgabe:   LCD -Code in A
; Verändert:  B, DPTR
_dadapt:
          xch  A, B           ;A in B sichern
          mov  DPTR, #_kovtab ;Basisadresse Konversionstabelle
          clr  A
_adalop:  push ACC
          movc A, @A+DPTR     ;Zeichen der Tabelle nach A
          jnz  _adacmp        ;ist das Zeich.der Tabelle 0?
          pop  ACC            ;ja .. Ende der Tabelle
          xch  A, B           ;Zeichen von B nach A
          ret                     
_adacmp:  cjne A, B, _adanxt  ;mit Zeichen in B vergleichen
          pop  ACC            ;wenn gleich
          inc  A              ;Zählwert in A + 1
          movc A, @A+DPTR     ;Ersatzzeichen nach A
          ret
_adanxt:  pop  ACC
          add  A, #2
          jmp  _adalop


; Übersetzungstabelle für dadapt
; ------------------------------

_kovtab:  db '„',  11100001b
          db '”',  11101111b
          db '',  11110101b
          db 'á',  11100010b
          db 'Ž',  00001110b     ;Zeichen aus CG-Ram
          db '™',  00001101b     ;Zeichen aus CG-Ram
          db 'š',  00001111b     ;Zeichen aus CG-Ram
          db 'ø',  11011111b
          db 'æ',  11100100b
          db 'ê',  11110100b
          db 'ö',  11111101b
          db 'ã',  11110111b
          db 'ä',  11110110b
          db 'ì',  11110011b
          db 'é',  11110010b
          db 'í',  11101100b
          db 'è',  11101100b
          db 'û',  11101000b
          db 'î',  11100011b
          db 'à',  11100000b
          db 'ù',  10100101b
          db 'Û',  11111111b
          db 05Ch, 00001100b     ; Zeichen aus CG-Ram
          db 0A0h, 00001000b     ; Zeichen 0 aus CG-Ram
          db 0A1h, 00001001b     ;   "     1
          db 0A2h, 00001010b     ;   "     2
          db 0A3h, 00001011b     ;   "     3
          db 0A4h, 00001100b     ;   "     4
          db 0A5h, 00001101b     ;   "     5
          db 0A6h, 00001110b     ;   "     6
          db 0A7h, 00001111b     ;   "     7
          db 0


; Display_Fix_Cursor -Programme
; setzen den Cursor an fest vorgegebene Positionen auf dem
; Bildschirm. Für alle Programme gilt:

; Übergabe:  keine
; Verändert: A, B, DPTR


; Setze den Cursor auf den Anfang der momentanen Zeile
; (Fkt:POS1)
dcurpos1:
          call dgetxy
          mov  A, #0
          jmp  dsetxy
              

; Setze den Cursor auf das Ende der momentanen Zeile
; (Fkt:ENDE)
dcurende:
          call dgetxy
          mov  A, #(_ZL-1)
          jmp  dsetxy
              

; Setze den Cursor auf die erste Position des Bildsch.
; (Fkt:BILD up)
dcurbildu:
          mov  A, #0
          mov  B, #0
          jmp  dsetxy
              

; Setze den Cursor auf die letzte Position des Bildsch.
; (Fkt:BILD down)
dcurbildd:
          mov  A, #(_AZ-1)
          call _gtze
          call dIout
          jmp  dbusy


; Display_Adjust -Programme:
; Ein kontinuierlicher Datenstrom zur LCD-Anzeige würde in
; den Zeilen (1,3,2,4) erscheinen. Diese Progamme prüfen
; an welcher Position sich der Cursor befindet und setzen
; ihn der Funktion des Programms entsprechend weiter. Es
; wird die Zeilenfolge (1,2,3,4) erzwungen. Hat der Cursor
; die erste oder letzte Ausgabeposition erreicht, so tritt
; ein Scrolling der gesamten Anzeige nach oben oder unten
; ein. Für alle nachfolgenden Programme gilt:

; Übergabe:   keine
; Verändert: A, B, DPTR


; Display_Adjust_right
; Cursor auf die nächste (rechte) Spalte, ohne das zuvor
; ein Zeichen ausgegeben wurde. Bei Erreichen der letzten
; Position wird nicht gescrollt.
dadjr:
           call dgetxy
           inc  A
           cjne A, #_ZL,_dadjre
           mov  A, #(_ZL-1)
_dadjre:   jmp  dsetxy


; Display_Adjust_right_Scrolling
; Cursor auf die nächste (rechte) Spalte ohne das zuvor
; ein Zeichen ausgegeben wurde. Bei Erreichen der letzten
; Position tritt ein Scrolling nach unten ein.
; (Fkt: Pfeil rechts)
dadjrs:
           call dgetxy
           inc  A
           cjne A, #_ZL,_dadjrse
           jmp  _dnxtl1
_dadjrse:  jmp  dsetxy



; Display_Cursor_down_Scrolling
; Cursor auf die nächste (untere) Zeile, ohne Änderung
; der Spalte. Wird die letzte Zeile erreicht tritt kein
; Scrolling ein
dcurdn:
           call dgetxy
           xch  A, B
           inc  A
           cjne A,#_AZ, _dcurdne
           mov  A, #(_AZ-1)
_dcurdne:  xch  A, B
           jmp  dsetxy


; Display_Cursor_down_Scrolling
; Cursor auf die nächste (untere) Zeile, ohne Änderung der
; Spalte. Wird die letzte Zeile erreicht, tritt ein
; Scrolling nach unten ein. Cursor Position 1 der neuen
; Zeile
; (Fkt: Pfeil runter)
dcurdns:
           call dgetxy     ;momentane Cursorposition holen
           jmp  _dnxtl2    ;nächste Zeile setzen



; Display_Next_Line
; Cursor auf die nächste Zeile, erste Spalte
dnxtln:
           call dgetxy     ;momentane Cursorposition holen
_dnxtl1:   clr  A          ;Spalte = 0
_dnxtl2:   xch  A, B       ;A= Zeile,  B=Spalte
           inc  A          ;Zeile= Zeile + 1
           cjne A, #_AZ, _dnxtl
           jb   ScrlFlg, _dnxts  ;Scrollen wenn Flagge =1
           mov  A, #_AZ-1
           jmp  _dnxtl
_dnxts:    jmp  dscrollu   ;Zeile scrollen
_dnxtl:    xch  A, B
           jmp  dsetxy     ;neue Position setzen



; Display_Adjust_left  (ohne Scrolling in die Vorzeile)
dadjl:
           call dgetxy
           jz   _dadjle
           dec  A
_dadjle:   jmp  dsetxy



; Display_Adjust_Left_BS
; (ohne Scrolling bei Erreichen von Zeile 1)
dadjlb:
           call dgetxy
           dec  A
           cjne A,#0FFh, _dadjlbe
           mov  A, #_ZL-1      ;Spalte = Endadresse
           xch  A, B           ;A= Zeile,  B=Spalte
           jz   _dadjlb
           dec  A
_dadjlb:   xch  A, B
_dadjlbe:  jmp  dsetxy         ;neue Position setzen



; Display_Adjust_left_Scrolling
; Cursor auf die vorherige (linke) Spalte ohne das zuvor
; ein Zeichen ausgegeben wurde.
; (Fkt: Pfeil links)
dadjls:
           call dgetxy            ;moment. Cursorpos. holen
           dec  A
           cjne A,#0FFh, _dadjles ;Curs am Anfg der Zeile?
           jmp  _dvorl1           ;dann in Vorzeile setzen
_dadjles:  jmp  dsetxy



; Display_Cursor_up
; Cursor auf die vorherige (obere) Zeile, ohne Änderung
; der Spalte.
; (Fkt: Pfeil hoch)
dcurup:
           call dgetxy         ;moment. Cursorpos. holen
           xch  A, B
           jz   _dcurupe
           dec  A
_dcurupe:  xch  A, B
           jmp  dsetxy         ;nächste Zeile setzen



; Display_Cursor_up
; Cursor auf die vorherige (obere) Zeile, ohne Änderung
; der Spalte.
dcurups:
           call dgetxy
           jmp  _dvorl2



; Display_Next_Line
; Cursor auf die letzte Spalte der vorherigen Zeile mit
; Scrolling nach oben
dvorl:
           call dgetxy         ;momentane Cursorposition holen
_dvorl1:   mov  A, #_ZL-1      ;Spalte = Endadresse
_dvorl2:   xch  A, B           ;A= Zeile,  B=Spalte
           dec  A
           cjne A, #0FFh, _dvorl  
           jmp  dscrolld       ;Zeile scrollen
_dvorl:    xch  A, B
           jmp  dsetxy         ;neue Position setzen



; Display_Set_Position_XY
; Die in A,B übergebene X,Y (Spalte,Zeile) Angabe wird auf
; der LCD-Anzeige gesetzt.

; Übergabe: A -Spalte  B -Zeile
; Verändert: A, B, DPTR
dsetxy:
           xch  A, B         ;Inhalte von A und B tauschen
           call _gtza        ;Anfadresse dieser Zeile holen
           add  A, B         ;dazu die Anzahl der Spalten
setpos:    call dIout        ;Cursor setzen
           call dbusy
           ret



; Display_Get_Position_XY
; Die momentane Position des Cursors wird in eine
; X,Y (Spalte,Zeile) Angabe in A,B umgerechnet.

; Übergabe: keine
; Rückgabe: A -Spalte   B -Zeile
; Verändert: DPTR wegen call busy
dgetxy:
           call dbusy        ;Cursorpos. der Anzeige holen
           mov  B, #0        ;ZeilenZähler auf 0 setzen
           xch  A, B         ;A= Zeile, B= Cursorposition
_dgtl:     push ACC          ;Zeilenzähler sichern
           call _gtze        ;Endadresse dieser Zeile holen
           cjne A, B, _eggc  ;Endadr >= Cursorp. ?
_eggc:     jc   _nxtad       ;nein: nächste Adresse prüfen
           clr  C
           subb A, #(_ZL-1)  ;Anfangsadresse der Zeile
           cjne A, B, _akgc  ;Anfadr <= Cursorp. ?
           jmp  _isok        ;ja:   Gleichheit
_akgc:     jc   _isok        ;ja:   Anfadr < Cursorp
_nxtad:    pop  ACC          ;Zähler holen
           inc  A            ;Zähler = Zähler+1
           jmp  _dgtl        ;mit nächster Endadr.vergleich
_isok:     xch  A, B         ;A= Cursorpos, B = Anfangsadr.
           clr  C            
           subb A, B         ;A= X-Position
           pop  B            ;B= Zeilenzähler = Y-Position
           ret



; Get_Zeilenende
; In A wird die Nummer der Zeile 0-3 übergeben. Das Pro-
; gramm gibt dann in A die Endadresse der Zeile zurück. Um
; Anzeigen mit mehr Zeilen betreiben zu können, müssen hier
; die Bezeichner der Endadressen dieser Zeilen angefügt
; werden
_gtze:
           inc  A                 ;'ret' liegt vor der zu
           movc A, @A+PC          ;lesenden Tabelle
           ret
           db _Z1e,_Z2e,_Z3e,_Z4e ;Zeilenende Tabelle. Muß
           db _Z5e,_Z6e,_Z7e,_Z8e ;bei Anzeigen mit mehr
                                  ;Zeilen ergänzt werden.
                                       


; Get_Zeilenanfang
; In A wird die Nummer der Zeile 0-3 übergeben. Das
; Programm gibt dann in A die Anfangsadresse der Zeile
; zurück.
_gtza:
           call _gtze        ;Zeilenende holen
           clr  C
           subb A, #(_ZL-1)  ;davon Die Zeilenlänge anziehen
           ret



; Display_Scroll_down
; Alle Zeilen der Anzeige werden um eine Zeile nach unten
; kopiert, die erste Zeile wird mit SPC gelöscht, und der
; Cursor an den Anfang dieser Zeile gesetzt.

; Übergabe:   keine
; Verändert: A, B, DPTR
dscrolld:
           mov  DPL, #(_AZ-1) ;Anzahl der Zeilen holen
_scrd:     mov  A, DPL
           cjne A, #0, _sdnl  ;kopieren bis Zeile 0 erreicht
           jmp  _scrl
_sdnl:     call _gtze         ;Adresse Zeilenende nach Zeile
           xch  A, B          ;nach Zeile in B
           dec  DPL
           mov  A, DPL
           call _gtze         ;Adresse Zeilenende  von Zeile
           call _dscr         ;kopieren der Zeile
           jmp  _scrd



; Display_Scroll (up)
; Alle Zeilen der Anzeige werden um eine Zeile nach oben
; kopiert, die letzte Zeile wird mit SPC gelöscht, und der
; Cursor an den Anfang dieser Zeile gesetzt.

; Übergabe:   keine 
; Verändert: A, B, DPTR
dscrollu:
           mov  DPL, #0        ;Anzahl der Zeilen holen
_scru:     mov  A, DPL               
           cjne A, #(_AZ-1), _sunl ;copy bis Zeile 0 erreicht
_scrl:     ljmp _dclrln
_sunl:     call _gtze          ;Adr. Zeilenende nach Zeile
           xch  A, B           ;nach Zeile in B
           inc  DPL
           mov  A, DPL
           call _gtze          ;Adr. Zeilenende  von Zeile
           call _dscr          ;kopieren der Zeile
           jmp  _scru



; Display_Scroll (Line)
; Es werden _ZL Spalten von Adresse A nach Adresse B kopiert
; _ZL gibt die Länge einer Zeile der Anzeige an.

; Übergabe:  A von  Adresse
;            B nach Adresse
; Verändert:  A, B, DPTR
_dscr:
           push DPL
           mov  dpl, #_ZL
_dscrl:
           push dpl
           push ACC
           call dIout         ;von Adresse ausgeben
           call dDin          ; dortiges Zeichen nach A
           push ACC
           mov  A, B          ;von und nach Adressen tauschen
           call dIout         ;nach Adresse einstellen
           pop  ACC
           call dDout         ; Zeichen dorthinkopieren
           pop  ACC
           pop  dpl

           dec  A
           dec  B
           djnz dpl, _dscrl
           pop  DPL
           ret



; Display _Clear_End of Screen
; Die Anzeige wird von der Cursorposition bis zum Ende mit
; SPC gelöscht. Der Cursor bleibt auf der Anfangsposition
dclreos:
           call dgetxy
           push ACC
           mov  A, #(_AZ-1)
           push B
eolclr:    pop  B
           cjne A, B,lnclr
           pop  ACC
           xch  A, B
           jmp  _dclreol
lnclr:     push B
           push ACC
           call _dclrln
           pop  ACC
           dec  A
           jmp  eolclr



; Dipsplay_Clear_Line
; Die Zeile in der der Cursor steht wird mit SPC gelöscht.
; Der Cursor wird an den Zeilenanfang gesetzt.

; Übergabe: keine
; Verändert: A, B, DPTR
dclrln:
           call dgetxy        ;momentane Cursorposition holen
           mov  A, B
_dclrln:   call _gtze         ;Endadresse der Zeile holen
           mov  B, A
           clr  C
           subb A, #(_ZL-1)   ;Anfangsadr. der Zeile berechn
           xch  A, B
           jmp  dclrBA        ;löschen



; Display_Clear till End of Line
; Die Zeile in der der Cursor steht, wird von der
; Cursorposition bis zum Zeilenende mit SPC gelöscht. Der
; Cursor bleibt auf der Ausgangsposition.
dclreol:
           call dgetxy        ;momentane Cursorposition holen
           xch  A, B         
_dclreol:  call _gtze         ;Endadresse dieser Zeile
           push ACC
           clr  C
           subb A,#(_ZL-1)    ;Anfangsadresse feststellen
           add  A, B          ;Cursoradresse berechnen
           xch  A, B
           pop  ACC
           jmp  dclrBA



; Display_Clear von A nach B  (A>=B)
; löscht rückwärts von Adresse A beginnend hin zu Adresse B
; die LCD- Anzeige      

; Übergabe: A -von Endadresse        
;           B -bis Anfangsadresse
; Verändert:  A, DPTR,  B bleibt unverändert
dclrBA:
           push ACC
           call dIout          ;Endadresse einstellen
           mov  A, #20h
           call dDout          ;SPC ausgeben
           pop  ACC
           dec  A
           cjne A, B, AklB     ;A >= B ?
AklB:      jnc  dclrBA         ;     nein: weiterer Umlauf
           mov  A, B           ;Cursor auf letzte gelöschte
           call dIout          ;Position
           ret



; Display_Clear
; Löscht die LCD-Anzeige und bringt den Cursor in die
; Home-Position

; Verändert:  A, DPTR
dclr:
           mov  A, #00000001b  ;Hitachi Code, lösche Anzeige
           call dIout
           mov  A, #10000000b  ;setzt Ausgabe-Adresse 0
           call dIout
           ret


; Display_Cursor on   (Cursor der Anzeige einschalten)
; Display_Cursor off  (Cursor der Anzeige ausschalten)
; schaltet die Anzeige ein, den Cursor der Anzeige ein oder
; aus und läßt das eingeschaltete Cursorzeichen blinken

; Verändert: A, DPTR

dcurson:
           mov  A, #00001111b  ;Hitachi Code  Cursor an
           call dIout
           ret
dcursoff:  mov  A, #00001100b  ;Hitachi Code  Cursor aus
           call dIout
           ret



;...,....|....,....|....,....|....,....|....,....|....,....

; Display_set_CG_Ram
; Display_set_default_CG

; Die LCD-Anzeige besitzt den DD-Ram, in den die
; anzuzeigenden Zeichen geschrieben werden, und den CG-Ram,
; in dem der Benutzer 8 eigene Zeichen definieren kann. Das
; Programm beschreibt den CG-Ram ab Adresse 0 mit
; Zeichendefinitionsbytes aus einer Tabelle, deren
; Anfangsadresse im DPTR angegeben ist. Die Tabelle kann
; weniger als 8 Zeichen umfassen. Sie muß mit 0 enden.

;Übergabe:   DPTR  Adresse der ZeichenTabelle
;Verändert: A, B, DPTR


;setzt die unten angegebene Zeichendefinitionstabelle
dsetDefCG:         
              mov  DPTR, #_chr1


;setzt beliebige Tabellen im CG-RAM, Auf den Beginn der
;Tabelle zeigt DPTR, das Ende der Tabelle ist eine 0
;Bei welchem Zeichen 0-7 begonnen werden soll steht in A
dSetCGramNr:             
          push DPL
          push DPH
          mov  B, #8
          mul  AB
          add  A, #01000000b  ;Basisadr. 40h addieren
          call dIout

_defchrl: pop  DPH
          pop  DPL
          clr  A
          movc A, @A+DPTR
          jz   _defchre       ;Endekennung ist 0
          inc  DPTR
          push DPL
          push DPH
          call dDout
          jmp  _defchrl
_defchre: mov  A, #10000000b  ;setzt die DD-RAMadresse 
          call dIout          ;auf 80h
          ret



; Standardzeichendefinition für das CG- RAM der LCD-Anzeige
; ---------------------------------------------------------
                              ;die Tabelle muß mit 0 enden

_chr1:   db 10011111b         ;Code:    00 od. 08
         db 10011101b         ;Zeichen: Logo d
         db 10011101b
         db 10010001b
         db 10010101b
         db 10010001b
         db 10011111b
         db 10011111b

_chr2:   db 10011111b         ;Code:     01 od. 09
         db 10010001b         ;Zeichen:  Logo E
         db 10010111b
         db 10010011b
         db 10010111b
         db 10010001b
         db 10011111b
         db 10011111b

_chr3:   db 10011111b         ;Code:     02 od. 0A
         db 10010001b         ;Zeichen:  Logo S
         db 10010111b
         db 10010001b
         db 10011101b
         db 10010001b
         db 10011111b
         db 10011111b

_chr4:   db 10011111b         ;Code:    03 od. 0B
         db 10011111b         ;Zeichen: Logo æ
         db 10011111b
         db 10010101b
         db 10010101b
         db 10010001b
         db 10010111b
         db 10010111b

_chr5:   db 10000000b         ;Code:    04 od. 0C
         db 10010000b         ;Zeichen: \
         db 10001000b
         db 10000100b
         db 10000010b
         db 10000001b
         db 10000000b
         db 10000000b

_chr6:   db 10001010b         ;Code:    05 od. 0D
         db 10001110b         ;Zeichen: ™
         db 10010001b
         db 10010001b
         db 10010001b
         db 10010001b
         db 10001110b
         db 10000000b

_chr7:   db 10001010b         ;Code:    06 od. 0E
         db 10001110b         ;Zeichen: Ž
         db 10010001b
         db 10010001b
         db 10011111b
         db 10010001b
         db 10010001b
         db 10000000b

_chr8:   db 10001010b         ;Code:    07 od. 0F
         db 10010001b         ;Zeichen: š
         db 10010001b
         db 10010001b
         db 10010001b
         db 10010001b
         db 10001110b
         db 10000000b
         db 0


;...,....|....,....|....,....|....,....|....,....|....,....|

; Basistreiber der LCD Anzeige
; LCD -Display Kernroutinen
; -------------------------

;dDin  - Display_Daten_in (Zeichen von der LCD_Anz holen)
;dIout – Display_Instruction_out(Befehl zur LCD_Anz. senden)
;dDout - Display_Daten_out (Zeichen zur LCD_Anz. senden)
;dBusy - Display_Beschäftigt ?

; diese Treiber können Daten und Befehle zur LCD senden und
; Daten von ihr holen. Sie kontrollieren zunächst,ob die LCD
; noch beschäftigt ist dann folgt ihre spezielle Aufgabe.

; dBusy  RS= 0, liest von der Anzeige ein Byte das die
; Position des Cursors angibt und in Bit 7 das Busy-Flag
; enthält. Wartet bis Bit 7= 0 wird und kehrt dann mit der
; Cursorposition in A zurück

; dDin   RS= 1, liest von der Anzeige das ASCII- Zeichen,
; auf dem der Cursor steht und gibt das Zeichen in A zurück

; dIout  RS= 0, übergibt das Zeichen in A der Anzeige. Wegen
; RS= 0 wird das Zeichen von der Anzeige als Befehl
; verstanden. (Adresse setzen, Anzeige löschen usw.)
; A bleibt unverändert

; dDout  RS= 1, übergibt das Zeichen in A der Anzeige. Wegen
; RS= 1 wird das Zeichen als Ausgabezeichen verstanden.
; A bleibt unverändert

dDin:    call dBusy
         setb RS            ;RS=1
         setb CS
         mov  A, Daten
         clr  CS
         ret

dIout:   push ACC
         call dBusy
         clr  RS            ;RS=0 -Befehl zum Display senden
         jmp  _dout
dDout:   push ACC
         call dBusy
         setb RS            ;RS=1 -Daten  zum Display senden
_dout:   pop  ACC
         clr  RW            ;RW=0 -R/W-Signal auf schreiben
         setb CS            ;CS=1 -Enable auf 1
         mov  Daten, A      ;Daten ausgeben
         clr  CS            ;CS=0 -Enable auf 0

dbusy:   mov  Daten, #0FFh  ;DatenTor fr Eingaben bereit
         clr  RS            ;RS=0 -Befehl zum Display senden
         setb RW            ;RW=1 -R/W-Signal auf lesen
busylop: setb CS
         mov  A, Daten
         clr  CS
         jb   ACC.7, busylop
         setb ACC.7
         ret


; dinit:
; Tastatur / LCD AnzeigeEinheit initialisieren
;------------------------------------------------------
; Das Programm berücksichtigt das Verhalten der LCD-Anzeige,
; wenn diese nach dem Anlegen der Spannungsversorgung ihren
; internen Resetablauf durchführt. In diesem Fall wird das
; BusyFlag zunächst 1 um dann auf 0 zu fallen, ohne daß
; jedoch schon Datenübergaben möglich wären. Für diesen Fall
; sendet 'dinit' ein Zeichen, bis eine Busyantwort erstma-
; lig erfolgt.

; Der LCD- Anzeige werden eine Reihe von Befehlsbytes
; übergeben, die die Datenbusbreite, die Zeilenzahl, den
; Cursor usw. einstellen. (siehe Befehlstabelle der Anzeige)

dinit:                        ;LCD nach erstem Einschalten
         mov  Daten, #0FFh    ;initialisieren.
         mov  DPTR, #7500     ;mind 15ms warten.
         call _initwait       ;RS R/W D7 D6 D5 D4 D3 D2 D1 D0
                              ;0  0   0  0  1  1  -  -  -  -
         mov  DPTR, #2050     ;mind 4,1ms warten
         call _initwait       ;0  0   0  0  1  1  -  -  -  -
                              ;mind 100us warten
         mov DPTR,  #50       ;0  0   0  0  1  1  -  -  -  -
         call _initwait       ;jetzt Busy-Flag i.o.
       
         mov  A, #00111000b   ;8Bit Datenbreite, 2 Zeilen
         call dIout
         mov  A, #00001111b   ;Disp on,Cursor on,Cursor blink
         call dIout
         mov  A, #00000110b   ;Cursor nach rechts kein shift
         call dIout
         mov  A, #10000000b   ;Zeile 1,Spalte 1
         call dIout
         setb ScrlFlg         ;Anzeige darf scrollen
         ret


_initwait:  inc  DPH        ;in DPTR angegebene Zeit warten
_iniwl:     djnz DPL, _iniwl
            mov  DPL, #0FFh
            djnz DPH, _iniwl
            clr  RS         ;8-Bit Datenübertragung senden
            clr  RW
            setb CS
            mov  Daten, #00111000b
            clr  CS
            ret
www..de