Forum: Mikrocontroller und Digitale Elektronik LCD EA W204B-NLW


von Kurt W. (surfer2000at)


Angehängte Dateien:

Lesenswert?

Hallo Allseits !

Wie schon in meiner ersten Anfrage "Was brauche ich ?" angekündigt, bin 
absoluter Neuling auf dem Gebiet der µC und kann auch nicht wirklich 
programmieren. Trotzdem werde ich versuchen, mein geplantes Projekt mit 
einem ATmega8 zu realisieren.

Gleich eines vorweg: Bitte keine Kommentare wie "Dann musst du halt C 
lernen" oder sonstige nicht zielführende Aussagen.

Als erste Etappe habe ich mir das Display vorgenommen. Es handelt sich 
dabei um ein W204B-NLW von Electronic Assembly. Der Controller auf dem 
Ding ist ein KS0073, angeblich HD44780 kompatibel, was nicht ganz 
stimmt. Durch das Lesen etlicher Beiträge hier im Forum habe ich das 
Display auch zum Laufen gebracht.

An dieser Stelle besonderen Dank an Bitkracherl, Karl Heinz und 
besonders an die Verfasser des AVR-GCC-Tutorial/LCD-Ansteuerung sowie an 
zahlreiche Andere, welche zu diesem Thema hier etwas Sinnvolles 
beigesteuert haben.

Die Zeilendfinition in der lcd-routines.h in Zeile 52 bis 55 habe ich 
aus den Original-Datenblatt von EA für dieses Display mit dem KS0073 
entnommen.

Wie gesagt, das Display läuft und es zeigt auch das Richtige an der 
richtigen Stelle an.    Nur, ich habe keine Ahnung, warum es das tut !!!

Der Grund dafür liegt vermutlich in den Dateien lcd-routines.h (Zeile 
131 bis Zeile 139 - ist dort #define LCD_FUNCTION_3LINE bzw. #define 
LCD_FUNCTION_4LINE wirklich unnötig ???) sowie in der main.c (Zeile 23 
bis Zeile 40 - lcd_setcursor ....)

Irgendwie kann ich die Werte bei lcd_setcursor( 0, 0 ); verändern, OHNE 
dass sich dabei nachher die Anzeige verändert, z.b bei der zweiten (!!! 
Zeile 33 !!!) und vierten (!!! Zeile 38 !!!) Zeile auf lcd_setcursor( 0, 
14 ); oder auch auf lcd_setcursor( 0, 15 ); ohne das sich die Anzeige am 
Display ändert, es kommt immer das gleiche Ergebnis:
1
zeile 1:   111 erste  zeile 111
2
zeile 2:   222 zweite zeile 222
3
zeile 3:   333 dritte zeile 333
4
zeile 4:   444 vierte zeile 444
Ämdere ich besagte Zeilen allerdings auf lcd_setcursor( 0, 1 ); so kommt 
folgendes raus:
1
zeile 1:   444 vierte zeile 444
2
zeile 2:
3
zeile 3:   333 dritte zeile 333
4
zeile 4:
Im Übrigen ist mir aufgefallen, dass wenn ich die Reihenfolge der 
Programmzeilen vertausche, sich auch die Anzeige am Display ändert:
1
  // Die Ausgabemarke in die 1te Zeile setzen
2
  lcd_setcursor( 0, 0 );
3
  // Text als String ausgeben
4
  lcd_string("111 erste  zeile 111");
5
6
  // Die Ausgabemarke in die 3te Zeile setzen
7
  lcd_setcursor( 0, 0 );
8
  // Text als String ausgeben
9
  lcd_string("333 dritte zeile 333");
10
11
  // Die Ausgabemarke in die 2te Zeile setzen
12
  lcd_setcursor( 0, 0 );
13
  // Text als String ausgeben
14
  lcd_string("222 zweite zeile 222");
15
 
16
  // Die Ausgabemarke in die 4te Zeile setzen
17
  lcd_setcursor( 0, 0 );
18
  // Text als String ausgeben
19
  lcd_string("444 vierte zeile 444");
ergibt
1
zeile 1:   111 erste  zeile 111
2
zeile 2:   222 zweite zeile 222
3
zeile 3:   333 dritte zeile 333
4
zeile 4:   444 vierte zeile 444
aber
1
  // Die Ausgabemarke in die 1te Zeile setzen
2
  lcd_setcursor( 0, 0 );
3
  // Text als String ausgeben
4
  lcd_string("111 erste  zeile 111");
5
6
  // Die Ausgabemarke in die 2te Zeile setzen
7
  lcd_setcursor( 0, 0 );
8
  // Text als String ausgeben
9
  lcd_string("222 zweite zeile 222");
10
 
11
  // Die Ausgabemarke in die 3te Zeile setzen
12
  lcd_setcursor( 0, 0 );
13
  // Text als String ausgeben
14
  lcd_string("333 dritte zeile 333");
15
16
  // Die Ausgabemarke in die 4te Zeile setzen
17
  lcd_setcursor( 0, 0 );
18
  // Text als String ausgeben
19
  lcd_string("444 vierte zeile 444");
ergibt
1
zeile 1:   111 erste  zeile 111
2
zeile 2:   333 dritte zeile 333
3
zeile 3:   222 zweite zeile 222
4
zeile 4:   444 vierte zeile 444

Könnte mir das bitte wer erklären? An welcher Stelle werden die 
"Einsprungsaddressen" nun wirklich definiert und wie weit ist das für 
lcd_setcursor auch bindend bzw. inwieweit hängen die #define 
LCD_FUNCTION_1LINE (bzw ..1-4LINE) mit den lcd_setcursor zusammen?

Bitte so erklären, dass es auch ein Laie wie ich verstehen kann.

: Bearbeitet durch User
von spess53 (Gast)


Lesenswert?

Hi

Wie jetzt, vier mal die gleiche Cursorposition und unterschiedliche 
Zeilen?

>Könnte mir das bitte wer erklären? An welcher Stelle werden die
>"Einsprungsaddressen" nun wirklich definiert und wie weit ist das für
>lcd_setcursor auch bindend bzw. inwieweit hängen die #define
>LCD_FUNCTION_1LINE (bzw ..1-4LINE) mit den lcd_setcursor zusammen?

Die Anfangsadressen der Zeilen sind in der lcd-routines.h definiert:

#define LCD_DDADR_LINE1         0x00  // Werte aus Datenblatt für
#define LCD_DDADR_LINE2         0x20  // LCD Display 4 x 20 mit
#define LCD_DDADR_LINE3         0x40  // Kontroller KS0073
#define LCD_DDADR_LINE4         0x60

>Gleich eines vorweg: Bitte keine Kommentare wie Gleich eines vorweg: Bitte >keine 
Kommentare wie "Dann musst du halt C lernen" oder sonstige nicht >zielführende 
Aussagen. oder sonstige nicht zielführende Aussagen.

"Dann musst du halt C lernen" ist aber zielführend (auch wenn ich 
notorischer Assemblerprogrammierer bin). Man muss sein Werkzeug 
beherrschen. Egal welches. Denn dann sind solche Threads unnötig.

MfG Spess

von Kurt W. (surfer2000at)


Lesenswert?

Jep, viermal die gleiche Cursorposition und unterschiedliche Zeilen, 
welche das Richtige anzeigen .... und genau das verstehe ich nicht !

Zu
>Die Anfangsadressen der Zeilen sind in der lcd-routines.h definiert:
diese Werte habe ich lt. Datenblatt für das 4x20 Display eingegeben

Aber bitte lies nochmal meine Frage, ich verstehe das Verhalten des 
Displays nicht, dass es bei verschiedenen Angeben bei lcd_setcursor 
gleich reagiert.

von spess53 (Gast)


Lesenswert?

Hi

>Aber bitte lies nochmal meine Frage, ich verstehe das Verhalten des
>Displays nicht, dass es bei verschiedenen Angeben bei lcd_setcursor
>gleich reagiert.

Vielleicht programmierst du nur einfach das falsche Hex-File.

MfG Spess

von Kurt W. (surfer2000at)


Lesenswert?

>Vielleicht programmierst du nur einfach das falsche Hex-File.

Nö, diesen Fehler habe ich ganz am Anfang vor einer Woche zweimal 
gemacht, seither passe ich darauf auf.

Ich habe nur einige der möglichen Werte für lcd_setcursor angegeben, bei 
denen das Display das Richtige anzeigt.  Bei anderen Werten werden die 
Zeilen erwartungsgemäß verschoben oder durcheinandergewürfelt. Im 
Endeffekt soll es ja nicht bei diesen Versuchs-Anzeigen bleiben, sondern 
es sollen dann verschiedene Menüpunkte sowie diverse Start- und 
Stopzeiten, eine Uhr usw. angezeigt werden. Und deshalb möchte ich schon 
genau wissen, was wann warum wo angezeigt wird.

Morgen werde ich nochmals einige Werte versuchen und die Ergebnisse dann 
hier posten, vielleicht weiß wer einen Rat oder den Grund, warum dies so 
ist.

mfg Kurt

: Bearbeitet durch User
von Klaus (Gast)


Lesenswert?

@Kurt W.

Das Verhalten könnte daher kommen, dass das sogenannte RE-Bit nicht 
gesetzt wird bei der Initialisierung.

HÄÄÄ was ist das RE-Bit?

Das ist, das Erweiterungs-Bit, laut Datenblatt damit es HD44780 
kompatible wird.

Im Datenblatt ist es etwas irreführend beschrieben und habe dann damals
beim Hersteller nachgefragt.

von Klaus (Gast)


Angehängte Dateien:

Lesenswert?

@Kurt W.

Das Initalisierungs Beispiel aus dem Datenblatt muss noch
für den 4-Bit Modus angepasst werden. (siehe Anhang)

Wichtig ist hierbei, dass das RE-Bit wieder zurückgesetzt wird
nachdem "8-Bit Datenlänge, extension Bit RE und 4 Zeilen Modus"
eingestellt wurde.

von Karl H. (kbuchegg)


Lesenswert?

Kurt W. schrieb:
> Jep, viermal die gleiche Cursorposition und unterschiedliche Zeilen,
> welche das Richtige anzeigen .... und genau das verstehe ich nicht !


Ich schon.

Schau ich mir die Funktion an
1
void lcd_setcursor( uint8_t x, uint8_t y )
2
{
3
    uint8_t data;
4
 
5
    switch (y)
6
    {
7
        case 1:    // 1. Zeile
8
            data = LCD_SET_DDADR + LCD_DDADR_LINE1 + x;
9
            break;
10
 
11
        case 2:    // 2. Zeile
12
            data = LCD_SET_DDADR + LCD_DDADR_LINE2 + x;
13
            break;
14
 
15
        case 3:    // 3. Zeile
16
            data = LCD_SET_DDADR + LCD_DDADR_LINE3 + x;
17
            break;
18
 
19
        case 4:    // 4. Zeile
20
            data = LCD_SET_DDADR + LCD_DDADR_LINE4 + x;
21
            break;
22
 
23
        default:
24
            return;                         // für den Fall einer falschen Zeile
25
    }
26
 
27
    lcd_command( data );
28
}

und vergleiche mit deinem Aufruf
1
  lcd_setcursor( 0, 0 );
dann sehe ich, dass der Fall 0 für das 2.te Argument gar nicht behandelt 
wird. D.h. dein lcd_setcursor macht effektiv gar nichts. Und dieses 'gar 
nichts' ist wörtlich zu nehmen.

Hast du selbst da in der lcd_setcursor Funktion rumgepfuscht? Denn als 
C-Programmierer ist man eigentlich daran gewöhnt, dass wir IMMER bei 0 
anfangen zu zählen und nicht bei 1. Die oberste Zeile in einem LCD ist 
nun mal die Zeile Nummer 0 und nicht die Zeile Nummer 1. So wie du das 
zwar an der verwendenden Stelle auch gemacht hast, allerdings in der 
Funktion dann anders auswertest.

Und der Rest deiner Ausgaben erklärt sich ganz einfach aus der internen 
Organisation des LCD, in der die Zeilen eben physikalisch anders 
angeordnet sind, als du das annimmst.

: Bearbeitet durch User
von Karl H. (kbuchegg)


Lesenswert?

PS:

Muss die Sache mit dem "herumpfuschen" zurück nehmen. Denn im Original 
sieht der Code auch so aus (auch wenn mir nicht klar ist, was sich der 
Autor dabei gedacht hat, die Zeilen bei 1 beginnen zu lassen).

Aber.
Hast du denn den Kommentar nicht gesehen?
1
////////////////////////////////////////////////////////////////////////////////
2
// Setzt den Cursor in Spalte x (0..15) Zeile y (1..4) 
3
 
4
void lcd_setcursor( uint8_t x, uint8_t y )

da steht eindeutig, wie die Funktion zu benutzen ist. Damit sind 
Versuche, als 2.ten Wert 0 oder auch 14 bzw. 15 zu übergeben recht 
sinnfrei. Es ist als ob die entsprechenden Aufrufe gar nicht da wären.

: Bearbeitet durch User
von Kurt W. (surfer2000at)


Lesenswert?

@ Klaus

Das dürfte nicht das Problem sein, die Anzeige funktioniert ja.
PS: daher habe ich dies auch nicht überprüft, möglich dass ich das noch
nachholen muss ....
Trotzdem Danke für den Hinweis.

@ Karl Heinz

Vielen Dank für die Info !
Ich habe in der Zwischenzeit etliche Versuche durchgeführt und bin in 
der Zwischenzeit auf einiges draufgekommen ....
Aber im Moment sitzt meine Tochter neben mir und will für den L17 
probefahren .... ich melde mich später wieder mit Genauerem.

lG Kurt

: Bearbeitet durch User
von Kurt W. (surfer2000at)


Lesenswert?

So, ich habe nun einiges ausprobiert. Nochmals Danke an Karl Heinz, die 
Versuche haben Deine Antwort größtenteils bestätigt. Der Vollständigkeit 
halber stell ich das ganze Protokoll hier rein:


ursprünglicher Code:
1
LN22  // Die Ausgabemarke in die 1te Zeile setzen
2
LN23  lcd_setcursor( 0, 0 );
3
LN24  // Text als String ausgeben
4
LN25  lcd_string("111 erste  zeile 111");
5
LN26
6
LN27  // Die Ausgabemarke in die 3te Zeile setzen
7
LN28  lcd_setcursor( 0, 0 );
8
LN29  // Text als String ausgeben
9
LN30  lcd_string("222 zweite zeile 222");
10
LN31
11
LN32  // Die Ausgabemarke in die 2te Zeile setzen
12
LN33  lcd_setcursor( 0, 0 );
13
LN34  // Text als String ausgeben
14
LN35  lcd_string("333 dritte zeile 333");
15
LN36
16
LN37  // Die Ausgabemarke in die 4te Zeile setzen
17
LN38  lcd_setcursor( 0, 0 );
18
LN39  // Text als String ausgeben
19
LN40  lcd_string("444 vierte zeile 444");
Anzeige am Display:
1
+-12345678901234567890-+
2
3
+----------------------+
4
I 111 erste  Zeile 111 I
5
I 222 zweite zeile 222 I
6
I 333 dritte zeile 333 I
7
I 444 vierte zeile 444 I
8
+----------------------+


Versuch 1: LN28, LN33 und LN38 mit // deaktiviert,
also //lcd_setcursor( 0, 0 )

Ergebnis: Gleich wie ursprünglich

(Ich nehme mal an, dass der µC die Werte einfach der Reihe nach 
abarbeitet.)


Versuch 2: LN30, LN35 und LN 40 ebenfalls mit // deaktivieren,
aber LN 25 ändern:

LN25  lcd_string("111 erste  zeile 111222 zweite zeile 222333 dritte 
zeile 333444 vierte zeile 444");

Ergebnis: Gleich wie ursprünglich (Genaugenommen habe ich das erwartet)


Versuch 3: Ursprünglichen Zustand wieder herstellen,
aber diesmal LN23, LN25, LN33 und LN38 deaktivieren
LN28 bleibt vorläufig unverändert:

LN28  lcd_setcursor( 0, 0 );

Ergebnis:

+----------------------+
I 222 zweite zeile 222 I
I 444 vierte zeile 444 I
I 333 dritte zeile 333 I
I                      I
+----------------------+

Auch das habe ich erwartet, irgendwo hier im Forum habe ich gelesen, 
dass ein 4x20 Display vom Kontroller her wie ein 2x40 Display behandelt 
und einfach in der mitte geteilt wird, also zuerst Zeile 1 und Zeile 3 
abgearbeitet werden und dann erst Zeile 2 und Zeile 4

Ich habe dann verschiedenste Werte(x) in LN28  lcd_setcursor( x, 0 ); 
eingetragen, das Ergebnis war immer das Gleiche, egal ob dort 0, 9, 10 
oder 25 stand.
Schließlich habe ich die Zeile wie folgt geändert:
LN28  lcd_setcursor; //( 0, 0 );
Beim compilieren erhielt ich dann eine Warnung, aber das Ergebnis am 
Display änderte sich nicht.

Versuch 4: LN17 bis LN20 sowie LN29 bis LN44 deaktiviert
nach LN45 eine neue Zeile eingefügt:

LN46  lcd_data( 'T' );

Dann diverse Werte in LN27 eingetragen.
Anmerkung:
Die erste Zahl steht für die Spalte (beginnend mit 0)
Die zweite Zahl steht für die Zeile (beginnend mit 1)

lcd_cursor ( 0, 1); ergibt ein T in der ersten  Zeile in Spalte 0  ( 1)
lcd_cursor (19, 1); ergibt ein T in der ersten  Zeile in Spalte 19 (20)
lcd_cursor (20, 1); ergibt ein T in der dritten Zeile in Spalte 0  ( 1)
lcd_cursor (39, 1); ergibt ein T in der dritten Zeile in Spalte 19 (20)

Nun versuchte ich die 2te Zeile anzusprechen und hätte ein T in der
2ten Zeile in Spalte 0 erwartet, aber es kam folgendes:

lcd_cursor ( 0, 2); ergibt ein T in der dritten Zeile in Spalte 12 (13)
lcd_cursor ( 1, 2); ergibt ein T in der dritten Zeile in Spalte 13 (14)
lcd_cursor ( 0, 4); ergibt ein T in der vierten Zeile in Spalte 12 (13)
lcd_cursor ( 1, 4); ergibt ein T in der vierten Zeile in Spalte 13 (14)

Gleich die nächsten Versuche mit
lcd_cursor ( 0, 3); ergibt ein T in der zweiten Zeile in Spalte 0  ( 1)
lcd_cursor (19, 3); ergibt ein T in der zweiten Zeile in Spalte 19 (20)
lcd_cursor (20, 3); ergibt ein T in der vierten Zeile in Spalte 0  ( 1)
lcd_cursor (39, 3); ergibt ein T in der vierten Zeile in Spalte 19 (20)

Erkenntnis daraus: ich kann also auf diese Weise jede beliebige Position 
in dem Display ansprechen, allerdings nur mit den Zeilen 1 und 3.

In der lcd-routines.h habe ich in Zeile 52 bis 55 die Werte angepaßt,
Ich glaube es zwar nicht, aber könnte es sein, das dies etwa falsche 
Werte sind? Oder liegt der "Fehler" ganz woanders?

Im Moment weiß ich nicht mehr weiter ....

(Für Trolle: Es ist mir durchaus bewusst, dass der größte Fehler hinter 
meiner Tastatur sitzt ...)

: Bearbeitet durch User
von Klaus (Gast)


Lesenswert?

@Kurt W.

Ersetz mal die lcd_init mit dieser hier und sag bescheid ob es dann 
geht.

Noch ein Hinweis. Am LCD gibt es einen speraten RESET den mal für ein 
paar
Sekunden auf GND oder 0V anschliessen. evtl. mehr mals probieren dann 
das Programm überspielen. Danach evtl. komplett alles aus ein.


//////////////////////////////////////////////////////////////////////// 
////////
// Initialisierung: muss ganz am Anfang des Programms aufgerufen werden.
void lcd_init( void )
{
    // verwendete Pins auf Ausgang schalten
    uint8_t pins = (0x0F << LCD_DB) |           // 4 Datenleitungen
                   (1<<LCD_RS) |                // R/S Leitung
                   (1<<LCD_EN);                 // Enable Leitung
    LCD_DDR |= pins;

    // initial alle Ausgänge auf Null
    LCD_PORT &= ~pins;

    // warten auf die Bereitschaft des LCD
    _delay_ms( LCD_BOOTUP_MS );

    // Soft-Reset muss 3mal hintereinander gesendet werden zur 
Initialisierung
    lcd_out( LCD_SOFT_RESET );
    _delay_ms( LCD_SOFT_RESET_MS1 );

    lcd_enable();
    _delay_ms( LCD_SOFT_RESET_MS2 );

    lcd_enable();
    _delay_ms( LCD_SOFT_RESET_MS3 );

  lcd_out(0x20 + 0x04);                            // Jetzt das 
Interface auf 4-Bitmodus  Erweiterungsbit RE setzen
    lcd_command(0x08 + 0x01 );                           // 4 Zeilen 
modus einstellen
  lcd_command(0x20 );                                  // Interface in 
4-Bitmodus und RE abschalten

    lcd_command(0x08 + 0x04);                         // LCD-Display Ein
    lcd_command(0x01);                                          // 
LCD-Display Löschen
    lcd_command(0x04 + 0x02 );                   // Cursor Adresse 
Automatisch erhöhen


    /*
    // 4-bit Modus aktivieren
     lcd_out( LCD_SET_FUNCTION |
        LCD_FUNCTION_4BIT );
        _delay_ms( LCD_SET_4BITMODE_MS );

    // 4-bit Modus  2 Zeilen  5x7
    lcd_command( LCD_SET_FUNCTION |
                 LCD_FUNCTION_4BIT |
                 LCD_FUNCTION_2LINE |  // LCD_FUNCTION_2LINE |
                 LCD_FUNCTION_5X7 );  // LCD_FUNCTION_5X7 );

    // Display ein  Cursor aus  Blinken aus
    lcd_command( LCD_SET_DISPLAY |
                 LCD_DISPLAY_ON |
                 LCD_CURSOR_OFF |
                 LCD_BLINKING_OFF);

    // Cursor inkrement / kein Scrollen
    lcd_command( LCD_SET_ENTRY |
                 LCD_ENTRY_INCREASE |
                 LCD_ENTRY_NOSHIFT );

    lcd_clear();
  */
}

von Kurt W. (surfer2000at)


Lesenswert?

@ Klaus

Danke für Info. Ich habe das Display mittlerweile auf eine andere Art 
zum (hoffentlich richtigem ?) laufen gebracht, trotzdem werde ich den 
von Dir geposteten Code ausprobieren, alleine um zu sehen, was sich da 
ändert.
Da jetzt jedoch wieder der Alltag beginnt, komme ich praktisch nur 
abends dazu.

mfG Kurt

von Karl H. (kbuchegg)


Lesenswert?

> In der lcd-routines.h habe ich in Zeile 52 bis 55 die Werte angepaßt,
> Ich glaube es zwar nicht, aber könnte es sein, das dies etwa falsche
> Werte sind?

Höchst wahrscheinlich sind die falsch.

> Oder liegt der "Fehler" ganz woanders?

Du bist sehr wahrscheinlich genau an der richtigen Stelle. Diese 4 Werte
1
#define LCD_DDADR_LINE1 0x00 // Werte aus Datenblatt für
2
#define LCD_DDADR_LINE2 0x20 // LCD Display 4 x 20 mit
3
#define LCD_DDADR_LINE3 0x40 // Kontroller KS0073
4
#define LCD_DDADR_LINE4 0x60
sind der Schlüssel.


Die 0x00 stehen ausser Frage. Das die erste Zeile bei 0 beginnt, ist 
nicht sonderlich überraschend.

Aus
1
lcd_cursor (20, 1); ergibt ein T in der dritten Zeile in Spalte 0 ( 1)
folgt, dass die 3. Zeile offenbar an der Adresse 0x14 anfängt. Also
1
#define LCD_DDADR_LINE1 0x00
2
#define LCD_DDADR_LINE2 0x20
3
#define LCD_DDADR_LINE3 0x14
4
#define LCD_DDADR_LINE4 0x60

Aus
1
lcd_cursor ( 0, 4); ergibt ein T in der vierten Zeile in Spalte 12 (13)
folgt dass die 4. Zeile 12 Zeichen vor 0x60 beginnt. Das wäre dann 0x54.
Also
1
#define LCD_DDADR_LINE1 0x00
2
#define LCD_DDADR_LINE2 0x20
3
#define LCD_DDADR_LINE3 0x14
4
#define LCD_DDADR_LINE4 0x54

Aus deinen Beschreibungen lässt sich leider nichts ermitteln, woraus man 
auf den Beginn der 2.ten Zeile schliessen könnte. Aus Analogiegründen 
würde ich mal mit 0x40 rechnen, denn die 3. Zeile ist 0x14 hinter der 
ersten Zeile, die 4. Zeile würde ich dann mal 0x14 hinter der zweiten 
Zeile annehmen. 0x54 - 0x14 ergibt 0x40. Ob das stimmt, wird ein Versuch 
zeigen müssen.

Mit der Belegung würde ich das daher mal ausprobieren.
1
#define LCD_DDADR_LINE1 0x00
2
#define LCD_DDADR_LINE2 0x40
3
#define LCD_DDADR_LINE3 0x14
4
#define LCD_DDADR_LINE4 0x54

lcd_setcursor mit zulässigen Zeilennummern und jeweils in Spalte 0 
positionieren.

: Bearbeitet durch User
von Kurt W. (surfer2000at)


Angehängte Dateien:

Lesenswert?

So, mal zwischendurch:

@ Klaus:

Ich habe den von Dir geposteten Teil der lcd-routines.c kurzerhand mal 
ausgetauscht (die durch das copy-paste entstandenen Fehler habe ich 
korrigiert). Beim Testen mit dem ursprünglichem Code (siehe Posting von 
06.01.2014 16:38) kam dabei folgendes raus:

+-12345678901234567890-+

+----------------------+
I V e 111222 zweite ze I
I                      I
I ile 222333 dritte ze I
I                      I
+----------------------+

Irgendwie ist mir das mittlerweile auch klar, warum dies so ist.
Diese ursprünglich hier geposteten Dateien
[[https://www.mikrocontroller.net/articles/AVR-GCC-Tutorial/LCD-Ansteuerung]]
sind als Vorlage für verschiedenste Möglichkeiten gedacht.

Ich habe mit copy-paste den gesamten Code einfach in die entsprechenden 
Dateien hineinkopiert - und da ich wie gesagt bis dato von C oder Cpp 
keine Ahnung habe - (mittlerweile weiß ich, das ich nix weiß) habe ich 
nur jene Werte angepaßt, auf welche ich hingewiesen wurde - das war zwar 
nicht falsch (zumindest nicht ganz falsch), aber bei weitem noch nicht 
richtig.
Wie gesagt, der Code ist für mehrere Möglichkeiten gedacht und 
sinnvollerweise (?) in mehrere (3) Dateien aufgeteilt. Dadurch kommt es 
vor, dass sich gewisse Teile gegenseitig beeinflussen oder aufheben, 
gültig ist dann jener Code, der zuletzt vom µC abgearbeitet wurde.

Sollte diese meine Meinung falsch sein, so ersuche ich um Hinweis.


@ Karl Heinz

Ich habe die von Dir angegebenen Werte kurz ausprobiert, funktioniert
leider auch nicht richtig. Wie gesagt, der ursprüngliche Quellcode (Link 
siehe oben) ist für ein 16 Zeichen Display ausgelegt und bietet außerdem 
mehrere Möglichkeiten, je nachdem, ob ein einzelnes Zeichen oder ein 
kompletter String angezeigt werden sollen. Und diese gegenseitigen 
Beeinflussungen muß ich noch rausbekommen.

Ganz am Anfang hatte ich Unterstützung von einem Informatik-Student, 
welcher mir eben aus diesem angegebenen Quellcode ein Programm 
zusammenstellte, welches aber aufgrund von falschen Hardware-Anschlüssen 
überhaupt nichts anzeigte. Leider hat dieser Student jetzt nur noch 
wenig Zeit, jedoch habe ich nachdem die Hardware richtig angeschlossen 
war, sein Programm nochmals hervorgeholt. Nach einigen kleineren 
Anpassungen funktioniert dieses tadellos. Im Anhang poste ich das Progi 
und sobald ich den Schaltplan ins Reine gezeichnet habe, auch diesen.

Danke für die Unterstützung, ich melde mich sobald die nächsten Troubles 
anstehen - also ziemlich bald ....

: Bearbeitet durch User
von Klaus (Gast)


Lesenswert?

Kurt W.

LOL.

Ich hab den unten stehenden Code bei mir getstet.
Kommt das gleiche wie bei dir raus.
Aber das ist doch klar und ist mir eben auch aufgefallen.

Da hier beim setzen " lcd_setcursor( 0, 0 ); ", von der
Software das Y = 0 garnicht behandelt wird, wirkt sich das aus wie
der HOME befehl.
Also muss es folglich " lcd_setcursor( 0, 1 ); für die erste Zeile 
heissen.

Des weiteren "lcd_setcursor( 0, 5 );", da beginnt die Ausgabe praktisch 
wieder bei Zeile 1.
Du hast nur ein 4 Zeilliges Display.

Hier wäre jetzt richtig  "lcd_setcursor( 0, 4 );


// Die Ausgabemarke in die 1te Zeile setzen
  lcd_setcursor( 0, 0 );
  // Text als String ausgeben
  lcd_string("111 erste  zeile 111");

  // Die Ausgabemarke in die 3te Zeile setzen
  lcd_setcursor( 0, 0 );
  // Text als String ausgeben
  lcd_string("333 dritte zeile 333");

  // Die Ausgabemarke in die 2te Zeile setzen
  lcd_setcursor( 0, 5 );
  // Text als String ausgeben
  lcd_string("222 zweite zeile 222");

  // Die Ausgabemarke in die 4te Zeile setzen
  lcd_setcursor( 0, 5 );
  // Text als String ausgeben
  lcd_string("444 vierte zeile 444");



Korrigierte Version.


// Die Ausgabemarke in die 1te Zeile setzen
  lcd_setcursor( 0, 1 );
  // Text als String ausgeben
  lcd_string("111 erste  zeile 111");

  // Die Ausgabemarke in die 3te Zeile setzen
  lcd_setcursor( 0, 3 );
  // Text als String ausgeben
  lcd_string("333 dritte zeile 333");

  // Die Ausgabemarke in die 2te Zeile setzen
  lcd_setcursor( 0, 2 );
  // Text als String ausgeben
  lcd_string("222 zweite zeile 222");

  // Die Ausgabemarke in die 4te Zeile setzen
  lcd_setcursor( 0, 4 );
  // Text als String ausgeben
  lcd_string("444 vierte zeile 444");

von Klaus (Gast)


Lesenswert?

Kurt sende mal nur diese zeilen zum Display

lcd_setcursor( 0, 1 );
// Text als String ausgeben
lcd_string("111 erste  zeile 111222 zweite zeile 222333 dritte zeile 
333444 vierte zeile 444");


Sollte die Ausgabe wie erwartet so sein.

zeile 1:   111 erste  zeile 111
zeile 2:   222 zweite zeile 222
zeile 3:   333 dritte zeile 333
zeile 4:   444 vierte zeile 444

Das 4 zeillige Display ist in Wirklichkeit ein Zwei zeilliges.
Das hast du ja schon mit bekommen denke ich.

Hier mal ein Beispiel wie die Offets bei mir aussehen.

#define Zeilen_Offset0     0x00
#define Zeilen_Offset1     0x20    // 20h EADIP204-4 ; 0x14 HD44780
#define Zeilen_Offset2     0x40    // 40h EADIP204-4 ; 0x40 HD44780
#define Zeilen_Offset3     0x60    // 60h EADIP204-4 ; 0x54 HD44780

von Klaus (Gast)


Lesenswert?

Klaus schrieb:
> Da hier beim setzen " lcd_setcursor( 0, 0 ); ", von der
> Software das Y = 0 garnicht behandelt wird, wirkt sich das aus wie
> der HOME befehl.

Das ist leider eine Falsch Aussage von mir.

Das heisst: Software das Y = 0 garnicht behandelt wird ist richtig.
Da es nicht behandelt wird auch keine Adresse eingestellt wo die Zeichen 
im
Display aus gegeben werden sollen.

Heisst letzt endlich das deine Anweisungen ganz einfach hintereinder 
ausgegeben werden.

von Kurt W. (surfer2000at)


Lesenswert?

@ Klaus

> lcd_setcursor( 0, 1 );
> // Text als String ausgeben
> lcd_string("111 erste  zeile 111222 zweite zeile 222333 dritte zeile
> 333444 vierte zeile 444");

Jep, kommt genauso raus, wie Du beschrieben hast .... mußte ich nicht 
nochmals eingeben, das habe ich schon vorher probiert.

Aber wie gesagt, im Prinzip ist mir diese Problematik (hoffentlich !?) 
bereits klar und damit eigentlich keine (???) mehr.

Meine nächste Etappe ist nun der Timer - siehe Anhang in Posting von 
07.01.2014 16:34 - Die "Uhr" funktioniert ja vorerst mal.

Damit ich dazu jedoch Fragen stellen und auch zielführende Antworten 
bekommen kann, muss ich erstmal den Schaltplan hier reinstellen.


mfG Kurt

von Klaus (Gast)


Lesenswert?

Das hier muss noch angepasst werden:

#define LCD_DDADR_LINE1         0x00
#define LCD_DDADR_LINE2         0x40
#define LCD_DDADR_LINE3         0x14  //0x10
#define LCD_DDADR_LINE4         0x54  //0x50

korrigiert:

#define LCD_DDADR_LINE1         0x00
#define LCD_DDADR_LINE2         0x20
#define LCD_DDADR_LINE3         0x40
#define LCD_DDADR_LINE4         0x60

von Kurt W. (surfer2000at)


Angehängte Dateien:

Lesenswert?

ups .... jep .... hab das da nicht durchgetestet und da es derzeit nicht 
verwendet wird, ist es mir auch nicht aufgefallen. Ist schon geändert.

Danke für den Hinweis.

Anbei noch der derzeitige Schaltplan, allerdings für das weitere 
Vorgehen muss ich diesen um Einiges erweitern. Das Ganze soll wie schon 
in
[[Beitrag "Was brauche ich ?"]] erwähnt eine 
Pumpensteuerung/Regelung werden und bedarf daher noch mehrerer 
Komponenten.

Dazu werde ich aber demnächst einen eigenen Thread aufmachen.
Grins ... da fällt mir auf, dass sich die ganzen Postings hier ja dann 
ähnlich wie eine objektorientierte Programmierung verhalten - 
Hauptprojekt (noch nicht erstellt) und jede Menge (derzeit nur 2) 
Unterprojekte.

( Darf ich das hier im Forum eigentlich so aufziehen ??? )

mfG Kurt

von Klaus (Gast)


Lesenswert?

Wenn du keine Frei definierbaren Zeichen brauchst kannst du R/W auf GND
lassen sonst an PD05 so als Vorschlag.

Eventuell, wenn man es dann auch möchte, die Beleuchtung über PWM 
ansteuern.

von spess53 (Gast)


Lesenswert?

Hi

>Wenn du keine Frei definierbaren Zeichen brauchst kannst du R/W auf GND
>lassen sonst an PD05 so als Vorschlag.

Mit frei programmierbaren Zeichen auch.

MfG Spess

von Kurt W. (surfer2000at)


Angehängte Dateien:

Lesenswert?

Wenn du genau hinsiehst, liegt R/W auf GND.
Aber ich habe vergessen, die Stromversorgung einzuzeichnen.
An Pin 2 des LCD´s liegt natürlich +5VDC an.

Anbei der korr. Schaltplan

: Bearbeitet durch User
von Klaus (Gast)


Lesenswert?

spess53 schrieb:
> Wenn du keine Frei definierbaren Zeichen brauchst kannst du R/W auf GND
>>lassen sonst an PD05 so als Vorschlag.

Sorry! Das hab ich jetzt mit dem Busyabfrage verwechselt.

von batty m. (battyman)


Lesenswert?

Tach auch. Ich habe mir mal den Thread hier so durchgelesen, da ich das 
selbe Display nun seit Weihnachten habe. Habe auch gründlich das 
AVR_GCC-Tutorial studiert. Da habe ich bei mir noch mal nach gesehen. 
Auszug aus dem Tutorial und auch so stehen bei mir im Programm:
1
#define LCD_DDADR_LINE1         0x00  //Im Tutorial mit eine 4x16 Display
2
#define LCD_DDADR_LINE2         0x40  //so um 4 Stellen erweitert für 4x20
3
#define LCD_DDADR_LINE3         0x14  //0x10
4
#define LCD_DDADR_LINE4         0x54  //0x50
dazu noch eure Case-Nummer Angabe in der "lcd.c" Datei nach gesehen:
1
void lcd_setcursor( uint8_t x, uint8_t y ) {
2
    uint8_t data;
3
 
4
    switch (y) {
5
        case 0:    // 1. Zeile
6
            data = LCD_SET_DDADR + LCD_DDADR_LINE1 + x;
7
            break;
8
 
9
        case 1:    // 2. Zeile
10
            data = LCD_SET_DDADR + LCD_DDADR_LINE2 + x;
11
            break;
12
 
13
        case 2:    // 3. Zeile
14
            data = LCD_SET_DDADR + LCD_DDADR_LINE3 + x;
15
            break;
16
 
17
        case 3:    // 4. Zeile
18
            data = LCD_SET_DDADR + LCD_DDADR_LINE4 + x;
19
            break;
20
 
21
        default:    
22
            return; // für den Fall einer falschen Zeile
23
    }
24
 
25
    lcd_command( data );
26
}
und wie man sieht ist die doch bei 0 beginnend.
Zur Probe habe ich meins nun auch noch mal angeschlossen, denn ich hatte 
für mich ebenfalls ersteinmal ein Verständnisproblem. Wenn ich nun nach 
Logik gehe müsste ja aufgrund der 4 Stellen längeren Zeichenlänge auch 
die um 4 Stellen angepasster Hex-Wert passen.
Hab nun ein kleines durchlaufprogramm geschrieben um den Curser-Weg nach 
zu prüfen:
1
int main(void)
2
{
3
  lcd_init();
4
  
5
  while(1)
6
  {
7
    for(i=0; i<8; i++)
8
    {
9
      if (i==0)
10
      {
11
        lcd_string("100 K");
12
      }
13
      else if(i==1)
14
      {
15
        lcd_setcursor(0, 1);
16
        lcd_string("200 K");
17
      } 
18
      else if (i==2)
19
      {
20
        lcd_setcursor(0, 2);
21
        lcd_string("300 K");
22
      }
23
      else if (i==3)
24
      {
25
        lcd_setcursor(0, 3);
26
        lcd_string("400 K");
27
      }
28
      else if (i==4)
29
      {
30
        lcd_setcursor(15, 3);
31
        lcd_string("500 K");
32
      }
33
      else if (i==5)
34
      {
35
        lcd_setcursor(16, 2);
36
        lcd_string("60 K");
37
      }
38
      else if (i==6)
39
      {
40
        lcd_setcursor(17, 1);
41
        lcd_string("7 K");
42
      }
43
      else if (i==7)
44
      {
45
        lcd_setcursor(19, 0);
46
        lcd_data('K');
47
      }
48
      _delay_ms(50);
49
      lcd_clear();  
50
    }
51
  }
52
  
53
  return 0;
54
}
Funktioniert einwandfrei!  Entweder ich habe das hier beschriebene 
Problem nicht ganz verstanden oder bei mir klappt das durch ein Zufall 
so wie ich es mir zumindestens gedacht habe.

Eine Frage habe ich dazu aber noch, wobei dies eher das
1
 _delay_ms(50);
betrifft. Was wird denn dabei eigentlich um 50 Millisekunden verzögert? 
Denn der Anzeigetextwechsel findet ungefähr alle 0,8 bis 0,9 Sekunden 
statt. Das wäre ja ungefähr das 16-fache von meiner Delay-Einstellung? 
Kann mir den bitte hier noch mit erklären, Danke!!!

LG

von Klaus (Gast)


Lesenswert?

batty man schrieb:
> as wird denn dabei eigentlich um 50 Millisekunden verzögert?
> Denn der Anzeigetextwechsel findet ungefähr alle 0,8 bis 0,9 Sekunden
> statt. Das wäre ja ungefähr das 16-fache von meiner Delay-Einstellung?
> Kann mir den bitte hier noch mit erklären, Danke!!!

Naja! Du würdest nur ein geflimmer sehen oder auch gar nichts.

Die 50ms sind dafür da, das du was siehst bevor das Diaplay gelöscht 
wird.
Probiers ganze einfach mal aus.

von batty m. (battyman)


Lesenswert?

Wenn ich keine Delay-Zeit nutzen würde, sehe ich wirklich nur 
undefiniertes durch Bild huschen.
Mein Verständnisproblem war nun jedoch, das ich gut 0,8 bis 0,9 Sekunden 
meinen angezeigten Wert bekomme. Das entspricht nicht 50ms, wie man 
unschwer erkennen kann. Dann hab ich mich nochmal mit dem Tutorial 
befasst und gelesen das diese "Wartezeit" real durch Störprozesse wie 
Interrupts effektiv länger werden können. Problem bei dieser Erklärung 
ist jedoch, das ich all das gar nicht habe.
Sind die Dleay-Zeiten von der verwendeten Systemfrequenz abhängig oder 
ist das schon in der Header-Datei für Delay-Zeiten schon mit 
berücksichtigt? Ich weiß jetzt gerade nicht ab ich 2, 8 oder 16 MHz 
verwende.Für mich wäre es nur so, dass 50ms, egal bei welcher 
Taktfrequenz, eben 50ms sind.

von Klaus (Gast)


Lesenswert?

batty man schrieb:
> Sind die Dleay-Zeiten von der verwendeten Systemfrequenz abhängig oder
> ist das schon in der Header-Datei für Delay-Zeiten schon mit
> berücksichtigt? Ich weiß jetzt gerade nicht ab ich 2, 8 oder 16 MHz
> verwende.Für mich wäre es nur so, dass 50ms, egal bei welcher
> Taktfrequenz, eben 50ms sind.

Ich hoffe ich sag jetzt nichts falsches, weil ein paar Geier darauf 
warten über einen herzufallen.

Ich jetzt nicht weiss welches Programmiertool du verwendest.

Bei Atmel Studio ist so!

Bsp. Externer Quarz 16 Mhz.
Damit 50ms bei dem Systemtakt 50ms werden muss folgendes am Anfang
im Programm stehen:

#define F_CPU 16000000UL  // unbedingt vor delay.h
#include <util/delay.h>


Aber das ist noch nicht alles.

Als nächstes ist die Optimerung auf -Os einzustellen.

Dann muss noch zwingend die Fuses des Controllers richtig gesetzt 
werden.

Also was auch immer bei #define F_CPU  angibtst,  sollten die Fuses auch
entsprechend gesetzt werden.

Falls du gar nicht #define F_CPU verwendest wird Standard mäßig
1Mhz verwendet also ohne Quarz.
Die Fuses müssen entsprechend auf den internen Oszilator und 1Mhz 
eingestellt sein.

von batty m. (battyman)


Lesenswert?

Nabnds,

ach ja ich benutze ein STK600 mit ATmega2560 und LCD EA W204B-NLW.
Also bei mir ist es wie beschrieben genau so aufgebaut, siehe:
1
#include <avr/io.h>
2
#include "lcd.h"
3
#define F_CPU 16000000UL
4
#include <util/delay.h>
5
uint8_t i;
also erst die Taktfrequenz von 16 MHz definiert und anschließend die 
Delay-Header-Datei eingebettet.
Da ich mit den Fuses noch keine Berührung hatte, habe ich die 
"Voreinstellung" von Atmel drin. Bzw. habe ich schon oft gelesen, dass 
man die erst ändern sollte wenn man davon n echten Plan hat, wat man 
dort ändert, denn dabei kann auch einiges "versaubeutelt" werden. 
Deswegen habe ich mich da auch noch nicht ran getraut.
Was hat das mit der Optimierung immer auf sich und wo find ich die im 
Atmel Studio 6.1?

Danke

von Klaus (Gast)


Angehängte Dateien:

Lesenswert?

@batty man

Anbei zwei Bilder!

1. Zeigt das Toolchain an.
   Wenn du auf deinen ATmega2560 in der Symboleiste klickst.
   Bei Optimization findest versichiedene Einstellungen.
   Einfach verschiedene einstellungen ausprobieren.
   z.b. eine Led 1 sek an und 1 sek aus.
   Mit einer Stoppuhr die Zeiten messen. Am Anfang alles ohne Interrupt

2. Wenn du auf Device Programming klickst
   macht sich ein seperates Fenster auf.

Solltest die Default Einstellung haben wie in Bild 3 musst du
den Eintrag wie in Bild 2 auswählen, weil du 16Mhz Quarz angeschlossen 
hast.

von batty m. (battyman)


Angehängte Dateien:

Lesenswert?

So, ich habe mal meine Toolchain nach der Optimierung durch gesehen und 
meine Default-Werte waren Optimize-O1 und das letzte Kontrollfeld ist 
deaktiviert, siehe Anhang. Warin liegen denn die Unterschiede zwischen 
O1, O2, O3 und Os bzw. warin bestehen die Vor- bzw. Nachteile die ich 
dann in Kauf nehmen muss??? Vielen Dank

von Klaus (Gast)


Lesenswert?

batty man schrieb:
> warin bestehen die Vor- bzw. Nachteile die ich
> dann in Kauf nehmen muss??? Vielen Dank

Das kann ich dir nicht ausführlich erklären, aber bei diesem link
http://gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html wird es
erklärt. Leider alles Englisch.

von batty m. (battyman)


Lesenswert?

-.-  Ohhh, ja danke...hehe, das ist ja bloß eine kleine Lektüre für mal 
so zwischen Durch  :D und dann noch in meiner gängig gesprochenen 
Muttersprache, SUUUUPIIII

Nee, mal im Ernst. Das ist wirklich mal ne ganze Menge Lesestoff und fit 
bin ich im Englischen nun auch nicht zu 100pro. Mir das mal zu Gemüte zu 
ziehen brauch mal eben ein wenig mehr Zeit. Vielen Dank für den Link so 
kann ich wenigstens bei Projektleerlauf mal was dazu lernen.

THX

von batty m. (battyman)


Lesenswert?

Hey ho allerseits,

ich bin mal neben meinen anderen Baustellen auch noch mit dem TEXT-LCD 
am werkeln. Dazu habe ich mal wieder ne kleine Frage.

In der lcd.c und lcd.h ist die lcd_clear() -Funktion ja eingebunden. Die 
löscht aber bekanntlich das gesammte 4*20 Display.

Wäre es auch möglich nur eine Zeile löschen zu lassen, während der Rest 
weiterhin stehen bleibt???

Wenn ich immer alles lösche und den nicht veränderlichen Text wieder 
ausgebe bekomme ich immer so ein nerviges geflacker. Dazu würde ich 
gerne die eine Zeile bloß löschen wolllen, da ich dort einen Lauftext 
ausgebe. Um das Überschreiben des vorherigen Buchstaben und damit ein 
restleuchten habe, ist es ziemlich schwierig zu lesen, sofern der Text 
in einer akzeptablen Geschwindigkeit durchläuft. Nun habe ich mir das so 
gedacht, dass ich das Nachleuchten durch ein vorheriges Löschen der 
Zeile minimiere.

Also mit dem Löschen des Displays und der erneuten Ausgabe kann ich die 
Leseeigenschaft verbessern. Blöd dabei ist nur, dass eben der nicht 
veränderliche Text nun sichtlicht zuckt/flackert.

von spess53 (Gast)


Lesenswert?

Hi

>Wäre es auch möglich nur eine Zeile löschen zu lassen, während der Rest
>weiterhin stehen bleibt???

Einfach die Zeile mit Leerzeichen beschreiben.

MfG Spess

von batty m. (battyman)


Lesenswert?

ok, danke. Hätt ich jetzt auch so gemacht. Dacht nur eventuell gibts da 
auch so eine schöne Funktion wie lcd_clear() nur abgewandelt für eine 
Zeile, wobei eben der Rest des Textes auf dem Display unberührt bleibt. 
Aber Leerzeichen machens dann wohl einfacher  :D

Frohe OSTERN!

von Marcel (Gast)


Lesenswert?

Moin,

ich habe auch das LCD-Modul EA W204B-NLW und frage mich welche Schrauben 
zum Befestigen des Moduls an eine Frontplatte benötigt werden.

M3 sind zu groß.

Ist es M2,5 oder M2 ?

Vielen Dank für eine Antwort diesbezüglich.

Gruss,

Stephan

von spess53 (Gast)


Lesenswert?


von batty m. (battyman)


Lesenswert?

Marcel schrieb:
> Ist es M2,5 oder M2 ?

Ich habe M2,5 genommen. Schraube gerade ansetzen und dann eben mit 
leichtem Druck einschrauben. Ist nur ganz wenig zu klein. Oder eben n 
kleinen 2,5 Bohrer und Loch aufweiten.

LG

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.