Hallo leute! Ich habe gerade versucht ein LCD Display (das normale HD44780) an meinen AVR anzuschlißen. Leider bin ich aus dem Tutorial hier nicht ganz schlau geworden, da es in Assembler geschrieben ist (ich nehm GCC). Ich hab trotzdem versucht das so gut wie möglich zu übersetzen. Leider wird auf dem Display nichts angezeigt, ich sehe nur 8 Schwarze Kästchen. Hier mein code: Ich habe diese beiden Funktionen, die ich nacheinander aufrufe: void setModeData( void ) { PORTC |= (1<<PC1); } void writeByte( void ) { //PORTC |= (1<<PC2)|(1<<PC3)|(1<<PC4)|(1<<PC5); unsigned char i=0; while(i<150) {i++;}; PORTC |= (1<<PC3)|(1<<PC5); PORTC |= (1<<PC0); i=0; while(i<150) {i++;}; PORTC &= ~(1<<PC0); PORTC &= ~(1<<PC3); PORTC &= ~(1<<PC5); PORTC |= (1<<PC4); PORTC |= (1<<PC0); i=0; while(i<150) {i++;}; PORTC &= ~(1<<PC0); } Hat jemand eine Idee, warum da kein Zeichen ausgegeben wird? Danke!
Moin, das sieht mir ganz nach zuviel Kontrast aus! Also prüfe ob du die Kontrastspannung angeschlossen hast(Pin 3 am Display)! Wenn ja drehe am Regler und schau ob sich etwas tut. Bis hierhin brauchst du noch keine Daten zum Display senden. Im Normalfall solltest du jetzt die Kästchen abschwächen können, bzw. sie ganz verschwinden lassen. Beachte, wenn du zu wenig Kontrast gibst, siehst du keine Zeichen mehr!!!!! Ich stelle den Kontrast zum Test bei mir immer so ein, dass ich die Segmente immer noch leicht sehen kann. Wenn alles funktioniert kannst du dann nach deinem Gutdünken verfahren. mfg Asterix-007
"Hast Du das Display initialisiert???" Muss man das? Wie geht denn das? Reicht es da ein paar Bytes zu senden, und wenn ja welche??? Danke :-)
>Muss man das? Wie geht denn das? Reicht es da ein paar Bytes zu senden,
und wenn ja welche???
naja, man braucht eine kleine Sequenz, die aber im Datenblatt meist
beschrieben ist...
Wieso? Für was braucht man ein Datenblatt lesen. Außerdem ist das auch noch auf Englisch!!!
im org. Datenblatt setht die Init Sequenz als Tabelle drin. muß man nur abtippen !!!! ist doch nicht sooo schwer. Dafür kommt man ja schon fast ohne english aus..
Das datenblatt hat immerhin 60 Seiten ;-) Ich hab versucht die Initialisierung zu implementieren, aber ich versteh sie ehrlich gesagt nicht so ganz. Das ist irgendwie ziemlich blöd aufgeschrieben... Das habe ich bis jetzt (von Seite 46): void initDisplay( void ) { // Belegung am Port C: // E RS DB4 DB5 DB6 DB7 ? ? // 0 b 0 0 0 0 0 0 0 0 WaitMs(20); // Warte erstmal 20 ms PORTC = 0b00110000; // Setze DB4 und DB5 auf 1 WaitMs(10); // Warte nochmal 10 ms PORTC = 0b00110000; // Nochmal: Setze DB4 und DB5 auf 1 WaitMs(10); // Warte diesmal 2 ms PORTC = 0b00110000; // Zum 3. mal: Setze DB4 und DB5 auf 1 } Warum muss ich denn immer wieder den selben Code senden? Und dann stehen auf der Seite in den nachfolgenden Codes noch *, ein N, ein F und sowas.... HÄ??? Danke für eure Hilfe :-)
am besten nimmst du die lib von peter fleury. mit der geht das dann recht einfach. gruß michael
Eigentlich hatte ich gehofft das nicht tun zu müssen. Die Lib ist mir nämlich etwas zu komplex (OK, dafür auch flexibel) ;-) Aber ich will mit dem Display ja garnicht viel machen: Nur einmal initialisieren, und dann von Zeit zu Zeit mal nen String ausgeben... Ich hatte irgendwie gehofft das wäre leicht machbar :-( Das kann doch nicht so schwer sein!?!?!
naja ist doch fast geschafft. Diese Werte benutze ich für 4Bit. tabelle_init: DB 30h,30h,30h,20h,28h,08h,01h,06h,0fh So jetzt leg los.
ansosnten schau Dir meine Routine an. LCD Ansteuerung in ISR auf 8051. Da mußt Du nur den RAM beschreiben. Der Rest geht fast von alleine.
Hey, danke Stefan :-) Werd's bald testen... Wo finde ich denn deine Routine?
suche nach Displayansteuerung in ISR oder nimm die 3fach Strom Spannungsanzeige. Bei Displayansteuerung sind noch Beiträge von Pieter und Peter drin. Vieleicht helfen die Codes weiter. Gibt wirklich genug hier davon und bei google noch ewige Meter Seiten mehr.
OK, nachdem ich jetzt ales fleißig gelsen habe, habe ich folgende Init Funktion gebastelt: PORTC = 0b00110000; WaitMs(10); PORTC = 0b00110000; WaitMs(10); PORTC = 0b00110000; WaitMs(10); PORTC = 0b00010000; WaitMs(10); PORTC = 0b00010000; WaitMs(10); PORTC = 0b00000000; WaitMs(10); PORTC = 0b00000000; WaitMs(10); PORTC = 0b00000100; WaitMs(10); PORTC = 0b00000000; WaitMs(10); PORTC = 0b00100000; WaitMs(10); PORTC = 0b00111000; WaitMs(10);
OK, nachdem ich nun alles fleißig gelsen habe bin ich zu folgender Init Funktion gelangt: WaitMs(20); PORTC = 0b00110000; WaitMs(10); PORTC = 0b00110000; WaitMs(10); PORTC = 0b00110000; WaitMs(10); PORTC = 0b00010000; WaitMs(10); PORTC = 0b00010000; WaitMs(10); PORTC = 0b00000000; WaitMs(10); PORTC = 0b00000000; WaitMs(10); PORTC = 0b00000100; WaitMs(10); PORTC = 0b00000000; WaitMs(10); PORTC = 0b00100000; WaitMs(10); PORTC = 0b00111000; WaitMs(10); Es tut sich aber leider garnichts :-( Hier nochmal die Pinbelegung: // Pin connections: // - PC0 - Grün = E // - PC1 - Gelb = RS // - PC2 - Orange = DB4 // - PC3 - Rot = DB5 // - PC4 - Braun = DB6 // - PC5 - Schwarz = DB7 Oder: // Belegung am Port C: // E RS DB4 DB5 DB6 DB7 ? ? // 0 b 0 0 0 0 0 0 0 0
Huh, wo kommt der erste doppelpost her? Kann ich den nicht irgendwie löschen???
Was ist PC0 ???? D0 an Port C ????? mit Wertigkeit von 2 hoch 0 =1 ??
Das musste schon umdrehen, sonst klappt gar nix. Außerdem setzt Du das Enable nie, so dass überhaupt nix übertragen werden kann. Vielleicht solltest Du Dir tatsächlich mal ein paar Abschnitte im Datenblatt ansehen. Und natürlich Grundlagen Zahlendarstellung (Hex und Binär)...
Zur Info: PC0 ist das niedrigstwertige (oder nierderwertigste...???) Bit in PORTC. Das steht in der Binärdarstellung ganz rechts. Ist genau wie im Dezimalsystem (da stehen die niederwertigen Stellen auch rechts), nur dass hier die Basis 2 ist. Dezimal: z.B. ...1000er, 100er, 10er, 1er Binär: ...128er, 64er, 32er, 16er, 8er, 4er, 2er, 1er (0b 0 0 0 0 0 0 0 0) Solange Du das nicht verstanden hast, brauchst Du mit µC-Programmierung gar nicht erst anzufangen. Bitte beschäftige Dich zunächst mit den Grundlagen. Aber lass Dich nicht entmutigen. Es ist noch kein Meister vom Himmel gefallen. Alles Schritt für Schritt... Gruß Johnny
>Es ist noch kein Meister vom Himmel gefallen.
Wenn einer nach bestandener Meisterprüfung einen Tandem-Sprung
geschenkt bekommen hat, schon... ;)
und bitte,..... D4-D7 vom Display bitte auf PC0-PC3 oder PC4-PC7. ABER nicht unbedingt in die Mitte. Du machst Dir das Leben nur unnötig schwer damit. ( Swappen ) Hab ichs doch richtig gesehen..... Die Aufstellung Deiner Binärzahlen ist ja völlig falsch !!!!
schau mal auf www.sprut.de nach. da wird dann einiges klar.
> OK, nachdem ich nun alles fleißig gelsen habe bin ich zu > folgender Init Funktion gelangt: > > WaitMs(20); > PORTC = 0b00110000; > WaitMs(10); > PORTC = 0b00110000 WaitMs() wartet nur, richtig? Also, dann wird das so nichts. Einfach nur am PortC irgendwelche Daten anlegen ist zuwenig. Dadurch wird nichts uebertragen. Du musst schon an den anderen Pins (Enable, Write) am LCD auch noch wackeln. Studier doch mal den Source Code von Peter Fleury, auch wenn sie dir jetzt komplex erscheint, was sie in Wirklichkeit nicht ist). Geh in Gedanken die Init-Sequenz dort durch und schau nach was er anders macht. Du kannst dadurch nur lernen. Es hilft auch das ganze mal im AVR-Studio im Debugger durchzusteppen und die Port-Ausgänge zu beobachten. Auch da sieht mann sehr schön welche Pins in welcher Reihenfolge auf 1 bzw. 0 gehen müssen. Zumindest in der Init-Sequenz.
@ Karl Heinz, der Michael hat grundlegende Probleme. Schau Dir mal die Beschaltung an. E ist in der Pinbelegung angeblich auf PC0 in seiner Binärzahl aber auf Bit 7 !!!! Sooo wird das nie was. Da sind die Steuersignale nur noch das I-Tüpfelchen.
Karl Heinz hat aber im Prinzip recht: Wenn Michael erst mal die Zahlensysteme verstanden hat und sich noch ein paar weitere Grundlagen angeeignet hat, dann sollte er sich vielleicht wirklich mal fertigen Code ansehen und versuchen, den zu verstehen. Die fehlenden Grundlagen sind sicher auch der Hauptgrund für seine Aussage, dass ihm die Lib von Peter Fleury zu komplex ist. Klar, wenn ich grad dabei bin, zu lernen, dass 1 + 1 = 2 ist, dann ist ein Dreisatz für mich auch komplex...
>1 + 1 = 2
Das ist aber eher ein Problem der Definition des Zeichensatzes / der
Syntax (oder war es die Semantik?)...
1 + 1 könnte auch 10 oder 1 sein...
Grundlagen haben noch niemandem geschadet...
Und noch verrückter vird es digital, da ist 1+1=0 und C=1
@Stefan: nicht unbedingt... in der "deutschen" Digitaltechnik wird das "Oder" auch als "v" (vom lateinischen vel = oder) dargestellt. Das "Und" als ^, wobei es sich bei beiden Symbolen um richtige (kleine) Dreiecke handelt. Man kann es sich auch so merken: "Oder" ist ist oben offen und "Und" unten... "+" und "*" kommen aus dem angloamerikanischen Sprachgebrauch, wobei das "+" noch einen Kreis drumherum haben müsste...
<digital ist ein Plus ein ODER !!!! ALso 1+1=1 !! Nicht ganz, weil es ist Sprachenabhängig. Wenn ich es matematisch betrachte ist die Addition gemeint. Betrache ich es aus der Richtung Schaltalgebra stimmt das. Verrückte Welt! MFG Uwe
@Stephan: Wenn du das "+" als Verknüpfungsoperator gemeint hast, gebe ich mich geschlagen. Wenn ich aber eine Addition ausführen möchte verlasse ich mich doch lieber auf das XOR wo 1+1 0 ergibt(plus den natürlich fälligen Übertrag). Gruß Chris
beim XOR-Plus war der Kreis drum...war wohl etwas falsch in der Erinnerung...
Sch**** da hab ich ja was losgetreten... Sollte doch nur ein Beispiel aus dem wahren Leben sein... und da lernt man zuerst mal normalerweise Dezimalsystem... Bei mir wars jedenfalls so. Fest steht, dass der Ausdruck 1+1=2 in jedem gebräuchlichen Zahlensystem, in dessen Zahlzeichenvorrat es eine 2 gibt, korrekt ist. Das kann man jetzt wahrscheinlich auch noch tausendmal drehen und wenden...
OK, vielen Dank erstmal für euren Input :-) Ich habe mich mittlwerweile ein wenig schlau gemacht, was die Binärzahlen angeht. Mein größtes Problem war wohl, dass ich dachte die Bits an den AVR-Ports wären 0 bis 7 aufsteigend. Aber wenn ich das jetzt richtig verstanden habe siehts so aus: PORTC = 0b76543210; (Wobei die Zahlen jetzt nur für die Pins stehen, nicht für Bits!). Ist das korrekt so? Dann nochmal zum Display: ich habe leichte Probleme mit der Sprut.de-Tabelle (Hier der Link direkt darauf: http://www.vankurt.de/images/dispTab.gif) Zu den ersten drei Befehlen hab ich diesen Init-Code gebastelt: WaitMs(20); // Warte erstmal 20 ms PORTC = 0b00001101; // Setze ENABLE, DB4 und DB5 auf 1 (8-Bit Modus) WaitMs(10); // Warte 10 ms PORTC = 0b00001101; // Setze ENABLE, DB4 und DB5 auf 1 (8-Bit Modus) WaitMs(5); // Warte 5 ms PORTC = 0b00001101; // Setze ENABLE, DB4 und DB5 auf 1 (8-Bit Modus) WaitMs(5); // Warte 5 ms PORTC = 0b00001001; // Setze ENABLE, DB4 und DB5 auf 1 (4-Bit Modus) Ist der denn so weit in Ordnung? Mein Problem ist dann der letze Teil der Tabelle. Sollen das da einfach 10 Befehle sein? Weil zuerst wurden die ja einzelnd tabellenmäßig getrennt, jetzt stehen sie direkt untereinander.... Und warum sind da Variablen wie N(1) oder F(0) drin? Und was bedeurten dann die "-" ? Soll man die auf 1 oder 0 setzen? Und wofür stehen die verschiedenen Hintergrundfarben (gelb, grün, blau)???? Sehr verwirrend das ganze!! :-( Ich hoffe ihr helft nochmal :-D
wie ist denn das Display jetzt wirklich angeschlossen ?? Das müssen wir schon wissen.
Oh :-) Also eigentlich wie gehabt, nur halt andersrum: // Belegung am Port C: // ? ? DB7 DB6 DB5 DB4 RS E // 0 b 0 0 0 0 0 0 0 0
30h,30h,30h,20h,28h,08h,01h,06h,0fh das sind die werte, so nun mal sehen, 30h b00001100 20h b00001000 28h b0010000 und danach b00001000 erst high dann low und so weiter, die Signale von RS E und RW kommand dann noch dazu. Sind jetzt nicht berücksichtigt !!!! ABER wie ich sagte mache die Belegung anders. Du machst Dir nen Wolf mit dem Nibbeln der Bytes. Folgender Vorschlag: 0b 0 0 0 0 0 0 0 0 Bits binär E RS RW DB7 DB6 DB5 DB4 Display PC6 PC5 PC4 PC3 PC2 PC1 PC0 Port C Dann siehst so aus: 30h 0b x x x 0 0 1 1 die X Werte müssen entsprechend gesetzt werden. Je nachdem ob Du lesen/schreiben willst, Befehle oder Daten sendest. Ab der 28h wird alles in 2er Paketen geschrieben. Erst High Nibble dann Low Nibble. Die 28h wäre dann 0b0000 0010 und 0b0000 1000. Das Leerzeichen ist nur symbolisch zum besseren Verständnis für Dich. So mehr kann man jetzt wirklich nicht für Dich tun. Habe fertig. stephan
>30h b00001100 >20h b00001000 sollte 30h nicht eher b00110000 und 20h b00100000 heissen? Deine Schreibweise gilt wohl eher als die Bit-Reihenfolge bei der Übertragung über die serielle Schnittstelle...
@Rahul, er hat an Bit 0 und 1 RS und E !!! Das wirkliche Bit 0 ist an Bit 2 !!! Jetzt kalr ??? Deswegen sagte ich ja er soll umstrippen.
Danke erstmal, dass du dir so viel Mühe gibst, Stefan :-) Leider hab ich's immer noch nicht hinbekommen... Damit das klar ist: "30h,30h,30h,20h,28h,08h,01h,06h,0fh das sind die werte, so nun mal sehen," Für welche Pin-belegung sind die denn gedacht? Die aus deinem Vorschlag? "Folgender Vorschlag: 0b 0 0 0 0 0 0 0 0 Bits binär E RS RW DB7 DB6 DB5 DB4 Display PC6 PC5 PC4 PC3 PC2 PC1 PC0 Port C" Dann versteh ich nämlich nicht ganz, wie du von 30h (was ja binär 110000) sein müsste auf 0bxxx0011 kommst... oder beziehst du dich da jetzt auf meine Belegung? (letzteres macht für mich gerade auch keinen Sinn) Die Verwirrung ist groß ^^ Danke!!!
Ich hatte etwas abgekürzt. Weil D0-D3 am Display auf GND liegen. vollständig und korrekt Korrekt wäre natürlich 0x00110000b !! Somit Interpretiert das Display die 3 als 30. Es sieht ja unten immer 0. Halte Dich an meinen Vorschlag und dann kriegen wir das hin.
Also gut, dann nochmal für Idoten: Wenn ich deine Pin-Belgung verwende: "Folgender Vorschlag: 0b 0 0 0 0 0 0 0 0 Bits binär E RS RW DB7 DB6 DB5 DB4 Display PC6 PC5 PC4 PC3 PC2 PC1 PC0 Port C" und dann in kleinen Zeitabständen deine Werte rübersende: "30h,30h,30h,20h,28h,08h,01h,06h,0fh", dann ist das Display vernünftig initialisiert? Bitte entschuldige meine Schwerfälligkeit - das ist eigentlich nicht meine Art. Aber in diesem Fall stehe ich so derbe auf der Leitung, das gibt's garnicht ;-) Ich denke wenn das Ding erstmal läuft macht's auch mehr Spass damit rum zu experimentieren. Aber so lange man garichts sieht ist das alles eher frustrierend... 1000 Dank für deine Geduld. Du bist ein echter Held für mich :-D
so siehts aus, allerdings hast Du dann erstmal nur den Kursor zu sehen. Also 1. Eable setzen, RW,RS, Wert Ausgeben, Enable low Wie gesagt, ab 20h mußt Du dann zerlegen in Low und High nibble. 4 Bit Modus. Beim Lesen vom Display auch in 2 Schritten. Ich habe bei mir RW fest auf MAsse, da ich nicht lesen will und nutze eine feste Zeit von 5-6ms. Das reicht immer und ist immer noch schnell genug. 2x16 schaffe ich damit ca. 4 Aktualisierung/Minute.
So, da bin ich wieder :-D Ich hab mir in der Zwischenzeit jede menge Zeug angelesen, da das alles einfach nicht funktionieren wollte. Nun war der Meinung, die Initialisierung endlich hinzubekommen. Dann habe ich mit diesem Simulator herumgespielt: http://www.geocities.com/dinceraydin/djlcdsim/djlcdsim.html und bin zu folgender Befehlsreihenfolge gekommen, die wenigstens einen blinkenden Cursor erzeugen sollte: Erst 3 mal DB5 und DB4 an -> Init 8 bit Modus Dann nur DB5 an -> Jetzt in 4 Bit wechseln Dann alle aus -> Upper Nibble Dann alle an -> Lower Nibble -> Jetzt müsste Display AN, Cursor AN und Blinken AN sein Der Code dazu sieht so aus: Belegung: // PC7 PC6 PC5 PC4 PC3 PC2 PC1 PC0 // 0b 0 0 0 0 0 0 0 0 // None E RS None D7 D6 D5 D4 Dann: void enable( void ) { PORTC |= (1<<PC6); } void disable( void ) { PORTC &= ~(1<<PC6); } void initDisplay( void ) { // PC7 PC6 PC5 PC4 PC3 PC2 PC1 PC0 // 0b 0 0 0 0 0 0 0 0 // None E RS None D7 D6 D5 D4 WaitMs(30); disable(); PORTC = 0b00000011; enable(); WaitMs(30); disable(); PORTC = 0b00000011; enable(); WaitMs(30); disable(); PORTC = 0b00000011; enable(); WaitMs(30); disable(); PORTC = 0b00000010; enable(); WaitMs(30); disable(); PORTC = 0b00000000; enable(); WaitMs(30); disable(); PORTC = 0b00001111; enable(); WaitMs(30); } ABER IMMERNOCH STREIKT DAS BLÖDE DING UND ZEIGT NUR SCHWARZE KÄSTCHEN!!! Das kann doch nicht wahr sein!?!?! :-(
WaitMs(30); disable(); PORTC = 0b00000010; enable(); WaitMs(30); disable(); PORTC = 0b00000000; enable(); WaitMs(30); hier fehlt noch ne Null !!!!! Du willst doch 0Fh schreiben oder nicht ??? zB.: disable (); portc = 0b00000000; lalala disable(); PORTC = 0b00001111; enable(); WaitMs(30);
Ahh, du hast Recht. Es fehlt tatsächlich eine 0. Hab also folgendes draus gebastelt: WaitMs(30); disable(); PORTC = 0b00000011; // 8Bit enable(); WaitMs(30); disable(); PORTC = 0b00000011; // 8Bit enable(); WaitMs(30); disable(); PORTC = 0b00000011; // 8Bit enable(); WaitMs(30); disable(); PORTC = 0b00000010; // Jetzt 4Bit enable(); WaitMs(30); disable(); PORTC = 0b00000000; // ... enable(); WaitMs(30); disable(); PORTC = 0b00000000; // Alles anschalten enable(); WaitMs(30); disable(); PORTC = 0b00001111; // ... enable(); WaitMs(30);
hast Du auch an die Signale für R/W E und RS gedacht ?????
Soweit ich weiß liest das LCD die Daten vom Port mit fallender Flanke am Enable-Pin. D.h. das müsste bei dir so aussehen: DDRC = 0xFF //alle Pins an Port C als Ausgang WaitMS(20); //am Anfang reichen 20ms PORTC |= (1 << PC6); //Enable-Pin High PORTC = 0b01000011; //8-Bit PORTC &= ~(1<<PC6); //Enable-Pin Low WaitMS(5); PORTC |= (1 << PC6); //Enable-Pin High PORTC = 0b01000011; //8-Bit PORTC &= ~(1<<PC6); //Enable-Pin Low WaitUS(160); PORTC |= (1 << PC6); //Enable-Pin High PORTC = 0b01000011; //8-Bit PORTC &= ~(1<<PC6); //Enable-Pin Low WaitUS(160); PORTC |= (1 << PC6); //Enable-Pin High PORTC = 0b01000010; //4-Bit Modus - MSB PORTC &= ~(1<<PC6); //Enable-Pin Low WaitUS(1); PORTC |= (1 << PC6); //Enable-Pin High PORTC = 0b01000000; //4-Bit Modus - LSB PORTC &= ~(1<<PC6); //Enable-Pin Low WaitUS(160); WaitMS(20); PORTC |= (1 << PC6); //Enable-Pin High PORTC = 0b01000010; //4-Bit Modus - MSB PORTC &= ~(1<<PC6); //Enable-Pin Low WaitUS(1); PORTC |= (1 << PC6); //Enable-Pin High PORTC = 0b01000000; //4-Bit Modus . LSB PORTC &= ~(1<<PC6); //Enable-Pin Low WaitUS(160); PORTC |= (1 << PC6); //Enable-Pin High PORTC = 0b01000000; //Display AN, Cursor AN - MSB PORTC &= ~(1<<PC6); //Enable-Pin Low WaitUS(1); PORTC |= (1 << PC6); //Enable-Pin High PORTC = 0b01001100; //Display AN, Cursor AN - LSB PORTC &= ~(1<<PC6); //Enable-Pin Low WaitUS(160); PORTC |= (1 << PC6); //Enable-Pin High PORTC = 0b01001000; //DD-RAM Position 0 - MSB PORTC &= ~(1<<PC6); //Enable-Pin Low WaitUS(1); PORTC |= (1 << PC6); //Enable-Pin High PORTC = 0b01000000; //DD-RAM Position 0 - LSB PORTC &= ~(1<<PC6); //Enable-Pin Low WaitUS(160); PORTC |= (1 << PC6); //Enable-Pin High PORTC = 0b01100100; //Schreibt ein A - MSB PORTC &= ~(1<<PC6); //Enable-Pin Low WaitUS(1); PORTC |= (1 << PC6); //Enable-Pin High PORTC = 0b01100001; //Schreibt ein A - LSB PORTC &= ~(1<<PC6); //Enable-Pin Low WaitUS(160); WaitUS(x) wartet x µs, ich weiß nicht, wie die Funktion bei dir dafür heißt, ich benutze delay.h von WinAVR (einbinden über #include <util/delay.h>) dort heißt es "_delay_us(x)". So funktioniert es bei mir einwandfrei Zwei Hilfreiche Links sind auch: http://www.myke.com/lcd.htm http://www.ulrichradig.de/site/atmel/avr_lcd/pdf/LC.pdf
@ Stephan Ja, ich denke schon: - RS ist bei mir an PC5, also in allen meinen Binärcodes = 0. => Befehlsmodus - RW hab ich nicht verwendet, ist an GND gelötet. => Schreibzugriff - E setze ich ja immer mit enable/disable vor und nach jedem Befehl, den ich übertragen möchte (siehe Code) Ist doch richtig so, oder? @Peter Bei fallender Flanke also? Nagut, hab meine Funktionen "enable" und "disable" mal vertauscht (die machen PORTC |= (1 << PC6); //Enable-Pin High PORTC &= ~(1<<PC6); //Enable-Pin Low genau wie in deinem Code). Leider bringt das immer noch nichts. Nach wie vor nur 8 schwarze Kästchen, und die andere Hälfte komplet leer :-(
Kurze Frage an peter: Warum hast du in allen deinen Befehlscodes (z.B. 0b01000011) an der zweiten Stelle nach dem b eine 1? Ich verwende ja auch diesen Code, bei mir ist's allerdings 0b00000011, also nur DB4 und DB5 an. Ist da noch was wichtiges an diesem Pin? Und für alle Ideen, die zur Lösung meines Problems beitragen bin ich natürlich absolut dankbar!!!
Am Pin 6 hängt nach deiner Aussage weiter oben das Enable-Signal! Das darfst du natürlich nicht wieder auf 0 setzen, während du Daten schickst!
Au verdammt! Das macht Sinn ^^ ich werd's gleich heut Mittag testen! Danke :-)
Bei mir (1x16 LCD) kann ich auch nur an den ersten 8 Stellen etwas anzeigen, die hinteren 8 bleiben einfach leer. Ich dachte, dass mein Display kaputt sei, denn wenn ich den Kontrast erhöhe sehe ich ganz schwach Kästchen. Ich habe auch mal versucht, ob die hinteren acht Stellen vom Controller vielleicht als zweite Zeile angesteuert werden, aber das hat auch nicht funktioniert. Hat dafür vielleicht jemand eine Lösung? @Michael Bist du dir sicher, dass dein Timing stimmt und die Funktion WaitMS(x) auch x Millisekunden wartet? Ich weiß von _delay_ms(x), dass die nur y / Mhz Millisekunden warten kann, wobei y irgendeine Zahl ist, die ich gerade nicht mehr weiß.
Ich habe ebengerade noch einmal versucht mein Display im 2-Zeilen Modus anzusteuern und es hat doch funktioniert. Das liegt wahrscheinlich an den Adressen der Zeichen (vermutlich: 80..87, C1..C7; ich war von 80 bis 8F ausgegangen). Als Lösung habe ich meine Routine so umgeschrieben, das sie ab einem Spaltenindex von 8 automatisch in die 2. Zeile umspringt und man das Display nun wie ein 1x16 LCD ansteuern kann.
Welches Display ist denn das, Peter? Sowas hab ich auch noch nicht gesehen.
Ich habe das 1x16 Zeilen LCD von Reichelt (LCD 161A). Auf die Sache mit den Adressen bin ich durch diese PDF (Seite 4): http://www.ulrichradig.de/site/atmel/avr_lcd/pdf/LC.pdf gekommen. In meinem Datenblatt habe ich aber nichts zu den Adressen für die Spalten gefunden.
Mittlerweile sieht der Code so aus: void enable( void ) { PORTC |= (1<<PC6); } void disable( void ) { PORTC &= ~(1<<PC6); } void initDisplay( void ) { // PC7 PC6 PC5 PC4 PC3 PC2 PC1 PC0 // 0b 0 0 0 0 0 0 0 0 // None E RS None D7 D6 D5 D4 WaitMs(30); enable(); // Setze E auf 1 PORTC = 0b01000011; // Befehl disable(); // Jetzt E auf 0 -> fallende Flanke WaitMs(30); enable(); PORTC = 0b01000011; disable(); WaitMs(30); enable(); PORTC = 0b01000011; disable(); WaitMs(30); enable(); PORTC = 0b01000010; disable(); WaitMs(30); enable(); PORTC = 0b01000000; disable(); WaitMs(30); enable(); PORTC = 0b01000000; disable(); WaitMs(30); enable(); PORTC = 0b01001111; disable(); WaitMs(30); } Und ratet was passiert? Genau! Schwarze Kästchen!!!!!! ICH BEKOMM HIER GLEICH NEN NERVENZUSAMMENBRUCH VERDAMMT!!!!!! ^^ Das kann doch echt nicht wahr sein.... gibt es sonst noch Tips? (Mal wieder vielen Dank an alle Mithelfenden!)
Ich weiß nicht, ob das eine Rolle spielt, aber für "normale" Befehle reicht es, wenn man 160µs nach jedem Byte wartet. Am Anfang (nach dem Spannung angelegt wurde) 15ms und 5ms für "Clear Display" und "Cursor Home". Zwischen MSB und LSB muss eigentlich nur ganz kurz (ich glaube 500ns) gewartet werden.
Es würde auch helfen, wenn du mal deine komplette C-Datei anhängen könntest. Vielleicht liegt der Fehler ja an einer ganz anderen Stelle.
1. Was hast du überhaupt für eine Prozessorclock? 2. Du musst das DDR Register zu Anfang auf Ausgang bei PORTC stellen. 3. Am besten ziehst du Enable, bevor du irngdwas am Display machst, erstmal auf High.
1) Also das mit dem Timing ist OK. Meine Funktion wartet eher zu lang als zu kurz, was ja kein Problem ist, oder? Ich benutze die auch um eine LED blinken zu lassen (mit 100ms, das sieht schon ganz OK aus). 2) Das hab ich wohl gemacht. 3) OK, da muss ich nochmal gucken... ;-) Die C-Datei findet sich im Anhang.
Also wenn ich mein Display einfach nur initialisiere ohne Daten ins DD-RAM zu schreiben bekomme ich auch nur schwarze Kästchen angezeigt. Schreibe mal noch folgendes an das Display: (hinter deinem bisherigen initDisplay) enable(); PORTC = 0b01001000; disable(); WaitMS(1); enable(); PORTC = 0b01000000; disable(); WaitMS(5); enable(); PORTC = 0b01100100; disable(); WaitMS(1); enable(); PORTC = 0b01100001; disable(); WaitMS(5); Und verkürze die Wartezeiten zwischen MSB und LSB mal auf 1ms.
Ich werd's gleich mal testen. Aber eigentlich sagt mein letzter Befehl: "Display ein, Cursor ein, Blinken ein" Beim Simulator funktioniert's auch, da ist dann ein blinkender Cursor zu sehen.....
Kannst du jetzt mal bitte dein komplettes Programm zippen und anhängen? Und mach mal zwischen enable und disable n paar takte pause, vielleicht ist der abstand einfach zu kurz und dein Display bekommts nicht mit. Immerhin kommen enable und disable fast im darauffolgenden Takt. Soviel ich weiß muss enable aber auch ne bestimmte mindestzeit auf High stehen. enable(); PORTC = 0b01100100; //hier warten disable(); Gruß Andreas
erst Enable high ; das Display wieß..Ah jetzt kommt was für mich dann RSund RW ; das Display wieß , Ah... Komando/ Daten, schreiben/lesen jetzt die Daten ; und jetzt Enable auf Low; Display.... OK hab ich !! In der Reihenfolge.
@Stefan: "erst Enable high ; das Display wieß..Ah jetzt kommt was für mich dann RSund RW ; das Display wieß , Ah... Komando/ Daten, schreiben/lesen jetzt die Daten ; und jetzt Enable auf Low; Display.... OK hab ich !!" Dieser Textblock ist syntaktisch etwas merkwürdig... ich bin nicht sicher, ob ich den richtig lesen kann ;-) @Andreas: Es ist ein AVR Mega16, mit einem 11 Mhz Quarz...oder was mainst du?
Mal ne Frage zu deinem Code: void enable( void ) { PORTC |= (1<<PC6); } PORTC |= (1<<PC6); ??? macht man das so bei einem AVR? Bitschubsen für das setzen eines einzelnen PortPins. Ich kenn das halt vom MSP430 anders oder versteh ich die drei Zeilen nicht? Steuer mein Display allerdings auch nur im 8bit-Modus an.
Jo, ich denke das geht klar so. Das 6te Bit (hier an E) wird damit angeknipst :-) PS: Das komplette Programm hab ich schon geposted, hängt ein bisschen weiter oben an :-)
@Marcel: Ja das macht man so. Was er da macht ist normale Bitmaskierung. Geschoben wird (ein halbwegs intelligenter Copiler vorausgesetzt) an der Stelle gar nicht: Das ganze kann schon zur compile-zeit als Konstante berechnet werden (in diesem fall 00100000). @Michael: Genau das meinte ich - 11 Mhz Quarz bedeutet 1 Takt braucht ca 90ns (1/11000000 = 9,0909... x 10e-8). Schau mal wieviele ns das enable signal high sein muss (Datenblatt) Und poste endlich mal deinen kompletten Code, damit wir sehen was du machst! Gruß Andreas
@Stephan: "" erst Enable high ; das Display wieß..Ah jetzt kommt was für mich dann RSund RW ; das Display wieß , Ah... Komando/ Daten, schreiben/lesen jetzt die Daten ; und jetzt Enable auf Low; Display.... OK hab ich !! "" Das ist übrigens Quark. Wichtig ist: Zur Zeit, wo Enable von High auf Low wechselt, müssen einfach nur die Datenleitungen und die RS+RW Leitungen valide Daten aufweisen. Mehr nicht. Nix mit "Ah jetzt weiß das Display"..
PS: Hier mal einen Ausschnitt aus meiner eigenen Lib, die übrigens mit einem EA DOG-M (16*2) super läuft.
1 | void lcd_cmd8(unsigned char cmd) |
2 | {
|
3 | |
4 | LCD_PORT = (cmd & 0xF0) >> 4; |
5 | |
6 | LCD_PORT &= ~(1<<LCD_RS); |
7 | |
8 | LCD_PORT |= (1<<LCD_E); |
9 | nop(); |
10 | nop(); |
11 | nop(); |
12 | nop(); |
13 | nop(); |
14 | nop(); |
15 | LCD_PORT &= ~(1<<LCD_E); |
16 | |
17 | nop(); |
18 | nop(); |
19 | nop(); |
20 | nop(); |
21 | nop(); |
22 | nop(); |
23 | |
24 | LCD_PORT = (cmd & 0x0F); |
25 | |
26 | LCD_PORT |= (1<<LCD_E); |
27 | nop(); |
28 | nop(); |
29 | nop(); |
30 | nop(); |
31 | nop(); |
32 | nop(); |
33 | LCD_PORT &= ~(1<<LCD_E); |
34 | |
35 | _delay_us(30); |
36 | }
|
@Simon, für gewöhnlich aktiviert man Bausteine bevor man sie mit Daten füttert. Und das passiert mit Enable. Ich habe lediglich versucht es für Michael verständlich auszudrücken, ( bildlich gesprochen ) sozusagen. Er scheint ja nicht mal die Vorschläge von ganz oben porbiert zu haben, sonst hätte er ja nicht knapp 80 Einträge im Tread. Und das erst beim INIT. .......
@Stephan: Richtig. Das Display aktiviert man eben, indem man Enable auf low zieht. Wenn Enable high ist, dann macht das Display rein garnichts. Ehrlichgesagt schätze ich mal, dass die Probleme timingbedingt sind. PS: Bei PORTC fällt mir immer JTAG Interface ein. Hast du das per Fuse ausgeschaltet?
Und versuche mal statt der Timerversion busy wait zu nehmen um auszuschließen, dass es daran liegt. Nimm mal für Pausen die _delay_ms() Funktion der libc. Gruß Andreas
@Simon, Zitat: "Das Display überwacht den Pegel von ENABLE. Ändert sich dieser Pegel von Low nach High, dann fragt es die Leitungen RS und R/W ab etc.pp :" nachzulesen bei Sprut und im Datenblatt !!! Es heist Enable und nicht /Enable ergo..... es ist High aktiv..... aber warscheinlich auch nur Quark !!!! Meine Display gehen jedenfalls sehr gut !! Und du solltest auch Hausaufgaben machen so wie Michael.
"Er scheint ja nicht mal die Vorschläge von ganz oben porbiert zu haben" glaub mir, ich HABE SO ZIEMLICH ALLES probiert. Ich kann mir auch nicht erklären woran's hapert.... aber ich werde da mal zusätzliche delays einbauen, so wie ihr das vorgeschlagen habt.
warum nimmst Du nicht mal die fertigen Routinen ???? wie ganz oben erwähnt ?? Die müssen gehen, sonst stimmt was ganz und gar nicht !!!
Sorry, aber @Stephan: Nein, das ist falsch. Auch wenn es nicht /Enable heißt (das / ist kein Muss), übernimmt das Display die Daten bei der fallenden Flanke. http://web.media.mit.edu/~ayah/documents/hd44780u.pdf Seite 58. Die Daten müssen bei der fallenden Enable-Flanke erst korrekt anliegen, Basta.
Ich habe jetzt überall noch kleine Delays (1 ms) eingebaut, wenn ich das E-Bit ändere. Damit sollte es jetzt also auch keine Probleme mehr geben... Leider hat das ganze noch immer keine Wirkung gezeigt :-( Mit den Fremdbibliotheken ist so eine Sache... die sind quasi garnicht dokumentiert (keine Tutorials oder Referenz so weit ich sehen kann). Und da sind krass viele merkwürdige Konstanten drin, die man wohl irgendwie setzen muss, die ich aber nicht verstehe :-(
Versuche einfachmal folgenden Code für die LCD-Ansteuerung zu verwenden, bei mir funktioniert dieser einwandfrei. Wenn es auch damit nicht geht liegt das Problem woanders.
1 | #include <util/delay.h> |
2 | |
3 | #define ENABLE_PIN 6
|
4 | #define RS_PIN 5
|
5 | |
6 | void LCDenable(void) |
7 | {
|
8 | PORTC |= (1 << ENABLE_PIN); |
9 | _delay_loop_1(2); |
10 | PORTC &= ~(1 << ENABLE_PIN); |
11 | }
|
12 | |
13 | void LCDwrite(char Data,char rs) |
14 | {
|
15 | DDRC = 0xFF; |
16 | if (rs == 0) |
17 | {
|
18 | PORTC &= ~(1 << RS_PIN); //rs == 0 -> Steuerregister |
19 | } else { |
20 | PORTC |= (1 << RS_PIN); //rs == 1 -> Datenregister |
21 | }
|
22 | PORTC = (PORTC&0xF0) + ((Data&0xF0)>>4); //Write Nibbel MSB |
23 | LCDenable(); |
24 | PORTD = (PORTC&0xF0) + (Data&0x0F); //Write Nibbel LSB |
25 | LCDenable(); |
26 | _delay_us(160); |
27 | }
|
28 | |
29 | void LCDclear (void) |
30 | {
|
31 | |
32 | LCDwrite (1,0); //Clear Display |
33 | _delay_ms(5); |
34 | LCDwrite (0x80,0); //Set DD-Ram Adresse = 0 |
35 | }
|
36 | |
37 | void LCDinit(void) |
38 | {
|
39 | DDRC = 0xFF; |
40 | _delay_ms(20); |
41 | LCDwrite(0x30,0); |
42 | _delay_ms(5); |
43 | LCDwrite(0x30,0); |
44 | LCDwrite(0x30,0); |
45 | LCDwrite(0x28,0); //LCD in 4bit Modus - 2 Zeilen |
46 | _delay_ms(20); |
47 | LCDwrite(0x28,0); //LCD in 4bit Modus - 2 Zeilen |
48 | LCDwrite(0x06,0); //Cursor wird nach schreiben nach rechts verschoben |
49 | LCDwrite(0x0C,0); //Display an, Cursor aus, Blink_Cursor aus |
50 | LCDwrite(0x80,0); //Set DD-Ram Adresse = 0 | 1000 0000 | 1=DD-Ram |
51 | 0000000=Adresse |
52 | }
|
53 | |
54 | int main(void) |
55 | {
|
56 | LCDinit(); |
57 | LCDclear(); |
58 | LCDwrite(0x54,1); |
59 | LCDwrite(0x65,1); |
60 | LCDwrite(0x73,1); |
61 | LCDwrite(0x74,1); |
62 | }
|
den Zeilenumbruch zwischen 50 und 51 müsstest du noch entfernen
Nochetwas: in Zeile 24 steht noch "PORTD" das muss bei dir "PORTC" heißen.
Hast du denn die Vorschläge von oben schon probiert: - PortC überprüfen (JTAG o.ä. deaktiviert?), oder nimm mal einen andern Port. - schmeiß deine eigene Wartroutine weg, ich wette es liegt am Timing. Nimm zum testen mal die busy-wait routine _delay_ms(...) Gruß Andreas
@Peter: Erstmal vielen Dank für deinen Code! Leider bringt auch der keine Veränderung: nach wie vor nur 8 schwarze Kästchen. Ich denke mal wir haben die gleiche Pinbelegung, ja? (zumindest RS und E sind schonmal korekt)..... Woran könnte es denn dann liegen? @Andreas: Ich hab zwar keine Ahnung wer oder was JTAG ist, aber der Port scheint OK zu sein. Hab auch mal alles an Port A gehängt (natürlich Software entsprechend geändert), hat aber auch nicht geholfen. Die Ports sind aber OK, ich hab LED-blink-Tests damit gemacht, und jeder Pin ist OK. Ich habe auch mit nem Multimeter geprüft, ob die Pins vom AVR gut mit dem Display verlötet sind. Das scheint ebenfalls so zu sein...
Aber wenn du nichts verändert hast an den Fuse-Bits dann IST JTAG nunmal aktiviert. Kann ich mir garnicht vorstellen dass die Portbits vernünftig funktionieren... ?!
Ich weiß leider immer noch nicht so genau was es mit diesem JTAG auf sich hat. Hier auf der Seite und bei Wikipedia wird das nich vernünftig erklärt.... was ist denn das?
@Michael Ich hatte den Code auf deine Pin-Belegung umgeändert. Du musst über die Fuse-Bits JTAG deaktivieren. Näheres zu den Einstellungen findest du im Datenblatt von deinem Controller (bei Fuse-Bits oder JTAG nachschauen).
Also ich habe mit PonyProg mal die "Configuration Bits" eingelesen. Dagibt es eins das "JTAGEN" heißt, das ist aber schon an.
Oh, sorry! Was ich eigentlch noch sagen wollte war, dass es aber leider keinen Unterschied macht, ob das Kästchen an ist oder nicht. Funzt nach wie vor nicht :-(
Vorschlag zur systematischen Fehlersuche: 1. Verwende bewährte Software (z.B. peter fleury´s lib) 2. Nehme die entsprechenden Einstellungen in der Software vor, meistens nur im Kopf der Quelltexte nötig 3. Baue Deine Schaltung komplett neu auf, nach den getroffenen Vorgaben, um zu verhindern, dass Du murks verdrahtet hast 4. Verwende ggf. R/W um die Busy Flag auslesen zu können. 5. Setze ggf. die Taktung Deines MC in der Configuaration herunter, da zu hohe Datenraten nicht verarbeitet werden 6. Mit Strom auf dem Module regele den Kontrast mit einem Poti an Pin 3 so ein, das die schwarzen Kästen gerade noch zu sehen sind Dann kannst Du immer noch Deine eigene (Code-) Suppe kochen und die Performance steigern. Sollte es immer noch nicht funktionieren versuche ggf. ein anderes Display. Viel Glück
Äh ich hoffe deine "LED-Blink-Tests" hast du nicht direkt am Bus gemacht? Dann könnte es sein, dass die Spannung die an den LEDs abfällt zu groß ist und die übrige Spannung nicht mehr eindeutig genug ist.. Nochmals die andere Frage: Hast du endlcih deine Warteroutine weggeworfen?? Gruß Andreas
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.