Lass mich bei der Erklärung mit einem 2 zeiligen LCD anfangen. Das ist
zunächst etwas einfacher.
Dazu ist zu sagen, dass für den Controller es eigentlich gar kein 2
zeiliges LCD gibt. Für ihn sieht die Sache so aus, dass er im Speicher
einfach eine Abfolge von Bytes hat
1 | +---+---+---+---+---+---+- ... -+---+---+---+- .... -+---+---+---+
|
2 | | | | | | | | | | | | | | | |
|
3 | +---+---+---+---+---+---+- ... -+---+---+---+- .... -+---+---+---+
|
Um ein 'A' anzuzeigen, schreibt er einfach den ASCII Code für 'A' zb in
diese Position
1 | +---+---+---+---+---+---+- ... -+---+---+---+- .... -+---+---+---+
|
2 | | A | | | | | | | | | | | | | |
|
3 | +---+---+---+---+---+---+- ... -+---+---+---+- .... -+---+---+---+
|
Damit daraus eine Anzeige auf dem Glas wird, gibt es eine Elektronik,
die ständig diesen Speicher durchgeht und entsprechend der vorgefundenen
Codes in jeder Pixelzeile die entsprechenden Pixel setzt.
Und diese Elektronik ist so gebaut, dass sie zb die ersten 16
Speicherpositionen in die erste Zeile abbildet und beginnend ab einer
bestimmten anderen Speicherposition die nächsten Zeichen in der 2.ten
Zeile.
1 | +---+---+---+---+---+---+- ... -+---+---+---+- .... -+---+---+---+
|
2 | | A | | | | | | | | | | | | | |
|
3 | +---+---+---+---+---+---+- ... -+---+---+---+- .... -+---+---+---+
|
4 |
|
5 | | Das hier kommt in die 1. Zeile | Und ab hier stehen die Zeichen
|
6 | für die 2. te Zeile
|
Normalerweise ist dieser 'Zeilenumbruch' bei der Speicherposition 64.
(Hex: 0x40)
Hä?
Wieso folgen die Speicherpositionen der 2.ten Zeile nicht direkt auf die
der ersten Zeile?
Zum einen weil der Speicher sowieso da ist und zum anderen weil man dann
ganz einfach LCDs austauschen kann. Ob ein LCD 2 Zeilen mit je 20
Zeichen oder 2 Zeilen mit je 16 Zeichen hat, spielt dann keine Rolle.
Die 2.te Zeile fängt im Speicher immer an der gleichen Stelle an. Das
hat Vorteile für die Software, die das LCD ansteuert. Denn die muss dann
nicht mehr wissen wieviele Zeichen eigentlich in eine Zeile passen. Die
schickt den Cursor immer in die 2.te Zeile, indem sie beginnend mit
Position 64 ausgibt. Egal wieviele physikalische Zeichen das LCD
tatsächlich anzeigt. Ist die Software so gebaut, dass sie zb 20 Zeichen
in einer Zeile annimmt, dann kann man da immer noch ein LCD mit 16
Zeichen pro Zeile anschliessen. Man wird zwar den Teil der Ausgabe, der
rechts 'raushängt' nicht sehen können, aber die Zeilenstruktur geht
damit nicht verloren.
D.h. bei einem LCD mit 2 Zeilen würde dann zb die erste Zeile bei der
Speicherposition 0 beginnen
1 | #define LCD_DDADR_LINE1 0x00
|
während die 2.te Zeile bei der Speicherposition 64 im Speicher beginnt
1 | #define LCD_DDADR_LINE2 0x40
|
Jetzt hast du aber kein LCD mit nur 2 Zeilen, sondern eines mit 4
Zeilen.
Irgendwo im Speicher mssen auch die Zeilen 3 und 4 anfangen. Nur wo?
Die 128 Bytes im Controller sind bereits so aufgeteilt, dass Zeile 1 bei
0 beginnt und Zeile 2 bei 64.
Aber
Du siehst ja gar nicht 64 Zeichen pro Zeile. Du siehst zb nur 16 Zeichen
pro Zeile, weil das LCD ja physikalisch gar nicht mehr anzeigen kann!
Man kann daher zb die Zeile 3 an der Position 16 beginnen lassen
1 | +---+---+---+---+---+---+- ... -+---+---+---+- .... -+---+---+---+
|
2 | | A | | | | | | | | | | | | | |
|
3 | +---+---+---+---+---+---+- ... -+---+---+---+- .... -+---+---+---+
|
4 |
|
5 | | Zeile 1 | Zeile 3 | Zeile 2 | Zeile 4 |
|
Die Zeilen 1 und 2 fangen nach wie vor genau dort im Speicher an, wo sie
auch vorher schon angefangen haben. Damit kann man ein 2 zeiliges LCD
gegen ein 4 zeiliges tauschen, ohne dass sich an der Ausgabe etwas
ändert. Die Zeilen fangen ja bei beiden LCD an derselben
Speicherposition an.
Zeile 3 fängt zb an der Speicherposition 16 an
1 | #define LCD_DDADR_LINE3 0x10
|
und Zeile 4 fängt 16 Positionen hinter der Zeile 2 im Speicher an
1 | #define LCD_DDADR_LINE4 0x50
|
Nur. Das kann jetzt bei dir nicht stimmen. Denn dein LCD hat ja nicht 16
Zeichen pro Zeile sondern 20.
Also werden die Zeilen 3 und 4 wohl wo anders anfangen.
Wie kriegt man das raus?
Datenblatt ist immer eine gute Idee, aber es geht auch so.
Denn: Für den Controller exstiert ja die Zeilenstruktur nicht. Der hat
einfach nur einen linearen Speicher mit 128 Bytes und was immer du
reinschreibst, kommt in die nächste Speicherposition und der 'Cursor'
wird um 1 Stelle weitergeschoben.
d.h du kannst zb etwas beginnend mit der Homeposition ausgeben. Zb das
hier
1 | ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz
|
Davon wirst du natürlich nur die ersten 20 Zeichen in der ersten Zeile
physikalisch sehen. Logisch. Mehr Zeichenpostionen gibt es dort nicht.
Aber der SPeicher existiert ja, und der wird weiter beschrieben.
1 | +---+---+---+---+---+---+- ... -+---+---+---+- .... -+---+---+---+
|
2 | | A | B | C | D | E | F | | Y | Z | a | | g | h | i |
|
3 | +---+---+---+---+---+---+- ... -+---+---+---+- .... -+---+---+---+
|
4 |
|
5 | | Zeile 1 | Zeile 3 | Zeile 2 | Zeile 4 |
|
Irgendwann wird das so in den Speicher geschriebene dann auch die
Position im Speicher erreichen, an der die Ausleselektronik das in die
2te (oder 3te oder 4te) physikalische Zeile bugsiert.
Und genau da liegt jetzt die Information für dich. Du schreibst zb das
Alfabet in den Speicher und siehst nach, welches das erste Zeichen ist,
das in der 2ten physikalischen Zeile ganz links auftaucht. Jetzt
brauchst du nur noch die Buchstaben zählen (du weisst ja, was du
ausgegeben hast) und weisst damit, wo bei dir im Speicher die 2te
physikalische Zeile anfängt. Und genau das trägst du dann bei den
#define ein.
Sinngemäss dasselbe für die Zeilen 3 und 4.
Klingt kompliziert? Ist es nicht. In 3 Minuten hast du alle Information
die du brauchst.