Forum: Mikrocontroller und Digitale Elektronik LCD Display - Frage zur Initialisierung


von M. G. (ixil96)


Angehängte Dateien:

Lesenswert?

Hallo!
Ich verwende ein Displaytech 162B im 4-Bit Betrieb) und verstehe die 
Initialisierungsroutine nicht ganz.

Wenn ich das Datenbit DB4 in den ersten 3 Schritten auf 1 stelle, 
funktioniert die Anzeige nicht. Ist das Bit jeweils auf 0, ist alles OK!

Sollte nach der Anleitung im Datenblatt nicht 3 Mal eine 1 für DB4 
geschrieben werden? Der 4-Bit Modus wird ja erst im 4. Schritt (set 
function - interface auf 4 bit setzen) eingestellt.

Oder habe ich hier etwas falsch verstanden?

Anbei meine Init-Tabelle und das Datenblatt.

von Carl D. (jcw2)


Lesenswert?

Die 1 bedeutet 8-Bit-Mode, die 0 4-Bit-Mode.
Da man sich nie sicher sein kann, in welchem Zustand sich das Dislay 
befindet (z.B. nach Reset am μC):

Startzustand:  8-Bit         4-Bit 1.Nibble  2.Nibble
      Nibble
1.    0011     8-Bit-Mode    8-Bit-Mode     abh.von 1.Nibble, dont care
2.    0011     8-Bit-Mode    1line,5x7      8-Bit-Mode
3.    0011     8-Bit-Mode    8-Bit-Mode     1line,5x7
  Ab hier haben wir definitiv 8-Bit-Mode (ein E-Pulse->ein Kommando)
4.    0010     4-Bit-Mode    4-Bit-Mode     4-Bit-Mode
  Ab hier haben wir definitiv 4-Bit-Mode, müssen also 2 Nibbles je
  Kommando ausgeben
5.    0010     4-Bit-Mode
6.    NFxx     N:lines; F:font

Damit hat man EINEN zuverlässigen Weg aus jedem Anfangszustand. Nach 
Power-On am Display funktionieren auch andere. Erst bei Reset am μC 
sieht man, ob's immer geht.

von M. G. (ixil96)


Lesenswert?

Also ich mach das eigentlich auch so :-(
Aber das Display schreibt nur komische Zeichen...

hier mein Code zur Initialisierung:
1
/****** Initialisierung des LCD Controllers *****/
2
void lcd_init()
3
{
4
  /* Port auf Ausgang schalten */
5
  LCDDDR  = 0xFF;
6
  LCDPORT = 0x00;
7
  _delay_ms(40);          // Warten bis LCD bereit ...
8
9
  /* Init 1 */
10
  sbi(LCDPORT, LCD_PIN_D5);    // D5 = 1
11
  sbi(LCDPORT, LCD_PIN_D4);    // D4 = 1
12
  _delay_ms(40);
13
  
14
  /* Init 2*/
15
  sbi(LCDPORT, LCD_PIN_D5);    // D5 = 1
16
  sbi(LCDPORT, LCD_PIN_D4);    // D4 = 1
17
  _delay_ms(5);
18
  
19
  /* Init 3*/
20
  sbi(LCDPORT, LCD_PIN_D5);    // D5 = 1
21
  sbi(LCDPORT, LCD_PIN_D4);    // D4 = 1 
22
  
23
  /* 4-Bit Modus starten ... */
24
  sbi(PORTD, LCD_PIN_E);      // Set ENABLE from L to H
25
  cbi(PORTD, LCD_PIN_E);
26
  _delay_ms(5);
27
28
  /* 2 Zeilen, 4-Bit Modus, Matrix 5x7 */
29
  lcd_send(BEFEHL, LCD_SET_1);  // Register SET FUNCTION = 0010 1000
30
31
  lcd_send(BEFEHL, LCD_OFF);    // Set LCD OFF
32
  lcd_send(BEFEHL, LCD_CLEAR);  // Clear LCD
33
34
  lcd_send(BEFEHL, LCD_SET_2);  // Entry Mode = Cursor increase, Display-Shift OFF
35
  lcd_send(BEFEHL, LCD_ON);    // Set LCD ON
36
}

von Ralf G. (ralg)


Lesenswert?

m. g. schrieb:
> sbi(LCDPORT, LCD_PIN_D5);    // D5 = 1
>   sbi(LCDPORT, LCD_PIN_D4);    // D4 = 1
>   _delay_ms(40);

Ich glaube, du solltest die Daten auch abschicken.

von M. G. (ixil96)


Lesenswert?

Ralf G. schrieb:
> Ich glaube, du solltest die Daten auch abschicken.

Huiii! Natürlich ;-)

Ich hab´s jetzt mal so gelöst:

Die Lösung mit den beiden Bits D5 und D4 in 2 Zeilen für die oberen 4 
Bits zu setzen gefällt mir aber nicht wirklich gut. Hat hier jemand eine 
bessere Lösung?

1
/****** Initialisierung des LCD Controllers *****/
2
void lcd_init()
3
{
4
  /* Port auf Ausgang schalten */
5
  LCDDDR  = 0xFF;
6
  LCDPORT = 0x00;
7
  _delay_ms(40);          // Warten bis LCD bereit ...
8
  
9
  /* LCD Soft-Reset 1*/
10
  LCDPORT = (1 << LCD_PIN_D5);
11
  LCDPORT |= (1 << LCD_PIN_D4);
12
  set_enable();          // Daten/Kommando übernehmen
13
  LCDPORT = 0x00;        
14
  set_enable();          // Daten/Kommando übernehmen
15
  _delay_ms(40);
16
  
17
  /* LCD Soft-Reset 2*/
18
  LCDPORT = (1 << LCD_PIN_D5);
19
  LCDPORT |= (1 << LCD_PIN_D4);
20
  set_enable();          // Daten/Kommando übernehmen
21
  LCDPORT = 0x00;        
22
  set_enable();          // Daten/Kommando übernehmen
23
  _delay_ms(5);
24
25
  /* LCD Soft-Reset 3*/
26
  LCDPORT = (1 << LCD_PIN_D5);
27
  LCDPORT |= (1 << LCD_PIN_D4);
28
  set_enable();          // Daten/Kommando übernehmen
29
  LCDPORT = 0x00;        
30
  set_enable();          // Daten/Kommando übernehmen
31
  _delay_ms(1);
32
33
  /* 2 Zeilen, 4-Bit Modus */
34
  lcd_send(BEFEHL, LCD_SET_1);  // Register SET FUNCTION = 0010 1000
35
  lcd_send(BEFEHL, LCD_OFF);     // Set LCD OFF
36
  lcd_send(BEFEHL, LCD_CLEAR);   // Clear LCD
37
  lcd_send(BEFEHL, LCD_SET_2);   // Set ENTRY MODE = 0000 0110
38
  lcd_send(BEFEHL, LCD_ON);     // Set LCD ON
39
}

von Mitlesa (Gast)


Lesenswert?

m. g. schrieb:
> Hat hier jemand eine bessere Lösung?

LCDPORT &= ~(alle bits die du neu setzen willst)
           ^ not!

LCDPORT |= (genau das was du alles reinschreiben willst)



>> set_enable();

eine sehr ungeeignete Benamung, denn was man setzt ist
erst einmal gesetzt. Das was deine Routine macht ist aber
offensichtlich einen Zyklus ausführen.

von M. G. (ixil96)


Lesenswert?

Mitlesa schrieb:

>>> set_enable();
>
> eine sehr ungeeignete Benamung, denn was man setzt ist
> erst einmal gesetzt. Das was deine Routine macht ist aber
> offensichtlich einen Zyklus ausführen.

Ja, da hast du recht!
Ich hab meinen Code nun wie folgt geändert:
1
/****** Initialisierung des LCD Controllers *****/
2
void lcd_init()
3
{
4
  /* Port auf Ausgang schalten */
5
  LCDDDR  = 0xFF;
6
  LCDPORT = 0x00;
7
  _delay_ms(40);          // Warten bis LCD bereit ...
8
  
9
  /* LCD Soft-Reset 1*/
10
  LCDPORT = (1 << LCD_PIN_D5)|(1 << LCD_PIN_D4);  // Oberes Nibble = 0011
11
  toggle_enable();                // Daten/Kommando übernehmen
12
  LCDPORT = 0x00;                  // Unteres Nibble = 0000
13
  toggle_enable();                // Daten/Kommando übernehmen
14
  _delay_ms(40);
15
  
16
  /* LCD Soft-Reset 2*/
17
  LCDPORT = (1 << LCD_PIN_D5)|(1 << LCD_PIN_D4);  // Oberes Nibble = 0011
18
  toggle_enable();                // Daten/Kommando übernehmen
19
  LCDPORT = 0x00;                  // Unteres Nibble = 0000
20
  toggle_enable();                // Daten/Kommando übernehmen
21
  _delay_ms(5);
22
23
  /* LCD Soft-Reset 3*/
24
  LCDPORT = (1 << LCD_PIN_D5)|(1 << LCD_PIN_D4);  // Oberes Nibble = 0011
25
  toggle_enable();                // Daten/Kommando übernehmen
26
  LCDPORT = 0x00;                  // Unteres Nibble = 0000
27
  toggle_enable();                // Daten/Kommando übernehmen
28
  _delay_ms(1);
29
30
  /* LCD auf 2 Zeilen, 4-Bit Modus, 5x7 Matrix einstellen */
31
  lcd_send(BEFEHL, LCD_SET_1);  // Register SET FUNCTION = 0010 1000
32
  lcd_send(BEFEHL, LCD_OFF);     // Set LCD OFF
33
  lcd_send(BEFEHL, LCD_CLEAR);   // Clear LCD
34
  lcd_send(BEFEHL, LCD_SET_2);   // Set ENTRY MODE = 0000 0110
35
  lcd_send(BEFEHL, LCD_ON);     // Set LCD ON
36
}

von Mitlesa (Gast)


Lesenswert?

Du schreibst immer noch den ganzen Port obwohl du nur 4 Bit
brauchst und willst. Könnte ja sein dass due die anderen
Bits für was anderes brauchst.

Das LCD braucht beim Init nur die 4 Bit da es ja noch nicht
weiss ob es 4 oder 8 bit machen soll, daher ist der zweite
Zyklus, das untere Nibble, nicht erforderlich.

von Carl D. (jcw2)


Lesenswert?

Vor allem betreibst du die Schnittstelle immer im 4-Bit-Modus (Ausgabe 
des 2.Nibbles). Diese 3x "8-Bit-Mode" am Anfang sollen das LCD aber 
definiert in den 8-Bit-Modus bringen. Erst dann weiß man, daß das nun 
folgende "4-Bit" richtig interpretiert wird.
1
/****** Initialisierung des LCD Controllers *****/
2
void lcd_init()
3
{
4
  /* Port auf Ausgang schalten */
5
  LCDDDR  = 0xFF;
6
  LCDPORT = 0x00;
7
  _delay_ms(40);          // Warten bis LCD bereit ...
8
9
#define LCD_8BITMODE  ((1 << LCD_PIN_D5)|(1 << LCD_PIN_D4))
10
11
  /* LCD Soft-Reset 1*/
12
  LCDPORT = LCD_8BITMODE;  // geht davon aus, daß nichts anderes als LCD an dem Port hängt
13
  toggle_enable();         // Kommando übernehmen
14
  _delay_ms(40);
15
  
16
  /* LCD Soft-Reset 2*/
17
  toggle_enable();                // Kommando übernehmen
18
  _delay_ms(5);
19
20
  /* LCD Soft-Reset 3*/
21
  toggle_enable();                // Kommando übernehmen
22
  _delay_ms(1);
23
24
// ab jetzt haben wir sicher 8-Bit Mode,
25
//  d.h. nächste Kommando wird sicher als ein solches verstanden
26
27
  /* LCD auf 2 Zeilen, 4-Bit Modus, 5x7 Matrix einstellen */
28
  lcd_send(BEFEHL, LCD_SET_1);  // Register SET FUNCTION = 0010 1000
29
  lcd_send(BEFEHL, LCD_OFF);     // Set LCD OFF
30
  lcd_send(BEFEHL, LCD_CLEAR);   // Clear LCD
31
  lcd_send(BEFEHL, LCD_SET_2);   // Set ENTRY MODE = 0000 0110
32
  lcd_send(BEFEHL, LCD_ON);     // Set LCD ON
33
}
Falls es dir aber nicht darum geht das zu verstehen, warum nimmst du 
nicht einfach den Code aus dem Tutorial?

von M. G. (ixil96)


Lesenswert?

Carl D. schrieb:

> Falls es dir aber nicht darum geht das zu verstehen, warum nimmst du
> nicht einfach den Code aus dem Tutorial?

Danke für die Hilfe!
Mir geht es vor allem darum, den Code und die Initialisierung zu 
verstehen!

von Mitlesa (Gast)


Lesenswert?

m. g. schrieb:
> Danke für die Hilfe!

Dann noch eine zum Schluss:

Was heisst LCD?
Was heisst LCD Display?

Was ist ein weisser Schimmel?

von Carl D. (jcw2)


Lesenswert?

Stimmt, ich hätte jedwede Hilfe aus formalen Gründen ablehnen sollen.
(es gibt neben dem weißen Schimmel auch noch den Schwarzen, nicht zu 
vergessen den Adligen: von Amtswegen)

: Bearbeitet durch User
von M. G. (ixil96)


Lesenswert?

Ok, soweit habe ich das jetzt verstanden!

Wenn ich jetzt aber am PORTD den Pin 3 für Enable und Pin 2 für RS 
verwenden möchte, dann muss ich die Bits D5 und D4 mit dem Makro 
sbi(Port,Pin) setzen. Richtig?
1
#define LCDPORT    PORTD
2
#define LCDDDR    DDRD
3
#define LCD_PIN_RS  2
4
#define LCD_PIN_E  3
5
#define LCD_PIN_D4  4
6
#define LCD_PIN_D5    5
7
#define LCD_PIN_D6    6
8
#define LCD_PIN_D7    7
9
#define LCD_SETDDRAM    0x80   // Set Display RAM Address
10
...
11
...
12
...
13
/****** Initialisierung des LCD Controllers *****/
14
void lcd_init()
15
{
16
  /* Port auf Ausgang schalten */
17
  LCDDDR  = 0xFF;
18
  LCDPORT = 0x00;
19
  _delay_ms(40);          // Warten bis LCD bereit ...
20
21
  /* LCD Soft-Reset 1*/
22
  sbi(LCDPORT, LCD_PIN_D5);    // LCD D5 = 1
23
  sbi(LCDPORT, LCD_PIN_D4);    // LCD D4 = 1
24
  toggle_enable();        // Kommando übernehmen
25
  _delay_ms(40);
26
  
27
  /* LCD Soft-Reset 2*/
28
  toggle_enable();                // Kommando übernehmen
29
  _delay_ms(5);
30
31
  /* LCD Soft-Reset 3*/
32
  toggle_enable();                // Kommando übernehmen
33
  _delay_ms(1);
34
35
  // Ab hier ist sicher der 8-Bit Mode eingestellt!
36
  // Somit wird das folgende Kommando auch richtig verstanden!
37
38
  /* LCD auf 2 Zeilen, 4-Bit Modus, 5x7 Matrix einstellen */
39
  lcd_send(BEFEHL, LCD_SET_4Bit);    // Register SET FUNCTION = 0010 1000
40
  lcd_send(BEFEHL, LCD_OFF);      // Set LCD OFF
41
  lcd_send(BEFEHL, LCD_CLEAR);    // Clear LCD
42
  lcd_send(BEFEHL, LCD_SET_2);    // Set ENTRY MODE = 0000 0110
43
  lcd_send(BEFEHL, LCD_ON);      // Set LCD ON
44
}

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.