Forum: Mikrocontroller und Digitale Elektronik Änderung LCD Grösse in Header Datei


von Jörg D. (misterbf)


Lesenswert?

Hallo zusammen,

Ich habe gestern mein LCD Display von MyAVR endlich in Betrieb genommen 
und konnte Sache anzeigen lassen. Allerdings Habe ich mir ein Display 
gekauft mit 20x4 Zeichen. Jetzt funktioniert die Darstellung 
Grundsätzlich schon nur ist es alles verschoben. Ich tippe auf den Teil 
der lcd-Routines.h die ich hier mal rein kopiert habe.

1
 
2
////////////////////////////////////////////////////////////////////////////////
3
// Zeilendefinitionen des verwendeten LCD
4
// Die Einträge hier sollten für ein LCD mit einer Zeilenlänge von 16 Zeichen passen
5
// Bei anderen Zeilenlängen müssen diese Einträge angepasst werden
6
 
7
#define LCD_DDADR_LINE1         0x00
8
#define LCD_DDADR_LINE2         0x40
9
#define LCD_DDADR_LINE3         0x10
10
#define LCD_DDADR_LINE4         0x50

Jetzt wäre total klasse wenn mir einer mal erklären könnte wie ich was 
anpassen muss und wieso man das so adressiert. Die einfache Lösung hilft 
mir ja nicht wenns wieder mal was zum Ändern gibt und daher bin ich am 
Lösungsweg interessiert.

Vielen Dank

: Verschoben durch Moderator
von g457 (Gast)


Lesenswert?

> Jetzt wäre total klasse wenn mir einer mal erklären könnte wie ich was
> anpassen muss und wieso man das so adressiert. Die einfache Lösung hilft
> mir ja nicht wenns wieder mal was zum Ändern gibt und daher bin ich am
> Lösungsweg interessiert.

Datenplatt zum Display oder zum Treiber aufschlagen, Angaben zur 
Organisation des GRAM suchen und übertragen.

Behelfsweise(!) das Display mit einer bekannten Sequenz vollschreiben, 
und zwar reihum immer beginnen an einem (bekannten) Zeilenanfang und 
(weit) über das Zeilenende hinaus, sodass man mit dem Auftauchen des 
Überhangs in einer neuen Zeile anhand der bekannten Sequenz die Adresse 
der neuen Zeilen abzählen/berechnen kann.

von Jörg D. (misterbf)


Lesenswert?

Ok das habe ich jetzt nicht so ganz verstanden :-(

wenn ich eine Zeichenfolge von 38 Zeichen ausgeben lasse, schreibt er 
die erste Zeile voll und dann den Rest in die dritte.

Aber was sagt mir das jetzt ?

von Forum: Mikrocontroller und Digitale Elektronik (Gast)


Lesenswert?

Jörg Drösser schrieb:
> Forum: GCC
Ich weiß zwar nicht, was das mit dem GCC zu tun hat...

Jörg Drösser schrieb:
> Aber was sagt mir das jetzt ?
Noch nichts, aber wenn du noch mehr schreibst wirst du irgendwann in die 
zweite Zeile kommen und kannst dann bestimmen bei welcher Adresse die 
zweite Zeile beginnt.

von g457 (Gast)


Lesenswert?

> wenn ich eine Zeichenfolge von 38 Zeichen ausgeben lasse, schreibt er
> die erste Zeile voll und dann den Rest in die dritte.
>
> Aber was sagt mir das jetzt ?

Du weisst jetzt, dass die dritte Zeile im Speicher hinter der ersten 
liegt. Falls Zeichen fehlen ist eine entsprechend große Lücke im 
Speicher, falls nicht gehts direkt weiter. Mit dieser Information kannst 
Du den Anfang der dritten Zeile berechnen: Anfang der ersten Zeile 
+Zeichen in der ersten Zeile +Anzahl der fehlenden Zeichen.

Als nächstes wirst Du wahrscheinlich von Zeile 3 in Zeile 2 und dann von 
dort in Zeile 4 springen. Dann hast du alle Konstanten zusammen.

von Karl H. (kbuchegg)


Lesenswert?

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.

: Bearbeitet durch User
von Arduinoquäler (Gast)


Lesenswert?

Soviele verschiedene LCD Adressierungen gibt es nicht.

bei 20 x 4 dürfe es aller Erfahrung nach so sein:

#define LCD_LINE0     0x00
#define LCD_LINE1     0x40
#define LCD_LINE2     0x14
#define LCD_LINE3     0x54

von Arduinoquäler (Gast)


Lesenswert?

Arduinoquäler schrieb:
> bei 20 x 4 dürfe es aller Erfahrung nach so sein:

Begründung:

Zeile2 - Zeile0 = 20
Zeile3 - Zeile1 = 20

von Jörg D. (misterbf)


Angehängte Dateien:

Lesenswert?

Hallo Karl-Heinz,

Vielen Dank für die ausführliche Erklärung. Die habe ich verstanden und 
auch genauso durchgeführt. Dabei kam dann mit dem diesem Code
1
int main(void)
2
{
3
  // Initialisierung des LCD
4
  // Nach der Initialisierung müssen auf dem LCD vorhandene schwarze Balken
5
  // verschwunden sein
6
  lcd_init();
7
 
8
  lcd_setcursor(0, 1 );
9
 lcd_string("11111111112222222222333333333344444444445555555555666666666677777777778888888888");
10
  // Text in einzelnen Zeichen ausgeben
11
  //lcd_data( 'T' );
12
  //lcd_data( 'e' );
13
  //lcd_data( 's' );
14
  //lcd_data( 't' );
15
 /*lcd_setcursor(0, 1 );
16
 lcd_string("Hallo Test");
17
 lcd_setcursor(0, 2 );
18
 lcd_string("Hallo Test");
19
 lcd_setcursor(0, 3 );
20
 lcd_string("Hallo Test");
21
 lcd_setcursor(0, 4 );
22
 lcd_string("Hallo Test");
23
*/

Bild : "Zahlen Voll"

Mit dem Test ob die Zeilenanfänge stimmen mit folgendem
1
int main(void)
2
{
3
  // Initialisierung des LCD
4
  // Nach der Initialisierung müssen auf dem LCD vorhandene schwarze Balken
5
  // verschwunden sein
6
  lcd_init();
7
 
8
  lcd_setcursor(0, 1 );
9
 //lcd_string("11111111112222222222333333333344444444445555555555666666666677777777778888888888");
10
  // Text in einzelnen Zeichen ausgeben
11
  //lcd_data( 'T' );
12
  //lcd_data( 'e' );
13
  //lcd_data( 's' );
14
  //lcd_data( 't' );
15
 lcd_setcursor(0, 1 );
16
 lcd_string("Hallo Test");
17
 lcd_setcursor(0, 2 );
18
 lcd_string("Hallo Test");
19
 lcd_setcursor(0, 3 );
20
 lcd_string("Hallo Test");
21
 lcd_setcursor(0, 4 );
22
 lcd_string("Hallo Test");

Kam das dabei raus

Bild : "Hallo"


Frage ist jetzt was mit der Vierten Zeile Passiert ist.

Meine Adresse sind gezählter weise
1
#define LCD_DDADR_LINE1         0x00
2
#define LCD_DDADR_LINE2         0x28
3
#define LCD_DDADR_LINE3         0x14
4
#define LCD_DDADR_LINE4         0x3C

hoffe jemand hat den Durchblick

von Karl H. (kbuchegg)


Lesenswert?

Jörg Drösser schrieb:

> #define LCD_DDADR_LINE2         0x28

Ist ungewöhnlich.
Probier mal, ob du bei 0x40 die Zeile 2 noch ein zweites mal liegen 
hast.
Das wär eigentlich der Normalfall

Hintergrund:
manchmal ist der Speicher doch nicht so ganz durchgängig vorhanden, wie 
man sich das naiv gesehen so vorstelle :-)

Wenn Zeile 2 wirklich bei 0x40 liegt, dann wäre Zeile 4 aus 
Symetriegründen wahrscheinlich bei 0x54, wie Arduinoquäler schon 
ausgeführt hat.

von Jörg D. (misterbf)


Lesenswert?

Ja ok,

wie Arduinoquäler es geschrieben hat passt es und klappt auch, aber 
wieso das jetzt Passt weiss ich leider noch nicht. Weil die Erklkärung 
von eben ja nun nicht auf den Code passt.
Im Datenblatt habe ich diesbezüglich nix gefunden ist ein 2004A 
Controller drauf.

von Karl H. (kbuchegg)


Lesenswert?

Jörg Drösser schrieb:
> Ja ok,
>
> wie Arduinoquäler es geschrieben hat passt es und klappt auch, aber
> wieso das jetzt Passt weiss ich leider noch nicht. Weil die Erklkärung
> von eben ja nun nicht auf den Code passt.

Sie passt immer noch.
Wenn du beginnend bei 0x40 deine Testzeichenkette fortlaufend ausgibst, 
dann würdest du die 4.te Zeile genauso wieder durch abzählen eruieren 
können.


Das beim ersten Test die 4. physikalische Zeile Zeichen aufwies, obwohl 
dort eigentlich nichts sein sollte, liesse sicherlich durch die interne 
Controllerbeschaltung erklären, wenn man die kennen würde. Irgendwo wird 
da wohl in der Adressdekodierung ein falscher Speicher angesprochen an 
einer Stelle an der am LCD überhaupt nichts sichtbar ist. Sowas kommt 
vor und hat es immer schon gegeben, wenn die Entwickler (nicht nur von 
LCD) bei der Adressdekodierung gespart haben.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.