LCD Display - Frage zur Initialisierung

OP #4252888
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.
Angehängte Dateien:
#4252960
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.
OP #4253020
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
}
OP #4253587
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
}
Gast #4253744
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.
OP #4254798
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
}
Gast #4254816
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.
#4254845
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?
OP #4254958
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
}

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