Forum: Mikrocontroller und Digitale Elektronik HD44780 kompatibles Display - Initialisierung klappt nicht


von Jörg (Gast)



Lesenswert?

Hallo,

ich bin ein lernwilliger Anfänger, was die Programmierung und die 
AVR-Mikrocontroller angeht.
Ich programmiere in C mit dem GCC Plugin für das AVR-Studio.
Als Lernprojekt habe ich mir vorgenommen ein Text LCD-Display 
anzusteuern.

Leider klappt bei mir nicht einmal die Initialisierung.
Da ich schon seit dem Wochenende viel versucht habe (ich habe auch die 
Suchfunktion benutzt), wende ich mich nun an euch.

Meine Hardware:
- Der AVR: ATMEGA16, interner Quarz 8Mhz
- Das Display: 4*20 Zeichen (Die Bezeichnung des LCD-Displays lautet: 
YM-2004A Series)

Durch meine Recherche habe ich schon rausgefunden, dass das Display 
entweder den Controller KS0066 oder den SPLC780 nutzt und diese 
eventuell anders initialisiert werden.
Im Anhang ist einmal das kleine Datenblatt des Displays(welches ich beim 
Kauf dabei bekommen habe).
Außerdem habe ich ein großes Datenblatt und ein Datenblatt für den 
KS0066, welche ich gegoogelt habe angehängt.

Fehler:
Sobald das LCD-Diplay Strom bekommt sehe ich in der 1.und der 3. Zeile 
Balken. Sonst passiert nichts - ich nehme stark an, dass die Balken nach 
der Initialisierung verschwinden sollten.

Mein Programm:

Ich bin bei der Initialisierung nach dem Datenblatt des KS0066 
vorgegangen (die Initialisierung vom HD44780 habe ich aber auch schon 
versucht).
1
#ifndef F_CPU
2
#define F_CPU 8000000UL 
3
#endif
4
5
#include <avr/io.h>
6
#include <util/delay.h>
7
8
#define RS     PD4
9
#define RW     PD5
10
#define DB7    PD3
11
#define DB6    PD2
12
#define DB5    PD1
13
#define DB4    PD0
14
#define E      PD6
15
16
void lcd_init( void );
17
18
// ***** Hauptprogramm *****
19
int main(void){
20
21
  lcd_init ();                                 // Display initialisieren    
22
                                               
23
while();                                       // Endlosschleife
24
25
}
26
27
void lcd_init( void )
28
{
29
30
//************  power on  *********************
31
//********  wait more than 30ms  **************
32
_delay_ms (50); 
33
34
//*************  Function set  ****************
35
// LOW
36
PORTD &= ~(1<<RS)  // RS LOW    
37
    |(1<<RW)  // RW LOW
38
    |(1<<DB7)  // DB7 LOW
39
    |(1<<DB6)  // DB6 LOW
40
          // DB5 HIGH
41
    |(1<<DB4);  // DB4 LOW
42
// HIGH
43
PORTD |= (1<<DB5);
44
//--------------------------------------------
45
// LOW
46
PORTD &= ~(1<<RS)  // RS LOW    
47
    |(1<<RW)  // RW LOW
48
    |(1<<DB7)  // DB7 LOW
49
    |(1<<DB6)  // DB6 LOW
50
          // DB5 HIGH
51
    |(1<<DB4);  // DB4 LOW
52
// HIGH
53
PORTD |= (1<<DB5);
54
//--------------------------------------------
55
// LOW
56
PORTD &= ~(1<<RS)  // RS LOW    
57
    |(1<<RW)  // RW LOW
58
          // DB7 HIGH
59
          // DB6 HIGH
60
          // DB5 HIGH
61
    |(1<<DB4);  // DB4 HIGH
62
// HIGH
63
PORTD |= (1<<DB7)
64
    |(1<<DB6)
65
    |(1<<DB5);  
66
67
//*********** wait more than 39us  **************
68
_delay_us (50);
69
70
//********  Display ON/OFF Control  *************
71
// LOW
72
PORTD &= ~(1<<RS)  // RS LOW    
73
    |(1<<RW)  // RW LOW
74
    |(1<<DB7)  // DB7 LOW
75
    |(1<<DB6)  // DB6 LOW
76
    |(1<<DB5)  // DB5 LOW
77
    |(1<<DB4);  // DB4 LOW
78
//--------------------------------------------
79
// LOW
80
PORTD &= ~(1<<RS)  // RS LOW    
81
    |(1<<RW);  // RW LOW
82
          // DB7 HIGH
83
          // DB6 HIGH
84
          // DB5 HIGH
85
          // DB4 HIGH
86
// HIGH
87
PORTD |= (1<<DB7)
88
    |(1<<DB6)
89
    |(1<<DB5)
90
    |(1<<DB4);
91
92
//********** wait more than 39us  ****************
93
_delay_us (50);
94
95
//******************  Display Clear **************
96
// LOW
97
PORTD &= ~(1<<RS)  // RS LOW    
98
    |(1<<RW)  // RW LOW
99
    |(1<<DB7)  // DB7 LOW
100
    |(1<<DB6)  // DB6 LOW
101
    |(1<<DB5)  // DB5 LOW
102
    |(1<<DB4);  // DB4 LOW
103
//--------------------------------------------
104
// LOW
105
PORTD &= ~(1<<RS)  // RS LOW    
106
    |(1<<RW)  // RW LOW
107
    |(1<<DB7)  // DB7 LOW
108
    |(1<<DB6)  // DB6 LOW
109
    |(1<<DB5);  // DB5 LOW
110
          // DB4 High
111
// HIGH
112
PORTD |= (1<<DB4);
113
114
//********* wait more than 1,53ms  ****************
115
_delay_ms (5);
116
117
//************  Entry Mode Set ********************
118
// LOW
119
PORTD &= ~(1<<RS)  // RS LOW    
120
    |(1<<RW)  // RW LOW
121
    |(1<<DB7)  // DB7 LOW
122
    |(1<<DB6)  // DB6 LOW
123
    |(1<<DB5)  // DB5 LOW
124
    |(1<<DB4);  // DB4 LOW
125
//--------------------------------------------
126
// LOW
127
PORTD &= ~(1<<RS)  // RS LOW    
128
    |(1<<RW)  // RW LOW
129
    |(1<<DB7)  // DB7 LOW
130
          // DB6 HIGH
131
          // DB5 High
132
    |(1<<DB4);  // DB4 LOW
133
// HIGH
134
PORTD |= (1<<DB6)
135
    |(1<<DB5);
136
137
//*************Initializstion end*******************
138
139
}

Vielen Dank für eure Hilfe!

von holger (Gast)


Lesenswert?

// LOW
>PORTD &= ~(1<<RS)  // RS LOW
>    |(1<<RW)  // RW LOW
>    |(1<<DB7)  // DB7 LOW
>    |(1<<DB6)  // DB6 LOW
>          // DB5 HIGH
>    |(1<<DB4);  // DB4 LOW

Das Ergebnis dieses Befehls ist:

// RS LOW
// RW High
// DB7 High
// DB6 High
// DB5 Low
// DB4 High

von Jörg (Gast)


Lesenswert?

Danke für den Hinweis.

Ich hatte versucht den Code zu kürzen um die Lesbarkeit zu verbessern.

Ich habe allerdings viele Versionen ausprobiert. Die Folgende 
funktioniert auch nicht:
1
#ifndef F_CPU
2
#define F_CPU 8000000UL 
3
#endif
4
5
#include <avr/io.h>
6
#include <util/delay.h>
7
8
#define RS    PD4
9
#define RW    PD5
10
#define DB7    PD3
11
#define DB6    PD2
12
#define DB5    PD1
13
#define DB4    PD0
14
#define E    PD6
15
16
void lcd_init( void );
17
18
19
// ***** Hauptprogramm *****
20
int main(void){
21
22
  _delay_ms (15);                               // wait min 15 mSec. after Power ON
23
  lcd_init ();     
24
                                               // Display initialisieren    
25
  for (;;);
26
27
}
28
29
void lcd_init( void )
30
{
31
32
//************  power on  *********************
33
34
//********  wait more than 30ms  **************
35
_delay_ms (50); 
36
37
//*************  Function set  ****************
38
// LOW
39
PORTD &= ~(1<<RS);  // RS LOW    
40
PORTD &= ~(1<<RW);  // RW LOW
41
PORTD &= ~(1<<DB7);  // DB7 LOW
42
PORTD &= ~(1<<DB6);  // DB6 LOW
43
          // DB5 HIGH
44
PORTD &= ~(1<<DB4);  // DB4 LOW
45
// HIGH
46
PORTD |= (1<<DB5);
47
//--------------------------------------------
48
// LOW
49
PORTD &= ~(1<<RS);  // RS LOW    
50
PORTD &= ~(1<<RW);  // RW LOW
51
PORTD &= ~(1<<DB7);  // DB7 LOW
52
PORTD &= ~(1<<DB6);  // DB6 LOW
53
          // DB5 HIGH
54
PORTD &= ~(1<<DB4);  // DB4 LOW
55
// HIGH
56
PORTD |= (1<<DB5);
57
//--------------------------------------------
58
// LOW
59
PORTD &= ~(1<<RS);  // RS LOW    
60
PORTD &= ~(1<<RW);  // RW LOW
61
          // DB7 HIGH
62
          // DB6 HIGH
63
          // DB5 HIGH
64
PORTD &= ~(1<<DB4);  // DB4 HIGH
65
// HIGH
66
PORTD |= (1<<DB7);
67
PORTD |= (1<<DB6);
68
PORTD |= (1<<DB5);  
69
70
//*********** wait more than 39us  **************
71
_delay_us (50);
72
73
//********  Display ON/OFF Control  *************
74
// LOW
75
PORTD &= ~(1<<RS);  // RS LOW    
76
PORTD &= ~(1<<RW);  // RW LOW
77
PORTD &= ~(1<<DB7);  // DB7 LOW
78
PORTD &= ~(1<<DB6);  // DB6 LOW
79
PORTD &= ~(1<<DB5);  // DB5 LOW
80
PORTD &= ~(1<<DB4);  // DB4 LOW
81
//--------------------------------------------
82
// LOW
83
PORTD &= ~(1<<RS);  // RS LOW    
84
PORTD &= ~(1<<RW);  // RW LOW
85
          // DB7 HIGH
86
          // DB6 HIGH
87
          // DB5 HIGH
88
          // DB4 HIGH
89
// HIGH
90
PORTD |= (1<<DB7);
91
PORTD |= (1<<DB6);
92
PORTD |= (1<<DB5);
93
PORTD |= (1<<DB4);
94
95
//********** wait more than 39us  ****************
96
_delay_us (50);
97
98
//******************  Display Clear **************
99
// LOW
100
PORTD &= ~(1<<RS);  // RS LOW    
101
PORTD &= ~(1<<RW);  // RW LOW
102
PORTD &= ~(1<<DB7);  // DB7 LOW
103
PORTD &= ~(1<<DB6);  // DB6 LOW
104
PORTD &= ~(1<<DB5);  // DB5 LOW
105
PORTD &= ~(1<<DB4);  // DB4 LOW
106
//--------------------------------------------
107
// LOW
108
PORTD &= ~(1<<RS);  // RS LOW    
109
PORTD &= ~(1<<RW);  // RW LOW
110
PORTD &= ~(1<<DB7);  // DB7 LOW
111
PORTD &= ~(1<<DB6);  // DB6 LOW
112
PORTD &= ~(1<<DB5);  // DB5 LOW
113
          // DB4 High
114
// HIGH
115
PORTD |= (1<<DB4);
116
117
//********* wait more than 1,53ms  ****************
118
_delay_ms (5);
119
120
//************  Entry Mode Set ********************
121
// LOW
122
PORTD &= ~(1<<RS);  // RS LOW    
123
PORTD &= ~(1<<RW);  // RW LOW
124
PORTD &= ~(1<<DB7);  // DB7 LOW
125
PORTD &= ~(1<<DB6);  // DB6 LOW
126
PORTD &= ~(1<<DB5);  // DB5 LOW
127
PORTD &= ~(1<<DB4);  // DB4 LOW
128
//--------------------------------------------
129
// LOW
130
PORTD &= ~(1<<RS);  // RS LOW    
131
PORTD &= ~(1<<RW);  // RW LOW
132
PORTD &= ~(1<<DB7);  // DB7 LOW
133
          // DB6 HIGH
134
          // DB5 High
135
PORTD &= ~(1<<DB4);  // DB4 LOW
136
// HIGH
137
PORTD |= (1<<DB6);
138
PORTD |= (1<<DB5);
139
140
//*************Initializstion end*******************
141
142
}

von holger (Gast)


Lesenswert?

Weisst du was mich an deinem Code stört, außer das die Timings
teilweise fehlen? RW wird angesteuert (was man gar nicht braucht
wenn man RW auf Masse legt), Enable aber nicht.

von Karl H. (kbuchegg)


Lesenswert?

Jörg schrieb:

> Ich habe allerdings viele Versionen ausprobiert. Die Folgende
> funktioniert auch nicht:


Meiner Meinung nach schneidest du dich mit so einem Schei.... nur ins 
eigene Fleisch.



> void lcd_init( void )
> {
>
> //************  power on  *********************
>
> //********  wait more than 30ms  **************
> _delay_ms (50);
>
> //*************  Function set  ****************
> // LOW
> PORTD &= ~(1<<RS);  // RS LOW
> PORTD &= ~(1<<RW);  // RW LOW
> PORTD &= ~(1<<DB7);  // DB7 LOW
> PORTD &= ~(1<<DB6);  // DB6 LOW
>           // DB5 HIGH
> PORTD &= ~(1<<DB4);  // DB4 LOW
> // HIGH
> PORTD |= (1<<DB5);
> //--------------------------------------------
> // LOW
> PORTD &= ~(1<<RS);  // RS LOW
> PORTD &= ~(1<<RW);  // RW LOW
> PORTD &= ~(1<<DB7);  // DB7 LOW
> PORTD &= ~(1<<DB6);  // DB6 LOW
>           // DB5 HIGH
> PORTD &= ~(1<<DB4);  // DB4 LOW
> // HIGH
> PORTD |= (1<<DB5);

usw. usw.

du musst jeden einzelnen Pin über 25 Statements verfolgen um zu wissen, 
wann genau der jeweilige Pin auf 0 bzw auf 1 ist.

Mir ist schon klar, dass das Ziel darin besteht, die Initialisierung 
über die Bühne zu bringen, ohne das die anderen Pins verändert werden.

Aber leg fürs erste nicht zuviel Gewicht auf dieses Ziel! Denn dadurch 
verlierst du es erst mal aus den Augen.

Fürs erste ist es völlig ausreichend, wenn du die Initalisierung so 
machst, dass du an den Port D zu Beginn jeden neues 
Initialisierungsschrittes das anzulegende Bitmuster komplett anlegst. 
Also einfach eine Zuweisung an PORTD. Dann hinen nach noch ein Toggeln 
mit dem E-Pin und das wars.

Mach dir die Sache nicht unnötigerweise zu komplex. Zumindest nicht am 
Anfang.

Kein Mensch stört sich bei einem Anfänger bei seinen ersten Schritten 
daran, wenn du anstelle von ...
1
//********  wait more than 30ms  **************
2
_delay_ms (50); 
3
4
//*************  Function set  ****************
5
// LOW
6
PORTD &= ~(1<<RS);  // RS LOW    
7
PORTD &= ~(1<<RW);  // RW LOW
8
PORTD &= ~(1<<DB7);  // DB7 LOW
9
PORTD &= ~(1<<DB6);  // DB6 LOW
10
          // DB5 HIGH
11
PORTD &= ~(1<<DB4);  // DB4 LOW
12
// HIGH
13
PORTD |= (1<<DB5);


... das so machst:
1
//********  wait more than 30ms  **************
2
  _delay_ms (50); 
3
4
  PORTD = (1<<DB5);


Weil ichs gerade sehe: Wo wedelst du eigentlich mit dem Enable-Pin?

von Jörg (Gast)


Lesenswert?

Ich denke, dass ich das auch noch nicht ganz verstanden habe.

Zu RW:
Ich habe RW an einen PORT-Pin angeschlossen, daher setzte ich diesen 
immmer auf LOW.

Zu E:
Wann muss ich E denn ansteuern?
Im Datenblatt konnte ich in dem Flussdiagramm nicht finden, dass E 
angesteuert wird. Daher steuere ich E auch nicht an.


Danke für deine Hilfe.

von Karl H. (kbuchegg)


Lesenswert?

Jörg schrieb:

> Im Datenblatt konnte ich in dem Flussdiagramm nicht finden, dass E
> angesteuert wird.

Im Datenblatt gibt es sicherlich ein Diagramm, welches die elektrischen 
Signale zeigt. Und dort taucht E auf

> Daher steuere ich E auch nicht an.

> Wann muss ich E denn ansteuern?

Immer dann, wenn der Zustand deiner Port-Bits fertig eingestellt ist.
Das LCD kann ja nicht hellsehen, dass dein Code jetzt mit Manipulation 
der Port-Bits fertig ist und es daher die anliegenden Signale übernehmen 
soll.

Ich weiß, der Name "Enable" ist etwas schlecht gewählt. Aber im Grunde 
ist das nichts anderes als die Leitung: "Alle Datenbits sind fertig 
eingestellt, R/W hab ich eingestellt, Command/Data hab ich eingestellt; 
jetzt bist du drann - mach was damit!"

von holger (Gast)


Lesenswert?

>Wann muss ich E denn ansteuern?
>Im Datenblatt konnte ich in dem Flussdiagramm nicht finden, dass E
>angesteuert wird.

Mittleres Datenblatt Seite 4 und 5. Man muss schon
ziemlich blind sein um das zu übersehen.

von Jörg (Gast)


Lesenswert?

Das auf Seite 4 und 5 im 2. Datenblatt hatte ich schon gesehen, 
allerdings wusste ich nicht, dass ich auch bei der Initialisierung diese 
Grafik beachten muss.

Ich dachte dies gilt nur, wenn ich nach der Initialisierung Daten in das 
Display schreibe.

Nun weiss ich es besser. Danke!

Muss ich E nun also ansteuern wenn ich die PINS DB7-DB4 ändere, oder 
immer erst nach einem "gesamten Initialisierungsschritt"

Mit Initialisierungsschritt meine ich die Schritte, welche im Datenblatt 
3(das des KS0066) auf Seite 27 aufgeführt sind.

von Karl H. (kbuchegg)


Lesenswert?

Jörg schrieb:
> Das auf Seite 4 und 5 im 2. Datenblatt hatte ich schon gesehen,
> allerdings wusste ich nicht, dass ich auch bei der Initialisierung diese
> Grafik beachten muss.

Immer!
Wie gesagt: Das LCD kann ja nicht hellsehen, wann die restlichen Pins 
ihren endgültigen Zustand angenommen haben.

> Muss ich E nun also ansteuern wenn ich die PINS DB7-DB4 ändere, oder
> immer erst nach einem "gesamten Initialisierungsschritt"

Laut Datenblatt geht E auf High
dann ändern sich die Datenpins
und dann geht E wieder auf Low

Siehe Timingdiagramm

Mit dem Übergang von E von High auf Low übernimmt das LCD die Daten.

Wobei das nicht soooo heiß gegessen wird.
Du kannst auch vorher die Datenleitungen einstellen, dann geht E auf 
High, wartet ein bischen und geht wieder auf Low. Entscheidend ist nur, 
dass die Datenleitungen (+R/W +Command) mit dem Wechsel von E von High 
auf Low übernommen werden und das E eine gewisse Mindestzeit auf High 
gehalten werden muss.

Warum studierst du den nicht anderen Code für solche Details? Im 
Tutorial gibt es einen Abschnitt über das LCD!

> Mit Initialisierungsschritt meine ich die Schritte, welche im Datenblatt
> 3(das des KS0066) auf Seite 27 aufgeführt sind.

Das hat nichts mit der Initialisierung zu tun.
Das ist der generelle Mechanismus, der einzuhalten ist, wenn Daten zum 
LCD übertragen (Write) oder vom LCD gelesen (Read) werden.
Ist wie beim Telefon: Du musst zuerst die Verbdinung herstellen und erst 
dann reden, nicht umgekehrt. Das ist beim Telefon der grundsätzliche 
Vorgang. Was du deinem Gegenüber mitteilst, ist davon unberührt.

von Jörg (Gast)


Lesenswert?

Ich habe mir verschiedensten Code angeguckt, jedoch wollte ich für den 
Anfang nur "das Nötigste" programmieren.

Für mich als Anfänger ist es noch etwas schwer durch den Code zu finden, 
wenn dieser in vielen Funktionen (mit verschiedenen Parameterübergaben) 
aufgeteilt ist.
Und ich muss jetzt feststellen, dass viel mehr code nötig ist als ich 
dachte. UND VORALLEM VERSTEHE ICH WARUM.

Ich habe noch Probleme diesen Abschnitt deines Beitrages zu verstehen:
"Entscheidend ist nur,
dass die Datenleitungen (+R/W +Command) mit dem Wechsel von E von High
auf Low übernommen werden und das E eine gewisse Mindestzeit auf High
gehalten werden muss.
"

Heisst das die Leitungen RW und RS(also Command?) sind erst HIGH und 
werden gleichzeitig mit E auf LOW gesetzt?

Und woher weiss ich wie lange ich E halten muss? Im Datenblatt steht da 
glaub ich nichts zu?

Vielen Dank, dass Ihr auf meine Anfängerfragen nicht total genervt 
reagiert.... ich merke selbst, dass die Fragen auf unterstem Niveau 
sind.

Gruß

von Karl H. (kbuchegg)


Lesenswert?

Jörg schrieb:
> Ich habe mir verschiedensten Code angeguckt, jedoch wollte ich für den
> Anfang nur "das Nötigste" programmieren.

Das ist das Problem:
Woher weißt du, was nötig ist und was Zugabe?

> Für mich als Anfänger ist es noch etwas schwer durch den Code zu finden,
> wenn dieser in vielen Funktionen (mit verschiedenen Parameterübergaben)
> aufgeteilt ist.

Dann musst du bei den einfachen Funktionen anfangen zu analysieren und 
dir merken, was sie machen. Ein gut gewählter Funktionsname hilft dabei.

Was macht ?
1
static void lcd_enable( void )
2
{
3
    LCD_PORT |= (1<<LCD_EN);     // Enable auf 1 setzen
4
    _delay_us( LCD_ENABLE_US );  // kurze Pause
5
    LCD_PORT &= ~(1<<LCD_EN);    // Enable auf 0 setzen
6
}

Aha. Das schickt einen Puls auf dem E-Pin raus. Also einmal auf 1, etwas 
warten und wieder zurück auf 0. Jetzt weißt du schon, aus dem 
Datenblatt, das du das immer brauchst, um eine Ausgabe abzuschliessen. 
Die Erwartung ist daher, dass diese Funktion wohl am Ende einer Ausgabe 
aufgerufen wird.

Schaun wir mal
1
static void lcd_out( uint8_t data )
2
{
3
    data &= 0xF0;                       // obere 4 Bit maskieren
4
 
5
    LCD_PORT &= ~(0xF0>>(4-LCD_DB));    // Maske löschen
6
    LCD_PORT |= (data>>(4-LCD_DB));     // Bits setzen
7
    lcd_enable();
8
}

Jup. Offenbar richtig. die Funktion lcd_out gibt etwas am Port aus und 
hinten nach wird der Enable Puls gesetzt. lcd_out enthält alles was 
notwendig ist um etwas an das LCD zu schicken.

Wo wird sie verwendet?
Na zb in der lcd_init. Anstelle sich in der lcd_init ständig mit den 
Port Pins rumzuschlagen, wird einfach nur lcd_out aufgerufen. lcd_out 
weiß dann schon, was da alles zu machen ist (inklusive Enable Pin 
toggeln)

> "Entscheidend ist nur,
> dass die Datenleitungen (+R/W +Command) mit dem Wechsel von E von High
> auf Low übernommen werden und das E eine gewisse Mindestzeit auf High
> gehalten werden muss.
> "
>
> Heisst das die Leitungen RW und RS(also Command?) sind erst HIGH und
> werden gleichzeitig mit E auf LOW gesetzt?


Nein
Das heisst dass du R/W und RS ebenfalls einstellen musst, bevor auf E 
der Wechsel 1 - warten - 0 erfolgt.

> Und woher weiss ich wie lange ich E halten muss?

Schau ins Timing Diagramm. Da sind Pfeile drinnen, die jeweils die 
Mindestzeiten angeben.

von Jörg (Gast)


Lesenswert?

Ich habe nun mein Progreamm noch mehrmals komplett überarbeitet.
Leider bekomme ich das Display nicht initialisiert.

Es wäre super, wenn Ihr mir sagen könntet ob mein Code jetzt richtig ist 
und ich vllt. einfach nur die falschen Kommandos zur Initialisierung 
benutze? -Aber welche sind dann richtig? - kann ich irgend etwas an den 
Fusebits falsch eingestellt haben, was nun Pins am Port D 
blockiert(durch mehrfachbelegung der pins)?

Besonders interessieren würde es mich, ob folgende Stellen korrekt sind:
1
instruction &= 0x0F;  //ändere nur unteres Nibble(DB4-DB7)
2
PORTD = instruction;   //schreibe in DB4-DB7 unteres Nibble von instruction
Und dann:
1
lcd_write_instruction(0x02);

Mit diesem Code soll an DB5(angeschlossen an PD1) eine 1 anliegen, 
während die Pins PD 4,5,6,7 unverändert bleiben.
1
#ifndef F_CPU
2
#define F_CPU 8000000UL 
3
#endif
4
5
#include <avr/io.h>
6
#include <util/delay.h>
7
8
void lcd_write_instruction(uint8_t instruction);
9
void lcd_write_data(uint8_t data);
10
void lcd_init (void); 
11
12
#define DB4    PD0
13
#define DB5    PD1
14
#define DB6    PD2
15
#define DB7    PD3
16
#define RS    PD4
17
#define RW    PD5
18
#define E    PD6
19
20
21
// ***** Hauptprogramm *****
22
int main(void){
23
//Ausgänge konfigurieren
24
DDRD = 0xff;     //D0-7 als Ausgänge
25
PORTD = 0x00;    //Ausgänge auf 0
26
27
_delay_ms (150);   // wait min 15 mSec. after Power ON
28
lcd_init ();       // Display initialisieren
29
                       
30
while(1);
31
32
}
33
34
void lcd_write_instruction(uint8_t instruction)
35
{
36
37
PORTD &= ~(1<<RS);      //RS=0
38
PORTD &= ~(1<<RW);    //RW=0
39
_delay_us (0.06);    //60ns(tSU1) warten
40
PORTD |= (1<<E);    //E=1
41
_delay_us (0.255);    //warte 255ns (450ns(tW)-195ns(tSU2))
42
43
instruction &= 0x0F;  //ändere nur unteres Nibble(DB4-DB7)
44
PORTD = instruction;   //schreibe in DB4-DB74 unteres Nibble von instruction
45
46
_delay_us (0.195);     //warte 195ns(tSU2)
47
PORTD &= ~(1<<E);    //E=0
48
_delay_us (0.01);     //warte 10ns(tH2)
49
_delay_us (0.5);    //warte 500ns (1000-(10+450+40)
50
}
51
52
void lcd_write_data(uint8_t data)
53
{
54
PORTD |= (1<<RS);    //RS=1
55
PORTD &= ~(1<<RW);    //RW=0
56
_delay_us (0.06);    //60ns(tSU1) warten
57
PORTD |= (1<<E);    //E=1
58
_delay_us (0.255);    //warte 255ns (450ns(tW)-195ns(tSU2))
59
60
data &= 0x0F;      //ändere nur unteres Nibble(DB4-DB7)
61
PORTD = data;       //schreibe in DB4-DB7 unteres Nibble von data
62
63
_delay_us (0.195);     //warte 195ns(tSU2)
64
PORTD &= ~(1<<E);    //E=0
65
_delay_us (0.01);     //warte 10ns(tH2)
66
_delay_us (0.5);    //warte 500ns (1000-(10+450+40)
67
}
68
69
void lcd_init( void )
70
{
71
//Power-ON
72
_delay_ms(30);
73
74
//Funktion Set
75
lcd_write_instruction(0x02);
76
lcd_write_instruction(0x02);
77
lcd_write_instruction(0x0E);
78
79
_delay_us(40);
80
//Display on/off Control
81
lcd_write_instruction(0x00);
82
lcd_write_instruction(0x0F);
83
84
_delay_us(40);
85
//Display Clear
86
lcd_write_instruction(0x00);
87
lcd_write_instruction(0x01);
88
89
_delay_ms(2);
90
//Entry Mode set
91
lcd_write_instruction(0x00);
92
lcd_write_instruction(0x06);
93
}

von Karl H. (kbuchegg)


Lesenswert?

Jörg schrieb:

> void lcd_write_instruction(uint8_t instruction)
> {
>
> PORTD &= ~(1<<RS);      //RS=0
> PORTD &= ~(1<<RW);    //RW=0
> _delay_us (0.06);    //60ns(tSU1) warten
> PORTD |= (1<<E);    //E=1
> _delay_us (0.255);    //warte 255ns (450ns(tW)-195ns(tSU2))
>
> instruction &= 0x0F;  //ändere nur unteres Nibble(DB4-DB7)
> PORTD = instruction;   //schreibe in DB4-DB74 unteres Nibble von
> instruction

Damit ist dann die ganze schöne Einstellung, die du vorher für RS, RW 
und E gemacht hast, zur Geschichte geworden. Gone with the wind

RS und RW sind hier noch egal, weil sie sowieso 0 sind. Aber E ist nicht 
egal


> void lcd_write_data(uint8_t data)
> {
> PORTD |= (1<<RS);    //RS=1
> PORTD &= ~(1<<RW);    //RW=0
> _delay_us (0.06);    //60ns(tSU1) warten
> PORTD |= (1<<E);    //E=1
> _delay_us (0.255);    //warte 255ns (450ns(tW)-195ns(tSU2))
>
> data &= 0x0F;      //ändere nur unteres Nibble(DB4-DB7)
> PORTD = data;       //schreibe in DB4-DB7 unteres Nibble von data

... während hier dann auch das RS Bit auch noch gelöscht wurde


Schluck deinen Stolz runter und hol dir die LCD Routinen aus dem 
Tutorial. Überpüf noch, ob die Initialisierung die Bytes schickt, die 
bei dir laut Datenblatt vorgeschrieben sind und bring es erst mal zum 
Laufen. Und dann studierst du den Tuorialcode im Detail.

Ich weiß schon, du willst das alles selbst schreiben, bla bla bal ... 
und überhaupt. Aber solange dir solche läppischen Fehler passieren, bist 
du einfach noch nicht soweit mehrer Leitungen simultan zu bedienen ohne 
dass du ungewollt durch die Manipulation einer Leitung eine andere 
irrtümlich veränderst ohne es zu merken. Ist nicht weiter schlimm, das 
wird schon werden. Aber ein LCD ist ein denkbar ungeeignetes und 
frustrierendes Objekt, um sich daran zu versuchen.

von holger (Gast)


Lesenswert?

>data &= 0x0F;      //ändere nur unteres Nibble(DB4-DB7)
>PORTD = data;       //schreibe in DB4-DB7 unteres Nibble von data

Und was ist mit dem oberen Nibble von data?
Willst du das nicht senden? Das musst du aber!

von Jörg (Gast)


Lesenswert?

Es müsste also so lauten: ?
1
while(1);
2
}
3
4
void lcd_write_instruction(uint8_t instruction)
5
{
6
7
PORTD &= ~(1<<RS);      //RS=0
8
PORTD &= ~(1<<RW);    //RW=0
9
_delay_us (0.06);    //60ns(tSU1) warten
10
PORTD |= (1<<E);    //E=1
11
_delay_us (0.255);    //warte 255ns (450ns(tW)-195ns(tSU2))
12
13
PORTD |= instruction;   //schreibe in DB1-DB4 unteres Nibble von instruction
14
15
_delay_us (0.195);     //warte 195ns(tSU2)
16
PORTD &= ~(1<<E);    //E=0
17
_delay_us (0.01);     //warte 10ns(tH2)
18
_delay_us (0.5);    //warte 500ns (1000-(10+450+40)
19
}
20
21
void lcd_init( void )
22
{
23
24
//Power-ON
25
_delay_ms(30);
26
27
//Funktion Set
28
lcd_write_instruction(0x02);
29
lcd_write_instruction(0x02);
30
lcd_write_instruction(0x0E);
31
32
_delay_us(40);
33
//Display on/off Control
34
lcd_write_instruction(0x00);
35
lcd_write_instruction(0x0F);
36
37
_delay_us(40);
38
//Display Clear
39
lcd_write_instruction(0x00);
40
lcd_write_instruction(0x01);
41
42
_delay_ms(2);
43
//Entry Mode set
44
lcd_write_instruction(0x00);
45
lcd_write_instruction(0x06);
46
}

Ich habe den code aus dem Tut auch nciht zum funktionieren bekommen ...

Danke für eure Gedult

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.