Forum: Mikrocontroller und Digitale Elektronik LCD 4x20 2004A auf Zeilen schalten


von Heinz W. (bibermann)


Lesenswert?

Hallo Forum,
habe das Forum abgescannt und viele Vorschläge getestet, aber leider 
nicht erfolgreich. Nutze Atmel Studio 7.0, die LCD und I2C Haeder- und 
C-Dateien von Peter Fleury mit einem Atmega 328P mit 16 MHz. Habe bisher 
ein 2x16 Display genutzt. Alles funktioniert einwandfrei. Habe mir jetzt 
mehrer 4x20 Displays gekauft. In den Headerdateien die defines auf 4 
Zeilen und 20 Spalten und die Zeilenadressen angepasst. Funktioniert 
bedingt, die Zeilendarstellung bekomme ich nicht hin. Mir ist bekannt, 
das die Zeile 1 in Zeile 3, respektive Zeile 2 in Zeile 4 fortgesetzt 
wird. Das funktioniert auch einwandfrei. Ich möchte aber nach einem 
"lcd_print nextline()" eine neue Zeile nutzen. Nach Zeile 1 klappt es, 
da die Zeilenadresse für Zeile 2 0x40 wohl übernommen wir. Habe mehrer 
Vorschläge für die Zeilen wie z.B. 0x00, 0x40, 0x14, 0x54 getestet. 
lcd_print nextline wird ab Zeile 2 nicht angenommen.
Ich habe im Datenblatt des 2004A gesehen, dass als LCD Controller ein 
ST7066U verbaut ist. Ist u.U dieser Baustein nicht kompatibel mit HD 
44870 etc.

von Max D. (max_d)


Lesenswert?

Das LCD enthält einfach nur einen großen Buffer in den dies strings (als 
ASCII) reingschrieben werden. Das nextline macht deine library im 
hintergrund.
Solange wir die nicht kennen ist alles nutzlos....

von Karl B. (gustav)


Angehängte Dateien:

Lesenswert?

Heinz W. schrieb:
> Ich habe im Datenblatt des 2004A gesehen, dass als LCD Controller ein
> ST7066U verbaut ist. Ist u.U dieser Baustein nicht kompatibel mit HD
> 44870 etc.

Hi,
habe 2 x 16 LCDs mit KS0066U-(ST7066)
selber getestet.
Kein Unterschied.
Was vielleicht etwas anders sein kann, sind die
Befehlsausführungszeiten und die Pausen zwischen den
einzelnen Schritten gerade bei der Initialisierung.

Und wenn es ein 40-er sein sollte, der zwei Controller hätte,
dann müsstest Du auch 2  Enable Anschlüsse haben.
Und entsprechend 2x Enableimpuls senden (jeweils einen auf den 
jeweiligen Pin.)
Ist aber wohl nicht so.

Wie sieht deine Befehlsfolge zu "locate" aus?
Bei mir:
Schnipsel in ASM.
Wobei zwei Routinen drin sind.
Einmal Befehl auf LCD
dann Charakter auf LCD

Die kennst Du bestimmt schon, brauche ich hier nicht ausführen.

Die Anfangsadressen findest Du doch durch Addition raus.
Schau Dir das Dabla für die Funktionsaufrufe einmal daraufhin an.

ciao
gustav

: Bearbeitet durch User
von Axel S. (a-za-z0-9)


Lesenswert?

Heinz W. schrieb:
> Habe mir jetzt
> mehrer 4x20 Displays gekauft. In den Headerdateien die defines auf 4
> Zeilen und 20 Spalten und die Zeilenadressen angepasst.

Das reicht u.U. nicht. Welche Library ist es denn? Es gibt ja nur ca. 
hundert verschiedene ...

> Funktioniert bedingt, die Zeilendarstellung bekomme ich nicht hin.

Großartige Fehlerbeschreibung!

> Mir ist bekannt,
> das die Zeile 1 in Zeile 3, respektive Zeile 2 in Zeile 4 fortgesetzt
> wird. Das funktioniert auch einwandfrei. Ich möchte aber nach einem
> "lcd_print nextline()" eine neue Zeile nutzen.

Ja, dann machs halt. Der Code für die Behandlung des NEWLINE Zeichens 
muß die aktuelle Zeile anschauen und basierend darauf die 
Schreibposition und die (neue) aktuelle Zeile setzen. Für ein 4-Zeilen 
Display brauchst du also eine Kette aus 4 if() Statements. Irgendwo da 
hast du einen Fehler drin. Zeig den Code!

von Heinz W. (bibermann)


Lesenswert?

Den Antworten zu urteilen habe ich nicht hinreichend klar formuliert.
Grundsätzlich ist die Funktion gegeben. Habe diese kurze Routine:
i2c_init();
  lcd_init();
  DDRB  = 0xFF;
  PORTB  = (1<<PB1);
  _delay_ms(100);
  lcd_command(LCD_DISPLAYON);
  _delay_ms(1000);
  lcd_command(LCD_CLEAR);
  _delay_ms(2);
  lcd_light(1);
  lcd_command(LCD_HOME);
  lcd_print("Zeile 1:XXXXXXXXXXXX");
  lcd_nextline();
  lcd_print("Zeile 2:yyyyyyyyyyyy");
  lcd_nextline();
  lcd_print("Zeile 3:ZZZZZZZZZZZZ");
  lcd_nextline();
  lcd_print("Zeile 4:UUUUUUUUUUUU");

Ergebnis:

Display Zeile 1:Zeile 1:XXXXXXXXXXXX
Display Zeile 2:Zeile 4:UUUUUUUUUUUU
Display Zeile 3:
Display Zeile 4:Zeile 3:ZZZZZZZZZZZZ


Display Konfiguration in i2clcd.h

#define LCD_I2C_DEVICE  0x4E
#define LCD_LINES      4
#define LCD_COLS      20
#define LCD_LINE_MODE   LCD_4LINE

#define LCD_LINE1      0x00
#define LCD_LINE2      0x40
#define LCD_LINE3      0x15
#define LCD_LINE4      0x54

Danke für einen Tipp.

von Max D. (max_d)


Lesenswert?

hast du den thread gelesen ?

WAS FÜR EINE LIBRARY VERWENDEST DU ?

es gibt ja nicht nur eine i2clcd.h auf diesem Planten....

von Guest (Gast)


Lesenswert?

Hat er doch geschrieben, die Peter Fleury library hier aus dem Forum.

von Display Displayer (Gast)


Lesenswert?

Versuche mal

#define LCD_LINE1      0x00
#define LCD_LINE2      0x38
#define LCD_LINE3      0x14
#define LCD_LINE4      0x54

oder

#define LCD_LINE1      0x00
#define LCD_LINE2      0x38
#define LCD_LINE3      0x28
#define LCD_LINE4      0x48

Das sind Werte die ich früher bei 20x4 Displays verwendet hatte.

von Karl B. (gustav)


Angehängte Dateien:

Lesenswert?

Bei mir sehen die Adressen anders aus:
Siehe Bild.
Ist I2C über USI Krücke.
Funktioniert aber.
Ob das I2C ist oder sonstwas, (über den PIC Adapter):
die Startadressen sind LCD-spezifisch.

https://bin-dez-hex-umrechner.de/

Max D. schrieb:
> Das LCD enthält einfach nur einen großen Buffer in den die strings (als
> ASCII) reingeschrieben werden.

Immer alternierend addieren:
in Dezimal:
128
192
148
212

Wieso das so ist, liegt am Displaycontroller.
Frag mich nicht, der Hersteller hat sich da was gedacht.
Vermutung:
Es werden für verschiedene "Längen" eben dieselben Controller verwendet.
Und da gibt es eben "Lücken", weil nicht alles was adressierbar wäre, 
auch angezeigt werden kann.
Z.B. bei einem 2 x 16 die restlichen 4 Stellen fehlen.
Dafür gibt es aber keine "Extrawurst".

ciao
gustav

: Bearbeitet durch User
von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

Karl B. schrieb:
> Frag mich nicht, der Hersteller hat sich da was gedacht.

Das liegt unter anderem daran, das es einen Expanderchip für den alten 
HD44780 gibt, den HD44100. Der hängt als Unterling am 44780 und füllt 
die fehlenden Speicheradressen. (Gut, es ist ein wenig komplizierter, 
aber das Prinzip ist so).

von Georg G. (df2au)


Lesenswert?

Du hast doch fast alle notwendigen Werte schon gefunden...

Heinz W. schrieb:
> Ergebnis:
>
> Display Zeile 1:Zeile 1:XXXXXXXXXXXX
> Display Zeile 2:Zeile 4:UUUUUUUUUUUU
> Display Zeile 3:
> Display Zeile 4:Zeile 3:ZZZZZZZZZZZZ
>
> Display Konfiguration in i2clcd.h
>
> #define LCD_I2C_DEVICE  0x4E
> #define LCD_LINES      4
> #define LCD_COLS      20
> #define LCD_LINE_MODE   LCD_4LINE
>
> #define LCD_LINE1      0x00
> #define LCD_LINE2      0x40
> #define LCD_LINE3      0x15
> #define LCD_LINE4      0x54

Zeile 1 erscheint mit richtigem Inhalt an der gewünschten Position.
Also ist #define LCD_LINE1  0x00 richtig.

In Zeile 2 erscheint der Inhalt für Zeile 4.
Also änderst du LCD_LINE4 von 0x54 auf 0x40.

In Zeile 4 kommt der Inhalt für Zeile 3.
Also wird LCD_LINE3 zu 0x54.

Fehlt noch die Zeile 2. 0x15 ist mit Sicherheit falsch. Sinnvoller wäre 
0x14 (20 Zeichen Versatz). Macht als Tabelle:

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

von Axel S. (a-za-z0-9)


Lesenswert?

Heinz W. schrieb:
> lcd_command(LCD_HOME);
>   lcd_print("Zeile 1:XXXXXXXXXXXX");
>   lcd_nextline();
>   lcd_print("Zeile 2:yyyyyyyyyyyy");
>   lcd_nextline();
>   lcd_print("Zeile 3:ZZZZZZZZZZZZ");
>   lcd_nextline();
>   lcd_print("Zeile 4:UUUUUUUUUUUU");

Das halte ich generell für grenzwertig. Die (uralte) Fleury-Lib die ich 
hier in einem Projekt verwende, hat ein Konfigurationsflag 
LCD_WRAP_LINES (defaultmäßig aktiv) und schaltet am Ende einer Zeile 
automatisch auf die nächste Zeile. Da du oben immer 20 Zeichen ausgibst, 
wären in diesem Fall die Aufrufe von lcd_nextline() komplett unnötig.

Und ganz generell würde ich da eher lcd_gotoxy() verwenden.


> Display Konfiguration in i2clcd.h
>
> #define LCD_LINE1      0x00
> #define LCD_LINE2      0x40
> #define LCD_LINE3      0x15
> #define LCD_LINE4      0x54

Wenn du nicht gerade ein ganz und gar exotisches Display hast, dann 
müßte das so aussehen:

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

Wenn ich bei einem Display nicht sicher bin, dann fülle ich einfach mal 
das Display-RAM mit dem ASCII (oder was das Display dafür hält) 
Zeichensatz. In einer Schleife mit ein paar 100ms Pause nach jedem 
Zeichen. Da sieht man dann sehr gut, welche Zeile welcher Adresse 
entspricht.

von Joachim B. (jar)


Lesenswert?

Max D. schrieb:
> Das nextline macht deine library im
> hintergrund.
> Solange wir die nicht kennen ist alles nutzlos....
Axel S. schrieb:
> Das reicht u.U. nicht. Welche Library ist es denn? Es gibt ja nur ca.
> hundert verschiedene ...

?

Heinz W. schrieb:
> die LCD und I2C Haeder- und
> C-Dateien von Peter Fleury mit einem Atmega

ich zeige sie euch, muss schwer sein ;)
http://www.peterfleury.epizy.com/avr-software.html

Axel S. schrieb:
> Wenn ich bei einem Display nicht sicher bin, dann fülle ich einfach mal
> das Display-RAM mit dem ASCII (oder was das Display dafür hält)
> Zeichensatz. In einer Schleife mit ein paar 100ms Pause nach jedem
> Zeichen. Da sieht man dann sehr gut, welche Zeile welcher Adresse
> entspricht.

genauso, oder in die LIB schauen und passend machen, sehe da auch keine 
Probleme.
Habe mit der Fleury LIB auch angefangen, sehr gut zu verwenden unter AVR 
oder Arduino(Atmel AVR) wer keine anderen findet.

von Karl B. (gustav)


Lesenswert?

Heinz W. schrieb:
> Habe mir jetzt
> mehrer 4x20 Displays gekauft.

Hi,
gibt es dazu Datenblätter?

http://www.sprut.de/electronic/lcd/

ciao
gustav

von Bernhard S. (b_spitzer)


Lesenswert?

Schreibe doch einfach alle Buchstaben von A-Z und von a-z ab der 
DD-RAM-Adresse 0 aufs Display. Dann kannst Du einfach ausrechnen, wo die 
weiteren Zeilen beginnen. Wenn Du dann noch nichts in einer Zeile 
siehst, setzte voher den Cursor auf 0x20, 0x30 oder 0x40 und probiere es 
noch mal.

In dem Datenblatt für ein 4x20 display ist die Rede von einem "1-line 
mode" mit linearen Adressen von 0x00-0x4F (0-79), sowie ein "2-line 
mode" mit Adressen von 0x00-0x27 Zeile 1 (und vermutlich nahtloser 
Übergang in Zeile 3) und 0x40-0x67 für Zeile 2 (weiter in 4).
https://www.beta-estore.com/download/rk/RK-10290_410.pdf

Was bei diesen Speicherorganisationen dann nicht geht ist scrollen des 
Display-Inhaltes.

Edit: nicht CG-RAM sondern DD-RAM Adresse. CG ist der Speicher zum 
definieren eigener Sonderzeichen.

: Bearbeitet durch User
von Karl B. (gustav)


Lesenswert?

Hi,
ist der Unterschied von 2004 zu 2004A
so groß?
Oben sind die Anfangs-Adressen des SainSmart2004
schon einmal angegeben worden.
Beitrag "Re: LCD 4x20 2004A auf Zeilen schalten"
Könnte man doch einmal ausprobieren, oder?

ciao
gustav

von Heinz W. (bibermann)


Angehängte Dateien:

Lesenswert?

Hallo Forum -- ich bin schon fast verzweifelt--
habe in der Zwischenzeit alle?? Vorschläge zur 4 Zeilen Darstellung auf 
dem Display 2004A mit I2C Interface (LCD und I2C Haeder- und
C-Dateien von Peter Fleury) ausprobiert. Leider funktioniert es nicht.
Habe ein weiteres Display nach dem AVR-GCC-Tutorial/LCD-Ansteuerung 
vorbereitet und siehe da, alles funktioniert wunschgemäß.
Bei der I2C Anbindung und der 4 Zeilen Konfiguration erhalte ich bei 
folgender Sequenz:

        lcd_gotolc(1,5);
  lcd_print("12345");
  lcd_gotolc(1,30);
  lcd_print("ABCD");
  lcd_gotolc(2,8);
  lcd_print("56789");
  lcd_gotolc(2,85);
  lcd_print("EFG");

Das im Bild dargestelle Ergebnis. Die Zeilenadressen habe ich die aus 
dem Programm s.o. übernommen. Bei erhärtet sich der Eindruck, dass durch 
i2clcd.c der gewünschte Modus vom Display nicht umgeschaltet wird. Für 
einen Tipp oder erprobte Routine wäre ich dankbar.

MfG
Heinz

von Georg G. (df2au)


Lesenswert?

Bitte probier das folgende Programm aus und zeige uns die Ausgabe:
(ich kenne nicht den Namen deiner Funktion, die nur ein Zeichen ausgibt, 
ich nenne sie mal lcd_lcd_char)

char i;

lcd_initialisieren(); (heisst bei dir bestimmt anders)

lcd_gotolc(1,1);
for (i = 0x21; i < 0x72; i++) {
lcd_lcd_char(i);
}

Das sollte dir das gesamte Display voll schreiben.

von Pieter (Gast)


Lesenswert?

lcd_gotolc(1,5);
  lcd_print("12345");

Die nächste Schreibposition ist 10.

  lcd_gotolc(1,30);

In Zeile1 gibt es keine Pos.30! Die Funktion wird nix tun.

  lcd_print("ABCD");

Hier wird nun ab Pos10 weitergeschrieben.

Ändere die 30 auf 18.

von norad (Gast)


Lesenswert?

Vllt. das hier mal ausprobieren!

#define LCD_LINE1      0x00
#define LCD_LINE2      0x20
#define LCD_LINE3      0x40
#define LCD_LINE4      0x60

Sind zwar Adressen  für einen KS0073 aber mal probieren.

Schau bitte auch mal ins Datenblatt ob ein sog.
Erweiterungs Bit RE, für Sonderfunktionen (Function Set)setzen musst zum
Umschalten in den 4 Bit Modus.

von BlaBla (Gast)


Lesenswert?

Ich hatte vor kurzem auch ein Problem mit der LCD-Library von Peter 
Fleury bei 16 MHz. Ich vermute ein Timing-Problem mit der internen 
delay-Funktion. Ich meine, etwas in der Library von 4 Mhz gelesen zu 
haben. Eventuell liegt hier die Herausforderung!?

von BlaBla (Gast)


Lesenswert?

Das meine ich:

[c]
/*********************************************************************** 
**
delay for a minimum of <us> microseconds
with a 4Mhz crystal, the resolution is 1 us
************************************************************************ 
*/
static void delay(uint16_t us)
{
    while ( us ) us--;
}
[-c]

Bei 16 MHz sind das dann keine 1µs Wartezeit.

von BlaBla (Gast)


Lesenswert?

Das meinte ich:
1
/************************************************************************* 
2
delay for a minimum of <us> microseconds
3
with a 4Mhz crystal, the resolution is 1 us
4
*************************************************************************/
5
static void delay(uint16_t us) 
6
{
7
    while ( us ) us--;
8
}

Bei 16 MHz ist das dann keine 1µs Wartezeit.

von Hugo H. (hugohurtig1)


Lesenswert?

Als "Kopiervorlage":
1
#define F_CPU 16000000UL  (falls nicht im Projekt eingetragen)
2
3
#define LCD_LINES           4     
4
#define LCD_DISP_LENGTH    20     
5
#define LCD_LINE_LENGTH  0x40     
6
#define LCD_START_LINE1  0x00     
7
#define LCD_START_LINE2  0x40     
8
#define LCD_START_LINE3  0x14     
9
#define LCD_START_LINE4  0x54     
10
#define LCD_WRAP_LINES      0

von BlaBla (Gast)


Lesenswert?

Hugo H. schrieb:
> #define F_CPU 16000000UL  (falls nicht im Projekt eingetragen)

Das hilft aber nicht der internen delay-Funktion. Die wird nicht von 
dieser Einstellung korrigiert. In meinem Projekt reagierte das Display 
bei Clear, Home und GotoXY seltsam.

von BlaBla (Gast)


Lesenswert?

BlaBla schrieb:
> Das meinte ich:
> /*********************************************************************** **
> delay for a minimum of <us> microseconds
> with a 4Mhz crystal, the resolution is 1 us
> ************************************************************************ */
> static void delay(uint16_t us)
> {
>     while ( us ) us--;
> }
>
> Bei 16 MHz ist das dann keine 1µs Wartezeit.

Und die Funktion wird auch noch im AS7 (-O1) weg optimiert.

von BlaBla (Gast)


Lesenswert?

1
/************************************************************************* 
2
delay for a minimum of <us> microseconds
3
with a 4Mhz crystal, the resolution is 1 us
4
*************************************************************************/
5
__attribute__((optimize(0)))
6
static void delay(uint16_t us) 
7
{
8
    while ( us ) us--;
9
}

Damit bleibt sie auch bei der Optimierung (-O1) im Code erhalten.
1
/************************************************************************* 
2
delay for a minimum of <us> microseconds
3
with a 16Mhz crystal, the resolution is 1 us
4
*************************************************************************/
5
__attribute__((optimize(0)))
6
static void delay(uint16_t us) 
7
{
8
    while ( us ) us--;
9
    while ( us ) us--;
10
    while ( us ) us--;
11
    while ( us ) us--;
12
}

von Georg G. (df2au)


Lesenswert?

BlaBla schrieb:
> static void delay(uint16_t us)
> {
>     while ( us ) us--;
>     while ( us ) us--;
>     while ( us ) us--;
>     while ( us ) us--;
> }

Möchtest du das bitte noch einmal überlegen?

Hinweis: Welchen Wert hat us nach dem ersten while?

: Bearbeitet durch User
von BlaBla (Gast)


Lesenswert?

Georg G. schrieb:
> Möchtest du das bitte noch einmal überlegen?

Oh ja.... stimmt. Krasser Fehler. Aber ist sinngemäß gemeint.

von Heinz W. (bibermann)


Lesenswert?

Hallo und guten Tag,

habe mein Problem  gelöst. Das Display 2004A funktioniert mit dem I2C 
Modul
jetzt einwandfrei. Ich denke der Compiler hat mir die Sorgen bereitet. 
Habe die Optimierung in AS 7.0 auf "Optimize for size (-Os) gestellt. 
Konnte allerdings noch nicht ermitteln was wegoptmiert wurde. Betreibe 
den Atmega 328P nach wie vor mit 16 MHz und die I2C Schnittselle mit 1 
kHz. Meine
Zeilenadessen sind 0x00, 0x40, 0x14 und 0x54.
Ich bedanke mich für alle Beiträge zur Lösung meiner Problematik. Da ich 
schon etwas älter bin (Jahrgang 1943) und keine externe Hilfe habe, muss 
ich mir Unterstützung in den Foren suchen. Ist wieder einmal sehr gut 
gelungen.
Danke!!
MfG
Heinz

von BlaBla (Gast)


Lesenswert?

Dann geht es eventuell so:
1
/************************************************************************* 
2
delay for a minimum of <us> microseconds
3
with a 16Mhz crystal, the resolution is 1 us
4
*************************************************************************/
5
6
__attribute__((optimize(0)))
7
static void delay(uint16_t us) 
8
{
9
    while ( (uint32_t) us << 2 ) us--;
10
11
}

Ob jetzt noch die 1 µs stimmen?!? War jetzt mal quick & dirty.

Heinz W. schrieb:
> habe mein Problem  gelöst.

Den Optimierer auszuschalten ist trotzdem blöd. Der wird von 
<util/delay.h> benötigt. Ich wollte jetzt auch nicht zuviel in Peters 
Lib ändern. Aber schön das es läuft.

von leo (Gast)


Lesenswert?

BlaBla schrieb:
> while ( (uint32_t) us << 2 ) us--;

Wie oft glaubst du, wird das Leftshift ausgefuehrt?

Argl - Kresse halten und so ...
leo

von BlaBla (Gast)


Lesenswert?

1
/************************************************************************* 
2
delay for a minimum of <us> microseconds
3
with a 16Mhz crystal, the resolution is 1 us
4
*************************************************************************/
5
__attribute__((optimize(0)))
6
static void delay(uint16_t us) 
7
{
8
  uint32_t us1 = us << 2;
9
    while (us1) us1--;
10
}

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.