LCD 4x20 2004A auf Zeilen schalten

OP #6104453
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.
#6104592
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
Angehängte Dateien:
#6104673
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!
OP #6104750
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.
Gast #6104780
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.
#6104986
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
Angehängte Dateien:
#6105121
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
#6105329
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.
#6105369
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.
#6107124
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.
OP #6121392
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
Angehängte Dateien:
#6121433
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.
Gast #6121918
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.
Gast #6122591
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.
Gast #6122609
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!?
Gast #6122613
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.
Gast #6122623
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.
#6122625
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
Gast #6122660
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.
Gast #6122670
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
}
OP #6122695
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
Gast #6122708
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.
Gast #6122752
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
}

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren