Hallo, ich habe hier ein LCD mit einem 44780 und mit 2*40 Reihen, was ich nicht initalisiert bekomme. Ein Handbuch hab ich dazu nicht. Das Display funktioniert einwandfrei in einer anderen Schaltung, die ich so übernommen habe und auch past. Der µ-Controller wird 1-2min nach dem Display eingeschaltet, dort gibt es also keine Timing Probleme. Der µ-Controller ist ein 89C51RE2 von Atmel und ich verwende die freie Version von Keil uVison3 bis 2kb Code. Hab versucht mich an den Sachen von folgenden links zu orientieren: Beitrag "LCD - Ansteuerung" http://www.sprut.de/electronic/lcd/index.htm#strom So nun zu meinem Code: //hier beginnt die Initalierung des LCD: disp_RS=0; disp_out(0x38,45); disp_out(0x38,15); disp_out(0x38,15); disp_out(0x0e,15); disp_out(0x01,15); disp_out(0x06,15); //hier die Funktion disp_out: void disp_out(unsigned char p, unsigned char t) { disp_EN=0; disp_port=p; disp_EN=1; disp_EN=0; zeit=t; while(zeit) { } } //Die variable zeit wird im timer0 decrementiert. //Hier das Init vom Timer: //timer0 16bit zähler TMOD=0x021; //timer0 für interrupt alle 0,333ms TH0 =0x0E8; TL0 =0x006; TR0 =1; ET0 und EA werden später gesetzt. Nach meiner Rechnung müßte der alle 0,33ms kommen. Ich verwende einen 18.432Mhz Quarz und der µ-Controller braucht 6takte pro Befehl. R/W vom Display liegt an GND. Geht auch leider nicht anders. Am Kontrast hab ich auch schon gedreht und ich kann mit einem Oszilloskop sehen wie die Befehle an den Pins des 44870 ankommen. Jedenfalls son zucken :) Die variable zeit hab ich auch schonmal höher und kleiner gemacht, hat nicht viel gebracht. Jetzt weiß ich echt nicht mehr weiter. Wo liegt mein Fehler? Sehe mittlerweile auch den Wald vor lauter Bäumen nicht mehr...
1. bitte kompletten (relevanten) Code posten 2. bitte kompletten (relevanten) Code mit Kommentaren posten Siehst du denn bei der Kontrastregelung einen Effekt? Stell den Kontrast zu Beginn ziemlich hart ein. Nach einem Reset ist normalerweise immer eine Zeile dunkel. Nach den Initialisierungsbefehlen verschwindet die dunkle Zeile. Wenn du also den Kontrast sichtbar einstellen kannst, die dunkle Zeile nach dem Einschalten erscheint und nach der Initialisierung verschwindet, bist du fast fertig. Also wie weit kommst du? Ralf
> Der µ-Controller wird 1-2min nach dem Display eingeschaltet, dort gibt > es also keine Timing Probleme. Schon das könnte ein Timingproblem sein. > Sehe mittlerweile auch den Wald vor lauter Bäumen nicht mehr... Teile und herrsche. Ja, wie wäre es denn, wenn du erst mal deinen Timer kontrollierst? Einfach im Interrupt einen Pin toggeln und kontrollieren, ob die Zeit zu deinen erwarteten 330us passt. BTW: Dir ist klar, dass du hier ein Semaphorenproblem bekommen kannst: disp_EN=0; disp_port=p; disp_EN=1; disp_EN=0; zeit=t; while(zeit) { } Während der Zuweisung von zeit solltest du den Interrupt sperren...
Versuch erstmal das Display ganz ohne Timer mit reichlich dimensionierten Warteschleifen zum laufen zu bringen. Als Anlage ein C-Programm, was bei mir auf AT89C51ED2 läuft. Zwar für SDCC, aber leicht an Keil anzupassen.
@Ralf Das ist (fast) mein kompleter C-Code. Alles andere hab ich mittlerweile rausgeworfen. Und was soll ich da noch mehr Kommentieren? Denn Kontrast kann ich so einstellen das nur die untere Reihe da ist. Die bleibt aber auch. Da passiert nix. @Lothar Wiso könnte da ein Problem sein wenn der µ-Controller so lange nach dem LCD angeht? Das mit dem PIN ist eine gute Idee. Werde ich mal ausprobieren. Und stimmt, das mit zeit hab ich so noch gar nicht gesehen - danke :) @Matthias Das mit den Schleifen hab ich auch schon ausprobiert. Hab ich damit auch nicht so hinbekommen und da ich nicht so richtig wußte wie lange so eine Schleife dauert, hab ichs jetzt so probiert. Werde mir das Stück C-Code morgen mal genauer angucken. Danke erstmal für die Hilfe
Hallo, folgende Fragen: a) wie wird disp_EN initialisiert (mindestens 15 ms vor dem ersten Aufruf von disp_out) üblicherweise ist nach dem Reset alles auf High-pegel beim 8031. Dies würde also eine Timing-Verletzung bedeuten. b) wird im Interrupt das Interrupt-Flag des Timers zurückgesetzt? (oder wird der Timer-Interrupt als Endlosschleife durchlaufen). c) Bist Du dir sicher ob der Enable-Impuls lang genug ist? Ich kann mich dunkel erinnern daß die Maximalfrequenz für einen sichern Betrieb eines LCD bei ca 11 MHz Prozessortakt liegt. (Ich weiß allerdings nicht mehr ob dies nur für den Betrieb am Datenbus gilt oder auch am I/O-Port).
Hallo nochmal... hab gerade mal den Tip von Lothar probiert und den Timer-Takt auf einen Pin gelegt. Da hab ich festgestellt das mein Timmer alle 0,4s kommt. Egal was ich in TH0 und TL0 einstelle. Ist also ein Timer Problem. Es ist egal ob in TH0 0xFF oder 0x00 steht immer sind es 0,4s, dann kann es ja auch nicht funktioneren... Hat jemand eine idee warum? Eigentlich müßte Timer0 doch richtig eingestellt sein? Hab mal meinen ganzen Code angehängt.
Du kannst es alternativ mal mit den fertigen Codebeispielen von Meba probieren. Ich benutze die schon seit Jahren und sie funktionieren problemlos. Der Code ist in ASM und C geschrieben für 8051 kompatible Controller und Keil-uVision Umgebung. Sämtlichen LCD-Code bekommst du auf seiner Homepage unter: http://www.c51.de/c51.de/Dateien/c51_buecher.php?Korb=1&UIN= Dort dann den Link "Buch_PraxisTeil2_Kap7.ZIP" herunterladen. Dort ist Code für 8Bit und 4Bit Ansteuerung drin. Und du bekommst auf seiner Homepage auch ein Plugin für uVision, welches genau diese LCDs simuliert, womit du deinen Code rein am PC schon testen kannst. Demoversion Erhältlich unter: http://www.c51.de/c51.de/Dateien/LCD.php?UIN= Dort dann den Link "lcd.zip" herunterladen. Die Demoversion ist schon ausreichend um das LCD im 4Bit Modus komplett zu simulieren. Funktioniert ebenfalls wunderbar bei mir. :) Ciao, Rainer
>Da hab ich festgestellt das mein Timmer alle 0,4s kommt. Egal was ich in >TH0 und TL0 einstelle. Wenn Du Dir mein Bsp. weiter oben mal genauer angesehen hättest, besonderes die TIMER0ISR, dann wär Dir aufgefallen, dass TH0 und TL0 in der ISR jedesmal nachgeladen wird um den Zählumfang des Timers zu verkürzen. Du machst das nicht, somit läuft Dein Zähler immer von 0x0000 bis 0xFFFF. Damit dürften die 400ms zu erklären sein. Insgesamt sollte sich das LCD nicht an so langen Pausen stören, die Ausgabe würde nur entsprechend in Zeitlupe erfolgen.
Also du hast in deinem Code schonmal einen grundlegenden Denkfehler drin. Der Timer0 arbeitet als 16Bit Timer, besitzt aber keine auto-reload Funktionn in diesem Modus. Du initialisierst zu Beginn in deiner init() Methode die Timer Register mit TH0=0x0FF und TL0=0x000 (wieso überhaupt dreistellige Hex Zahlen, es sind ja nur 8Bit Register). Das heißt, der Timer läuft das erste mal auch vom richtigen Startwert los. Aber sobald er einmal übergelaufen ist startet er wieder bei 0x0000. Du mußt also in der ISR des Timer0 die Register TH0 und TL0 immer wieder neu mit deinen Reload Werten befüllen, wenn du den gewünschten Effekt erreichen willst. Mit deinem jetzigen Code wird bei 18.432MHz und Standardeinstellungen alle ~42,6ms der Portpin umgeschaltet (wegen dem fehlenden Reload). Deine 0,4s sind für mich nicht nachvollziehbar. Um ehrlich zu sein, finde ich dein Herangehensweise im Code um das LCD anzusteuern etwas merkwürdig. Ich würde deshalb erst mal versuchen funktionierenden LCD Code zu benutzen um Softwarefehler auszuschließen. Und falls das LCD damit funktioniert kannst du dich an eine eigene Implementierung wagen. :) Ciao, Rainer
Ahh jetzt verstehe ich das mit dem 16Bit timer. Dachte das wäre wie mit dem 8Bit timer. @MAtthias Ja hab ich jetzt auch gesehen. Muß aber gestehen das ich deinen Code nicht verstehe. Bin noch C anfänger. @Fox Mulder ich wußte gar nicht das es sowas schon so komplet fertig gibt. Dacht bis jetzt immer das man sich sowas immer selber schreibt. Mach das ganze hier auch komplet autodidaktisch. Hab mit µ-Controllern noch nie richtig was zu tun gehabt - studier Maschinbau. Wie binde ich das denn jetzt richtig ein? Hab die LCD_Lib_8BitPort.h eingebunden. Beim Aufruf der Funktion uc_LCDIni(_8BIT | _2LINE) bekomme ich vom Compiler zwar keine fehlermeldung im Debugger sehe ich aber auch keine Änderung des Ausgangsport. Die Pin belegung hab ich in der .a51 angepast. Ist das so alles richtig? Was macht so eine .a51?
A51 steht für assembler Dateien. Denn die eigentliche Ansteuerung ist aus Effizienzgründen in Assembler geschrieben. Du bruchst zum Einbinden in dein Projekt nur die zwei Dateien LCD_Lib_4BitPort.h und LCD_Lib_4BitPort.a51. In der Header Datei (*.h) stehen die gesamten Definitionen für die LCD Bibliothek drin. Im Normalfall brauchst du dort nur den Eintrag "#define LCD_PORT P1" auf den von dir verwendeten Port abzuändern (z.B. P0, P1, P2, ...). In der .a51 Datei brauchst du dann keine Änderungen vorzunehmen. Standardmäßig wird der Port dann wie folgt mit dem LCD verbunden: LCD_EN = LCD_PORT.0; LCD_RW = LCD_PORT.1; LCD_RS = LCD_PORT.2; LCD_D0 = LCD_PORT.4; LCD_D1 = LCD_PORT.5; LCD_D2 = LCD_PORT.6; LCD_D3 = LCD_PORT.7; Falls dir diese Anordnung nicht passen sollte, dann kannst du in der LCD_Lib_4BitPort.a51 die sbit Definitionen von Hand anpassen. Um nun die Bibliothek zu verwenden musst du zu Beginn die Header Datei in dein Projekt einbinden mit #include <LCD_Lib_4BitPort.h> Dadurch stehen dann automatisch alle LCD Funktionen zur Verfügung. Nun musst du das LCD initialisieren in deinem Programm. Das machst du z.B. mit // 4Bit Modus, 2 oder mehr Zeilen uc_LCDIni(_4BIT | _2LINE); // Cursor ausgeschaltet und nicht blinken, LCD eingeschaltet v_SETLCDIns(CONTROL | CURSOR_OFF | NO_BLINK | DISPLAY_ON); Nun kannst du den nicht mehr sichtbaren Cursor auf dem Display an eine gewünschte Position verschieben mit // Cursor in Zeile 1 Spalte 10 v_SETLCDIns(SET_DD_RAM | (_1_LINE + 10)); Und zu guter letzt kannst du dann ein Zeichen ausgeben an dieser Stelle mit // Zeichen 'x' auf dem LCD ausgeben putchar('x'); Es stehen auch noch weitere Konfigurationsparameter zur Verfügung. Z.B. kannst du einstellen, daß die Zeichen von rechts nach links ausgegeben werden sollen mit // Automatische Adressweiterschaltung dekrementieren v_SETLCDIns(ENTRY | DECREMENT); Das LCD hat intern eine automatische Adressweiterschaltung, weshalb du nicht für jedes Zeichen die Position angeben musst. Von der einmal angegebenen Position aus kannst du fortlaufend Text ausgeben und das LCD wechselt nach jedem Zeichen an die nächste Stelle (default eins nach rechts). Ich habe dir mal ein komplettes Beispielprojekt für uVision angehängt mit einem 4x20 LCD. Ich habe in dem Projekt auch das Plugin eingebungen, mit welchem man LCDs im Debug Modus direkt simulieren kann. Falls du das Plugin von der Homepage nicht installiert haben solltest kann ich dir das nur empfehlen. Damit kannst du deine Software für das LCD komplett in uVision debuggen. Ich habe das Programm gut dokumentiert, also solltes du schnell die Zusammenhänge erkennen können. :) Ciao, Rainer
@ZuDummFürLCD Sorry! Ich vermisse die Information ob du im 4- Bit oder 8-Bit modus, das LCD ansteuerst. So wie ich das sehe hälst du das Timing bei der Initialiserung nicht ein. Und lass für den Anfang den quatsch mit dem Timerinterrupt. So lange Timer nicht beherscht. Versuchs erstmal das Timing lt. Datenblatt mit Warteschleifen zu realisieren. Wenn der Cursor auf der 1 Zeile Blinkt und ein Zeichen ausgeben kannst kannste weitermachen. In deiner disp_warte routine scheinen die Zeiten, die da übergibts, zu kurz zu sein. Das Timing zum setzen und Rücksetzen ist hier ne entscheidende sache. Machst das zu schnell hat der LCD-Controller keine Zeit die Daten abzuholen. Lieber etwas langsamer am Anfang. Kannst ja mal versuchen das mit BUSY-Flag abfrage zu realisieren. Gruß Klaus
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.