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
voidLCD_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
voidmain(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.
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.
>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.
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.
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
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.
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.
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
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)?
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.
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.
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:
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!!
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
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.....
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.
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.
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.
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!