DSEG CurDisplay: ds 1 ;Für folgende Ausgabe aktive Display-Hälfte(n) ;(für ein vierzeiliges Display) CSEG ;****************************************************************************** ;** Wenn man beim Löten etwas Mist baut (hier: die Steuer- und Datenpins ** ;** unglücklich verteilt), kann man's auch durch Software wieder hinbiegen, ** ;** ist aber NICHT nachahmenswert! ** ;** Verbleibenden Portpins werden rigoros auf den _gelesenen_ Pegel gesetzt, ** ;** Vorsicht bei Eingängen! ** ;****************************************************************************** DISP_DATA set P4 ; Port mit den 4 Datenleitungen (Nibble-Modus) DATA0_BIT set 0 DATA1_BIT set 2 DATA2_BIT set 4 DATA3_BIT set 6 DATA0 set 1 shl DATA0_BIT DATA1 set 1 shl DATA1_BIT DATA2 set 1 shl DATA2_BIT DATA3 set 1 shl DATA3_BIT DISP_CONTROL set P5 ; Port mit den 4 Steuerleitungen E_unten set 1 shl 7 ; 1=Enable untere 2 Zeilen E_oben set 1 shl 6 ; 1=Enable obere 2 Zeilen RW set 1 shl 5 ; 0=Schreiben, 1=lesen RS set 1 shl 4 ; 0=Steuerbefehl, 1=Zeichen Eu_BIT set DISP_CONTROL.7 Eo_BIT set DISP_CONTROL.6 RW_BIT set DISP_CONTROL.5 RS_BIT set DISP_CONTROL.4 ;******************************* ;** Anzeige: LowLevel-Zugriff ** ;******************************* ;PUBLIC disp_addr_in, disp_data_in, disp_ctrl_out, disp_char_out, disp_init_ll disp_nib_in: ;1 Nibble vom Display einlesen ;PE: [CurDisplay]=E_unten _oder_ E_oben, RW_BIT=1 und RS_BIT schon gesetzt ;PA: a=gelesenes Nibble, High-Teil=0 ;VR: a mov a,DISP_DATA orl a,#(DATA3 or DATA2 or DATA1 or DATA0) mov DISP_DATA,a ; alle Bits high = hochohmig mov a,DISP_CONTROL orl a,CurDisplay mov DISP_CONTROL,a nop ;Zeit bis zum Erscheinen der Daten t(DDR)=360ns clr a mov c,DISP_DATA.DATA3_BIT rlc a mov c,DISP_DATA.DATA2_BIT rlc a mov c,DISP_DATA.DATA1_BIT rlc a mov c,DISP_DATA.DATA0_BIT rlc a disp_disable: clr Eu_BIT clr Eo_BIT ret disp_data_in: ; Befehl "Read Data" ;PE: r2=E_oben _oder_ E_unten ;PA: a=gelesene Daten ;VR: a,b, RW_BIT=1, RS_BIT=1 setb RS_BIT sjmp disp_byt_in disp_addr_in: ; Befehl "Read Busy+Addr" ;PE: r2=E_oben _oder_ E_unten ;PA: a=gelesene Daten ;VR: a,b, RW_BIT=1, RS_BIT=0 clr RS_BIT disp_byt_in: ;1 Byte vom Display einlesen ;PE: [CurDisplay] = E_oben _oder_ E_unten sowie RW=1 und RS wie gewünscht ;PA: a=gelesene Daten ;VR: a,r2 setb RW_BIT call disp_nib_in ;High-Nibble zuerst lesen swap a mov r2,a call disp_nib_in ;Low-Nibble danach lesen orl a,r2 ret disp_wait_ready: ;Wartet bis Display bereit zum Datenempfang ;VR: RW_BIT=1, RS_BIT=0, kann komplett blockieren! push ACC disp_warte: call disp_addr_in jb ACC.7,disp_warte pop ACC ret disp_char_out: ;1 Zeichen (mit RS=1) auf Display-Hälfte(n) ausgeben, wartet auf Bereitschaft ;PE: a=Zeichen (oder Zeile des Zeichenbildes) [CurDisplay]=Display-Hälften-Bit(s) ;PA: - ;VR: r2 call disp_wait_ready setb RS_BIT sjmp disp_byt_out disp_ctrl_out: ;1 Steuer-Byte (mit RS=0) auf Display-Hälfte(n) ausgeben, wartet auf Bereitschaft ;PE: a=Steuerbyte, [CurDisplay]=Display-Hälften-Bit(s) ;PA: - ;VR: r2 call disp_wait_ready ;löscht RS bereits(!) disp_byt_out: ;1 Byte auf Display ausgeben OHNE zu warten ;PE: a=Zeichen- oder Steuerbyte, RS_BIT nach Wunsch, [CurDisplay]=Bits ;PA: - ;VR: r2 clr RW_BIT ;immer "schreiben" acall disp_nib_out disp_nib_out: ;Ausgabe eines Nibbles aufs Display(s) ohne auf Not-Busy warten ;PE: a=Zeichen- oder Steuer-Nibble IM HIGH-TEIL, r2="Steuerleitungen", also ; E_oben = oberen Controller ansprechen, E_unten = entsprechend, auch beide gleichzeitig möglich ; RS_BIT = Zeichenausgabe (sonst Steuerbefehl) ;PA: a: Low-Nibble zum High-Nibble geschafft, Low-Nibble undefiniert ;VR: a,r2 rlc a ;Bit ausschieben mov DISP_DATA.DATA3_BIT,c ;Bit3 hier einsetzen rlc a ;Bit ausschieben mov DISP_DATA.DATA2_BIT,c ;Bit2 dort einsetzen rlc a ;Bit ausschieben mov DISP_DATA.DATA1_BIT,c ;dito rlc a ;Bit ausschieben mov DISP_DATA.DATA0_BIT,c mov r2,a mov a,DISP_CONTROL orl a,CurDisplay mov DISP_CONTROL,a ;das setzt die gewünschen Bits mov a,r2 jmp disp_disable ;fallende Flanke(n) erzeugen disp_init_ll: ;LowLevel-Initialisierung des Displays und seines Interfaces ;PE: - ;PA: [CurDisplay] adressiert noch beide Display-Hälften ;VR: a,r2,r4,r5 mov CurDisplay,#E_oben or E_unten ;beide Hälften clr RS_BIT ;immer "Steuerbefehl" clr RW_BIT ;immer "schreiben" mov a,#30h call disp_nib_out mov r4,#4 call wait mov a,#30h call disp_nib_out call wait1 mov a,#30h call disp_nib_out call wait1 mov a,#20h ; auf Nibble-Betrieb stellen call disp_nib_out call wait1 mov a,#28h ; "System Set": 2/4 Zeilen jmp disp_ctrl_out ;******************************** ;** Anzeige: HighLevel-Zugriff ** ;******************************** ;PUBLIC put_cg, gotoxy, put_xy, Put_Follow, Put_XY_Follow, disp_init put_cg: ;Zeichen-Bitmap setzen ;PE: a=CG-Adresse (40h=1. Zeichen, 48h=2. Zeichen usw.) ; r3=Anzahl Bytes ; DPTR=Bitmap-Zeiger (ins Code-Segment) 8 Bytes ;PA: DPTR zeigt hinter die 8 Bytes ;VR: a,b,DPTR,r2,r3,[CurDisplay] (danach gotoxy aufrufen!) mov CurDisplay,#E_oben or E_unten ;beide Chips call disp_ctrl_out ; "CG-Adresse setzen" pu_cg_next: clr a movc a,@a+dptr inc dptr call disp_char_out djnz r3,pu_cg_next ret gotoxy: ;PE: R3=Spalte (Bits 0..5) und Zeile (Bits 6 und 7) ;PA: [CurDisplay]=Zeichen-Ausgabe-"Adresse" für folgende byt_out-Aufrufe ;VR: a,r2 mov CurDisplay,#E_oben mov a,r3 ;r3 legt fest E_oben oder E_unten mit Bit 7 anl a,#80h jz pu_1 ;E_oben oder E_unten? mov CurDisplay,#E_unten pu_1: mov a,r3 orl a,#80h ; Adress-Befehl zusammensetzen jmp disp_ctrl_out ; "CC-Adresse setzen" ;gotoxy ENDP put_xy: ;String-Ausgabe aus Codesegment ;PE: r3=Ausgabe-Adresse (0=1. Zeile, 40h=2. Zeile, 80h=3. Zeile, C0h=4. Zeile) ; DPTR=String-Zeiger (im Code-Segment) ;PA: DPTR zeigt hinter die Null ;VR: a=0,DPTR,r2 call gotoxy sjmp put_string put_string_loop: call disp_char_out put_string: clr a movc a,@a+dptr inc dptr jnz put_string_loop ;(noch ein) Zeichen ausgeben ret Put_Follow: ;Ausgabe konstanter ASCIIZ-String, der nach dem Unterprogramm-Aufruf ;notiert wird ;PE: - (CurDisplay muss durch einen Aufruf von gotoxy stehen) ;PA: - ;VR: a=0,dptr,r2 pop DPH pop DPL call put_string jmp @a+dptr ;zurück zum Aufrufer (wirklich!) Put_XY_Follow: ;wie "gotoxy" und "Put_Follow" zusammen ;PE: R3 = Position ;PA: - ;VR: a=0,dptr,r2 pop DPH pop DPL call put_xy jmp @a+dptr ;zurück zum Aufrufer (wirklich!) disp_init: ;HighLevel-Initialisierung: Modus setzen u.ä. mov a,#08h call disp_ctrl_out mov a,#01h call disp_ctrl_out mov a,#06h call disp_ctrl_out mov a,#00001100b ;Cursors blinken usw. jmp disp_ctrl_out