Forum: Mikrocontroller und Digitale Elektronik LCD Ansteuerung (EIGENE INIT)


von Patrick N. (petzibaer69)


Angehängte Dateien:

Lesenswert?

Guten Morgen,

ich habe, wie so viele, Schwierigkeiten mit der Initialisierung eines 
LC-Displays ( Displaytech 162 ). Das Display ist wie auf dem Schaltplan 
mit dem µC verbunden. Die Hintergrundbeleuchtung funktioniert, ebendso 
der Kontrast.
Nun zeigt mir das Display 16 "Kästen" in der zweiten Zeile an. Woraus 
ich schließe, dass das Display funktioniert und nun einzeilig 
konfiguriert ist.
Soweit so gut.
Allerdings möchte ich es nun initialisieren für meine Bedürfnisse. Das 
heißt dann zwei Zeilen, 4 Bit Datenbus...
Ich habe jetzt genügend Threads gelesen, in denen die vorgefertigten 
Dateien benutzt werden. Ich will es aber gerne selber schreiben, damit 
ich mich selber besser dran tasten kann, weil ich im Moment nicht der 
erfahrenste programmmierer bin. Soll heißen 'learning by doing'.

Ich benutze MPLAB mit dem C18 Compiler.

folgendermaßen sieht es nun bei mir aus.
1
void LCD_INIT(void){
2
   
3
  LCD_RS = 0;              
4
  LCD_RW = 0;
5
  LCD_EN = 0; 
6
  DelayMS(15);
7
     
8
  PORTB = 0x30;  //8-Bit
9
  LCD_E = 1;              
10
  LCD_E = 0;              
11
  DelayMS(4.5);            
12
  
13
  LCD_EN = 1;  //8-Bit (toggeln mit enable)            
14
  LCD_EN = 0;              
15
  DelayMS(1);            
16
17
  LCD_EN = 1;  //8-Bit (toggeln mit enable)            
18
  LCD_EN = 0;              
19
20
  DelayMS(5);  //warten bis Display fertig            
21
              
22
  PORTB = 0x10;  //Display ausschalten
23
  LCD_EN = 1;              
24
  LCD_EN = 0;
25
26
  PORTB = 0x82  // 4 Bit, 2 Zeilen, 5x7
27
  LCD_EN = 1;              
28
  LCD_EN = 0;
29
30
  PORTB = 0x80;  // Display aus, Cursor aus, Blinken aus
31
  LCD_EN = 1;              
32
  LCD_EN = 0;
33
  
34
  PORTB = 0x60;  //Shift aus
35
  LCD_EN = 1;              
36
  LCD_EN = 0;
37
38
  PORTB = 0xC0;  // Display an
39
  LCD_EN = 1;              
40
  LCD_EN = 0;
41
  }
42
43
...
44
45
void main (void){
46
47
....
48
49
LCD_INIT();
50
51
}

Wenn es jetzt richtig wäre, müsste im Display nun die Reihe mit den 
Balken verschwinden, tut sie aber nicht. Nur wo ist an der Stelle der 
Fehler?
Das man das ganze mit den fertigen Dateien wesentlich kürzer und 
einfacher machen kann ist mir wohl bewusst, aber wie gesagt, es geht mir 
darum das ich mich selber gut reinfinden kann.

von Bastler (Gast)


Lesenswert?

Wenn's nur eine Zeile schwarze Kästchen zeigt, ist es nicht (richtig) 
initialisiert. Warum nicht vorher mal einen LCD Artikel lesen. Andere 
haben sich damit schon ausgiebig beschäftigt.

von dummy (Gast)


Lesenswert?

>Das man das ganze mit den fertigen Dateien wesentlich kürzer und
>einfacher machen kann ist mir wohl bewusst, aber wie gesagt, es geht mir
>darum das ich mich selber gut reinfinden kann.

Du darfst dir die Codes zum vergleichen mit deinem Code aber ansehen.
Oder kannst du das nicht?

Schau dir die 100000 Threads zu "LCD geht nicht" an.
Dort werden alle deine Fragen beantwortet. Auch die die
du noch nicht gestellt hast.

So langsam hat keiner mehr Lust den 100001 zu beantworten.

von Teo D. (teoderix)


Lesenswert?

Der Enable Pin sollte min. 500ns Hi sein!

von Rainer U. (r-u)


Lesenswert?

Patrick N. schrieb:
> Nun zeigt mir das Display 16 "Kästen" in der zweiten Zeile an.

Dann steht es "auf dem Kopf" :-)

Patrick N. schrieb:
> Woraus
> ich schließe, dass das Display funktioniert und nun einzeilig
> konfiguriert ist.

Das machen die Displays so beim Anlegen der Betriebsspannung, hat nichts 
mit einzeilig zu tun - damit Du den Kontrast einstellen kannst und sehen 
kannst, dass es heil ist.


Funktioniert es denn, wenn Du die Standard-Routinen verwendest (von 
denen Du gelesen hast)

Patrick N. schrieb:
> PORTB = 0x30;  //8-Bit
>   LCD_E = 1;
>   LCD_E = 0;
>   DelayMS(4.5);

Da wäre noch das timing zu hinterfragen - wie lange ist hier Enable 
gesetzt? lange genug?


Also mein Tip: Bring erstmal die (fertigen, getesteten) 
Standard-Routinen in Gang.

von Patrick N. (petzibaer69)


Lesenswert?

Rainer Unsinn schrieb:
> Da wäre noch das timing zu hinterfragen - wie lange ist hier Enable
> gesetzt? lange genug?

An dem timing liegt es nicht. Da ist genug Zeit, damit das Display 
arbeiten kann.

Rainer Unsinn schrieb:
> Also mein Tip: Bring erstmal die (fertigen, getesteten)
Standard-Routinen in Gang.

Der Tipp ist ansich nicht schwer. Damit würde ich es sofort versuchen 
wollen. Das Problem liegt bei mir nur darin, dass ich mit einem PIC und 
MPLAB (C18 Compiler) arbeite. Die meisten Codes sind für AVR und 
Assembler geschrieben. Mir fällt es z.Z. etwas schwer das dann zu 
übersetzen und für meinen Aufbau anzupassen.

Daher wollte ich wissen, ob generell etwas gegen meinen Code spricht 
oder ob der Aufbau an sich richtig ist.
Wo ich mir z.B. nicht sicher war, war der Enabele-Pin. Muss der jedes 
mal von High auf Low bzw. umgekehrt gesetzt werden oder müssen einfach 
die Befehle nach und nach an das Display geschickt werden?
Laut Datenblatt würde ich es so verstehen, dass es ohne den Enable-Pin 
initialisiert werden kann. In anderen Berichten habe ich es dann auch 
teilweise ohne sowie mit gesehen.

Und meine Frage, bezüglich des Displays nach dem initialisieren, ist 
noch nicht beantwortet worden. Sollte alles richtig ablaufen müssen alle 
Balken weg sein, richtig?

Mfg Patrick

von Chris B. (dekatz)


Lesenswert?

Patrick N. schrieb:
> Das Problem liegt bei mir nur darin, dass ich mit einem PIC und
> MPLAB (C18 Compiler) arbeite. Die meisten Codes sind für AVR und
> Assembler geschrieben. Mir fällt es z.Z. etwas schwer das dann zu
> übersetzen und für meinen Aufbau anzupassen.
>

Hier:

http://www.sprut.de/electronic/lcd/index.htm

findest du ein ASM-Beispiel für PIC welches man leicht auf C umsetzen 
kann.

Die LcdInit besteht eh fast nur aus Transferbefehlen von Daten an PORTB.
In <OutLcdDaten> und <OutLcdControl> findest du das Handling der E/RW/RS 
Leitungen. (<bsf> setz einen Pin auf HIGH, <bcf> auf LOW) und der <swap> 
Befehl vertausch oberes mit unteren Nibble eines Byte, der Rest der 
ASM-Befehle im Datenblatt deines Controllers).
Delay-Anweisung hast du ohnehin in C auch zur Verfügung und auf die 
Abfrage des BUSY-Flags kann man notfalls verzichten und ein Delay mit 
1ms (oder weniger) einfügen.

von c-hater (Gast)


Lesenswert?

Patrick N. schrieb:

> Wo ich mir z.B. nicht sicher war, war der Enabele-Pin. Muss der jedes
> mal von High auf Low bzw. umgekehrt gesetzt werden

Schon die Frage ist falsch. Genau dieses "jedesmal" ist einer der 
Knackpunkte in der Initialisierungsphase für den 4Bit-Modus, was 
"jedesmal" bedeutet, ändert sich nämlich im Verlauf der Initialisierung, 
weil die ersten Kommandos noch als 8Bit-Kommandos auszugeben sind (auch 
wenn das Display nur die oberen 4Bit davon zu sehen bekommt).

Der andere Knackpunkt ist das Timing, das allerdings unabhängig davon, 
ob für den 4Bit-Modus oder für den 8Bit-Modus initialisiert wird.

> Laut Datenblatt würde ich es so verstehen, dass es ohne den Enable-Pin
> initialisiert werden kann.

Das ganz sicher niemals. Ohne Enable-Pin geht garnix, deswegen auch der 
Name.

Erst das Signalspiel an Enable bringt das Display dazu, die anderen 
Signale überhaupt wahrzunehmen. Solange an Enable nix passiert, können 
die anderen Signale wackeln wie sie wollen, das ist dem Display völlig 
scheißegal.

> In anderen Berichten habe ich es dann auch
> teilweise ohne sowie mit gesehen.

Das glaube ich nicht. Wo willst du ein Beispiel für einen 
funktionierenden Code gesehen haben, der ohne Enable auskommt?

> Und meine Frage, bezüglich des Displays nach dem initialisieren, ist
> noch nicht beantwortet worden. Sollte alles richtig ablaufen müssen alle
> Balken weg sein, richtig?

Nach der korrekten Initialisierung ist das Display entweder vollkommen 
leer oder man sieht den Cursor. Je nachdem, ob man selbigen in der 
Initialisierung ein- oder ausgeschaltet hat. Da der Cursor aber auch als 
Blockcursor erscheinen kann, wenn man ihn entsprechend konfiguriert, 
kann es also sein, daß nach der Initialisierung ein "Balken" überbleibt, 
das ist dann eben der Cursor.

von Display user (Gast)


Angehängte Dateien:

Lesenswert?

In deiner Init benutzt du zuerst LCD_E und danach LCD_EN.

warum das?

und warum schaltest du weiter unten das Display aus?


Eine funktionierende Init für ein 2x8 Display sieht z.B. so aus:

8Bit
  0x30
  0x30
  0x30
  0x20

4Bit
  0x20  (0x28) ; Function Set: 4Bit, zweizeilig, 5x8 Font
  0x80
  0x00  (0x01) ; Clear Display
  0x10
  0x00  (0x0F) ; Display On, Cursor On, Cursor blinkt
  0xF0
  0x00  (0x06) ; Entry Mode: Cursor nach rechts, kein Displayshift
  0x60

von Rainer U. (r-u)


Lesenswert?

Patrick N. schrieb:
> An dem timing liegt es nicht. Da ist genug Zeit, damit das Display
> arbeiten kann.

Was soll der Geiz - bau doch ruhig eine Verzögerung von 2ms ein nach dem 
setzen von Enable (nur zum Test) - dann bist Du auf der sicheren Seite.

Ich würde noch eine einfach Übung versuchen (ruhig 8 Datenleitungen 
benutzen auf einem Steckbrett): Beschreibe eine Adresse vom LCD mit 
einem Byte Deiner Wahl, und dann lies die gleiche Adresse wieder aus.

Ich bin nicht 100% sicher, ob das geht, aber wozu hat man sonst eine 
Möglichkeit zum Lesen (read)?

von Max H. (hartl192)


Angehängte Dateien:

Lesenswert?

Patrick N. schrieb:
> folgendermaßen sieht es nun bei mir aus...
Das funktioniert so vllt im 8bit Modus, im 4bit aber sicher nicht. 
Erstens wird das Display nicht in den 4bit Modus umgeschaltet und 
zweiten müssen die Befehle danach in zweit Teilen gesendet werden (High 
Nibble; Enable; Low Nibble; Enable; Delay)

Ich habe es immer so wie im Anhang initialisiert und hatte nie Probleme.

: Bearbeitet durch User
von Peter D. (peda)


Lesenswert?

Patrick N. schrieb:
> Die meisten Codes sind für AVR und
> Assembler geschrieben. Mir fällt es z.Z. etwas schwer das dann zu
> übersetzen und für meinen Aufbau anzupassen.

Es gibt auch narrensichere Beispiele in C:

http://www.avrfreaks.net/index.php?name=PNphpBB2&file=viewtopic&t=102296

Die Anpassung an den PIC sollte kein Problem sein.

von Patrick (Gast)


Lesenswert?

Max H. schrieb:
> Ich habe es immer so wie im Anhang initialisiert und hatte nie Probleme.

Das ist der Hinweis der mir gefehlt hatt, weil ich mich die ganze Zeit 
gefragt habe, wieso ich nicht bei dem Teil mit den High- und Low-Nibble 
ankomme. Habe da wohl was falsch interpretiert.
Versuche es dann mal auf die schnelle so wie es in dem Anhang steht, 
sobald ich weiß wie ich in C in die beiden Teile aufteile.
Vielen Dank schon mal bis hier her.

von Patrick (Gast)


Lesenswert?

So, nach stunden langen Versuchen und hin und her funktioniert es 
endlich. Das Display lässt sich jetzt auch problemlos beschreiben. Es 
hat die ganze Zeit an der Maskierung für die Datenleitung gehapert. 
Letzendlich habe ich die Bits zum initialisieren einzeln an das Display 
gesendet, ohne die Steuerleitungen zu beeinflussen. Also Enable 
unabhängig angesteuert.

Ich wüsste nun allerdings schon gaz gerne wo bei mir der Fehler ist, 
wenn ich versuche mit Maskierung zu arbeiten, oder ob es sogar schon 
bekannte Probleme mit Maskierungen und MPLAB C18 bzw PIC-Controllern 
(PIC18F2420) gibt.

So sah es bei mir aus:
1
    PORTB &= 0x0F;
2
    Toggle();
3
    PORTB |= 0x30;
4
    Toggle();
5
6
...

Jetzt habe ich es so gelöst:
1
#define LCD_7    PORTBbits.RB7
2
#define LCD_6    PORTBbits.RB6
3
#define LCD_5    PORTBbits.RB5
4
#define LCD_4    PORTBbits.RB4
5
#define LCD_EN    PORTBbits.RB3
6
#define LCD_RW    PORTBbits.RB2
7
#define LCD_RS    PORTBbits.RB1
8
9
[...]
10
11
    Delay10KTCYx(10);
12
    LCD_7 = 0;
13
    LCD_6 = 0;
14
    LCD_5 = 1;
15
    LCD_4 = 1;
16
    Toggle();


Mfg Patrick

von Chris B. (dekatz)


Lesenswert?

Patrick schrieb:
>     PORTB &= 0x0F;
>     Toggle();
>     PORTB |= 0x30;
>     Toggle();
>
> ...
Was machte den <Toggle()> zwischen den Verknüpfungen?

Und da du einen PIC18 verwendest sollst du auch nicht direkt in das 
PORTx-Register schreiben , sondern in das entsprechende LATx-Register. 
Nur beim Lesezugriff auf einen Port verwendet man die PORTx-Register.
Stichwort: Read-Modify-Write Problem!!

von Patrick (Gast)


Lesenswert?

Chris B. schrieb:
> Was machte den <Toggle()> zwischen den Verknüpfungen?

Stimmt, das habe ich nicht erläutert. Durch die Funktion wird Enable 
getogglt. Habe in der Funktion aber auch nen Delay gesetzt.

Den Unterschied mit PORTx und LATx habe ich total vernachlässigt. Kommt 
davon wenn man hier tagelang nicht vorran kommt und sämtliche Sachen im 
Kopf hat. Da geht das schon mal verloren. Ich versuche es dann gleich 
mal mit LATx.

Danke

von Chris B. (dekatz)


Lesenswert?

Patrick schrieb:
> Chris B. schrieb:
>> Was machte den <Toggle()> zwischen den Verknüpfungen?
>
> Stimmt, das habe ich nicht erläutert. Durch die Funktion wird Enable
> getogglt. Habe in der Funktion aber auch nen Delay gesetzt.

Unnötig bzw. falsch!

Und die Verknüpfung geht in einem Zug:
PORTB = (PORTB & 0x0F) | 0x30
Nur eben mit LATB.....

von Peter D. (peda)


Lesenswert?

Patrick schrieb:
> Es
> hat die ganze Zeit an der Maskierung für die Datenleitung gehapert.

Das ist auch zu 99,9% die Fehlerursache der anderen Anfänger.

Aber warum sich mit sowas überhaupt rumplagen?
Wenn Dein Compiler Bitzugriffe kann, dann nimm diese.
Gut, dann wird die Sende-Nibble Funktion einen Tick aufwendiger, aber 
man muß sie ja nur ein einziges mal schreiben. Sämtliche anderen 
Codeteile rufen sie nur auf.

Ich verstehe nicht, warum Anfänger ihren Code immer so unnötig 
kompliziert machen müssen. Das LCD ist doch ein schönes Beispiel, wie 
man höhere Funktionen auf einfache Funktionen aufbauen kann.

von Max H. (hartl192)


Lesenswert?

Peter Dannegger schrieb:
> Wenn Dein Compiler Bitzugriffe kann, dann nimm diese.
Dann hättest du auch den Vorteil, dass die Routine wenn du die Defines 
änderst an allen IOs verwendet werden kann und nicht nur wenn die 
Datenleitungen an PORTx<4:7> angeschlossen sind. Genau us diesem Grund 
habe ich nicht bei meiner Routine für den Bitzugriff entschieden.

: Bearbeitet durch User
von Uwe (de0508)


Lesenswert?

Hallo Patrick,

Du müsstest Dir erst mal ein Datenblatt deines Display laden und Dir die 
Zustandsdiagramme bzgl. den Steuer- und Datenleitungen ansehen.

Hier hapert es noch im Verständnis der EN Steuerleitung.

Der C-Code
http://www.avrfreaks.net/index.php?name=PNphpBB2&file=viewtopic&t=102296
zeigt doch sehr schön, wie man es in C programmieren kann.

Kopiere dies doch einfach und passe es dann an deine Umgebung ab.

von c-hater (Gast)


Lesenswert?

Peter Dannegger schrieb:

> Ich verstehe nicht, warum Anfänger ihren Code immer so unnötig
> kompliziert machen müssen.

Weil sie halt Anfänger sind und ihnen damit zwangsläufig der Überblick 
fehlt. Das ist nix schlimmes.

Viel schlimmer sind meiner Meinung nach Typen, die seit einem 
Vierteljahrhundert oder so programmieren, denen aber immer noch der 
Überblick fehlt. Also z.B. solche, die vollkommen überfordert sind, wenn 
sie mal in einer Sprache programmieren (oder debuggen) müssen, die sie 
nicht selber tagtäglich benutzen.

Sowas finde ich viel tragischer. Das sind dann keine Anfänger, sondern 
vollständig verblödete Fachidioten. Komischerweise sind die nach meiner 
Erfahrung ausschließlich im Lager der C-rules-the-world-Verfechter zu 
finden. Die halten ihren verschissenen aufgedonnerten Macro-Assembler 
doch tatsächlich fast für Gottes Eigenes Gebot und die ultima ratio des 
Programmierens und sich selber für die die einzig wahren Propheten 
dieses Gottes.

Arme Irre!

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.