Nabend, also, ich habe mir nun bei pollin ein LCD NAN YA LMK62R gekauft. Ich habe es an meinen AT89S52 angeschlossen. Wenn ich Vcc anlege, dann erscheint der obere Balken in schwarz. Es scheint also schonmal anzugehen ;) So, nun bin ich dabei zu verstehen, wie man das Display ansteuert. Das man, wenn man im 4 bit modus arbeitet, die 8 bit aufteilen und dann in 2 nibbles senden muss habe ich wohl verstanden. Dafür setze ich die ausgänge auf den wert den ich gern hätte und dann einmal kurz E=1 kurz warten und dann E=0. Soweit so gut. Um allerdings den rest zu vestehen, müsste ich wohl einigermaßen assembler können...denn das AVR LCD tutorial nutzt diese sprache. Ich würde es allerdings gern in C machen. Gibts dafür eine gute Seite? Unter den weblinks find ich leider nix.
@ Oliver D. (highspeed-oliver) >assembler können...denn das AVR LCD tutorial nutzt diese sprache. >Ich würde es allerdings gern in C machen. Gibts doch auch alles. http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial#LCD-Ansteuerung MfG Falk
Ah ich glaube bei sprut.de bin ich fündig geworden :)
Oh cool. Ich hatte bei artikel suche LCD eingetippt. In LCD bin ich dann unten auf AVR LCD gegangen... Wer suchet der findet ;)
Hmm, bei dem AVR GCC tutorial ist es natürlich für den AVR...somit müsste ich mich überall durchwursten. Ich glaube da ist es schlau mit Anleitung erstmal selber zu programmieren. Das AVR GCC tut ist für meine C kenntnisse ziehmlich riesig.
@ Oliver D. (highspeed-oliver) >Hmm, bei dem AVR GCC tutorial ist es natürlich für den AVR...somit >müsste ich mich überall durchwursten. ???? Es werden lediglich schreibende Portzugriffe gemacht. Der Rest ist Standard-C. Das sollte in Null Komma Nix an den 89er anpassbar sein. >Das AVR GCC tut ist für meine C kenntnisse ziehmlich riesig. Du braucht nicht mal einen Bruchteil. MfG Falk
Mag sein, dass ich nur einen bruchteil brauche....da ich aber noch garkeine ahnung habe und auch niemanden der es mir am pc erklären kann, ist das schon eine kleine herausforderung.
Hmm, wenn ich das AVR GCC tutorial an meinen at versuche anzupassen, kriege ich ooohne ende fehler.... z.B. void set_cursor(uint8_t x, uint8_t y); das kommt in die lcd_routines.h Als fehler erhalte ich Invalid parameter declaration.
@ Oliver D. (highspeed-oliver) >z.B. void set_cursor(uint8_t x, uint8_t y); >das kommt in die lcd_routines.h Als fehler erhalte ich Invalid >parameter declaration. Da fehlt wahrscheinlich #include <stdint.h> >Was ist mit >#define LCD_DDR >gemeint? Das ist das Data Direction Register, welches festlegt, ob ein Bit eines Ports Ein- oder Ausgang ist. MfG Falk
Der Fehler bleibt bestehen. Invalid parameter declaration. Das Data direction register sitzt doch im avr nicht wahr? Sowas hat mein AT89S52 garnicht. Meine ich.... Ich kann einfach einen portpin auf masse ziehen um einen zweiten zustand zu haben. Vorher schreibe ich einfach eine 1 rein. Der Taster z.b. zieht die 1 dann auf masse.
Ja da hast du Recht, du musst nur die Daten ausgeben ein DDR hat der AT89S52 nicht. Deshalb bringt dir das auch nicht wirklich was die Zeilen aus dem Tutorial zu kopieren. Was hast du denn für nen Compiler? Versuch doch einfach das Tutorial zu lesen und zu verstehen. Dann kannst du das in 0,nix für deinen uC umsetzen.
Hmm ja, ich versuche natürlich das zu verstehen. Mir würde es reiche, wenn ich zumindest das display schonmal initialisiert bekommen. Dafür gibt es bei sprut.de ein ablaufdiagramm, wo was geschrieben werden muss um das display in den 4 bit modi zu bekommen. Das habe ich programmiert und auf den uc geschrieben, aber es wird nur der oberste reihe meines LCDs eingeschaltet. Eigentlich sollten das dann doch beide sein.
Nee, wenn man Spannung anlegt, leuchtet je Nach Display immer nur ein Teil. z.B. die erste Zeile, erste und dritte, die erste Hälfte der Zeile,... Deine Initialisierung funktioniert nicht sonst würde es nur kurz aufblinken und dann leer sein. Da stimmt bestimmt das Timing nicht.
Ok. Ich meine aber alle zeiten eingehalten zu haben und eher ein bischen zu viel zu haben....
Tja, dann stell doch mal nen Schaltplan und das Programm hier rein. Das Datenblatt des LCD ist ja eher dürftig...
Oliver D. wrote: > Ok. > > Ich meine aber alle zeiten eingehalten zu haben und eher ein bischen zu > viel zu haben.... Vielleicht hilft Dir das ja weiter... ...
Ehm schaltplan? Ich habe das Display so verbunden: sbit DB4=0xB0; sbit DB5=0xB1; sbit DB6=0xB2; sbit DB7=0xB3; sbit RS=0xB4; sbit E=0xB5; Also einfach an Port B0 das dingen angeklemmt. RW liegt auf masse. Mein Board funktioniert 100% einwandfrei. Die Verkabelung zum Display ist ebenfalls einwandfrei. Habs durchgemessen. Ich habe ausserdem ein zweites Display hier, was sich mit gleichem code ebenfalls nicht inititalisieren lässt. Liegt dann wohl an meinem code ;) Ich habe den mal in den Anhang gepackt. Wundert euch nicht, dass es absoluter Mist vom Stil her ist...Es ist einfach mal für den Anfang gedacht um einfach das Display mal zu initialisieren. Für die Zeit habe ich einfach mal eine For schleife genommen. Achja, mein uC läuft bei 11,0592Mhz.
Wie gesagt, das Timing stimmt nicht. Näach anlegen der Betriebsspannung >=15ms warten... Deine Warteschleifen werden wohl auch wegoptimiert und dann fehlt auch noch enable in deinem Code.
Enable? Mir fällt gerade auch auf, das beim Beispiel programm code des AVR GCC ein kurzer Enable Impuls eingetragen ist. Dieser wird scheinbar immer dann ausgefüht, wenn ein Wert übernommen werden soll?!?! Im Tutorial von Sprut.de steht aber nur, das sich bei 1 Signal auf E das Display ansprechen lässt. Achja, muss ich unbedingt eine LCD Clear routine ausführen, damit nach dem initialisieren der balken verschwindet? Oder geht der automatisch weg?
Halt ich für ein Gerücht, das steht da nicht. Nach der Initialisierung ist das Display leer, da siehst du ob es funktioniert hat. Das pdf von Hannes ist auch ganz toll.
Ja, das mag sein. Naja ich glaube nach 3 stunden rumprobiererei... Jedenfalls währe es schön einfach mal ein einfaches beispiel nur zur initialisierung zu haben. Gibts nicht irgendeine gute website auf der sowas für "anfänger" geschrieben ist? Ich finde den code sehr groß, vor allem weil in jeder funktion wieder eine andere aufgerufen wird etc.
Ja hier das Tutorial auf der Seite. Die Fehler, die oben auftauchen, liegen an deinem compiler. Der hat bestimmte Definitionen des gcc nicht bzw. andere. Wenn du keine Programmiererfahrung hast, dann solltest du erstmal mit ASM loslegen oder das Handbuch zu dem Compiler lesen. Ach und fang bei Schritt 1 an. LED Blinken lassen im 2Hz Rhythmus, dann 2 LED blinken lassen und zwar gleichzeitig und dann mal entgegengesetzt. Das erspart dir viel Zeit und Frust...
Hmm, also in C bekomme ich sowas bereits hin. Mit Timer etc. Auch Interruptroutinen kann ich programmieren. Z.b. eine Ampelschaltung mit LEDs. BEi Interrupt wird dann den Fußgängern das überqueren ermöglicht... solche spielereien. Asm möchte ich mir einfach nicht antun. Ich werde für meine Prüfung ohnehin nur c brauchen, da muss man nicht noch soetwas lernen.
Ist ehrlich schwer vorstellbar mit Ampel und Interrupt... Also ich kann kein C und find das alles recht gut und easy im Tut. erklärt. ASM "antun", man glaubt garnicht wie hilfreich das manchmal sein kann. Erst wird die Funktion jedes Pins des LCD erklärt, übrigens auch bei sprut. Und dann die einzelnen Funkionen.. void lcd_data(unsigned char temp1); sendet Daten an das Display void lcd_command(unsigned char temp1); sendet einen Befehl an das Display void lcd_enable(void); // erzeugt den Enable-Puls void lcd_init(void); // Initialisierung: // Muss ganz am Anfang des Programms aufgerufen werden. usw. void set_cursor(uint8_t x, uint8_t y); die Funktion macht nen Error weil dein Compiler wohl uint8_t nicht kennt aber die Funktion brauchst du eh noch nicht. also void lcd_init(void) { LCD_DDR = LCD_DDR | 0x0F | (1<<LCD_RS) | (1<<LCD_EN); // Port auf Ausgang schalten -> brauchst du nicht // muss 3mal hintereinander gesendet werden zur Initialisierung _delay_ms(15); hm, wie lautet die warte 15ms Funktion in Ride? -> So jetzt werden die Pins gesetzt. LCD_PORT &= 0xF0; LCD_PORT |= 0x03; LCD_PORT &= ~(1<<LCD_RS); // RS auf 0 -> Enable Puls lcd_enable(); _delay_ms(5); ->Warten usw..... jetzt kannst du das doch für deines anpassen. void display_init (void) { wait (50); -> ersetzen durch warteschleife 40ms E=0; // Enable ausschalten //initialisieren f�r 4 bit RS=0; //Steuerregister auswählen DB7=0; //Datenleitungen einstellen DB6=0; DB5=1; DB4=1; E=1; //Enable Leitung triggern wait (1us); //kleine Pause E=0; ..... So. unt wenn du schon mit Interrupts gearbeitet hast, dann kannst du ja den Timerinterrupt nutzen um die Pause zu machen, falls dein Compiler keine wartefunktion hat.
> Asm möchte ich mir einfach nicht antun.
Schade eigentlich. Denn der Controller kann kein C, der kann nur
Maschinencode, der einszueins nur in Assembler notiert werden kann. Mit
C alleine kommst Du vielleicht unter einem Betriebssystem zurecht, bei
Mikrocontrollern ist man aber sooooo dicht an der Hardware, dass
Assemblerkenntnisse schon erforderlich sind. Die Leute, die gute
C-Programme für Mikrocontroller schreiben, die können auch alle
Assembler.
...
Hmm ja, könnte ich machen ;) Also zu dem enable. Wenn ich daten an den controller schicken will muss ich zunächst auf E=0 schreiben. Dann kurz warten. Dann in RS und RW=0 schreiben. kurz warten. Dann E=1 setzen. Jetzt gebe ich meine steuerbefehle auf die Leitung. kurz warten. E=0 setzen. Mit der negativen Flanke werden die steuerdaten übernommen. Ist das so korrekt? Das brauche ich ja dann quasi immer, weil nur dann daten vom HD controller bearbeitet werden. Achja, bei Sprut.de ist eine tabelle für den HD controller, wie man in den 4 bit modus kommt. (im anhang) Wenn ich das schritt für schritt genauso nachprogrammiere, müsste mein display doch initialisiert sein, oder? Natürlich mit dem zwischenschritt, dass ich die daten immer nur per wechsel von E auf 0,1,0 in den Controller reinbekomme. Korrekt?
> Wenn ich das schritt für schritt genauso nachprogrammiere, müsste mein > display doch initialisiert sein, oder? Du kannst programmieren was Du willst, wenn Du das Verhalten Deines Compilers nicht kennst, kommt sowiso was anderes raus als Du denkst programmiert zu haben. Ich kann kein C, ich programmiere in Assembler, aber nur AVRs. Man liest hier aber immer wieder, dass C-Compiler Warteschleifen wegoptimieren und auch sonst ein gewisses Eigenleben entwickeln. Einziger Weg, Sicherheit zu haben, ist das Überprüfen des vom C-Compiler erzeugten Assemblercodes, dazu sollte man aber etwas Assembler können. Nächster Punkt: Du benutzt einen relativ schnellen Quarz. Könnte es sein, dass das Timing deshalb nicht einzuhalten ist? Highspeed ist nicht immer der beste Weg... Im Übrigen habe ixch den Eindruck, dass Du hier völlig orientierungslos mit Versuch und Irrtum experimentierst, anstatt die Sache mal systematisch anzugehen. Im von mir weiter oben geposteten Pollin-Datenblatt (in Deutsch) sind in Kurzfassung die Algorithmen zur Initialisierung beschrieben. Du musst sie nur noch in der Programmiersprache Deiner Wahl umsetzen und dabei das Timing einhalten. Wenn Du aber zuviele Baustellen gleichzeitig hast, also weder den Algorithmus verstehst, noch mit Deiner Programmiersprache umgehen kannst, dann hast Du schlechte Karten, dann solltest Du wirklich nochmal mit kleineren Projekten beginnen, die Aussicht auf Erfolg haben, um durch Training sattelfest zu werden. ...
also erst Daten anlegen, dann einmal enable auf 1, kurz warten wieder auf 0. Ja wenn du das so programmierst, dann sollte das Display initialisiert werden und auch leer sein.
Irgendwo im Datenblatt steht bestimmt, was man dem Display für Signale senden muss, damit es funzt. Diese Funktionen programmierst du dann selber in C (sollte für dich ja kein problem sein, nach der Ampelsteuerung) Dann noch was zum Thema for-Schleifen optimierung: Den Grad der Optimierung kann man in der Regel einstellen. Wenn du Wartezeiten mit for-Schleifen programmierst, ist es ratsam ohne Optimierung zu arbeiten, da diese sonst wegoptimiert werden.
Hannes Lux wrote: > Ich kann kein C, ich programmiere in Assembler, aber nur AVRs. Man liest > hier aber immer wieder, dass C-Compiler Warteschleifen wegoptimieren und > auch sonst ein gewisses Eigenleben entwickeln. Einziger Weg, Sicherheit > zu haben, ist das Überprüfen des vom C-Compiler erzeugten > Assemblercodes, dazu sollte man aber etwas Assembler können. "Eigenleben". Hallo. Da wird was optimiert (schneller, kleiner, besser), nur weil du die C-Syntax nicht verstehst und noch nie was programmiert hast, heisst das nicht das der Compiler etwas falsch macht. Am besten bleibst du doch bei deinem Assembler, da wirst du nicht vom C ueberfordert.
@Stephan Klaro kenn ich Volatile!!! Aber ich will doch den Highspeed-Oliver nicht mit solchen Ausdrücken verwirren. Der läuft ja mit dem Display schon auf Anschlag. Nach meiner Meinung ist eine Antwort nur immer so gut, wie sie vom Zuhörer verstanden wird!
Hallo Hannes, ich habe mir natürlich dein Datenblatt durchgelesen. Dort steht erstmal die eigenschaft mit dem E etwas anders beschrieben, als ich das verstanden habe. Z.b. ist dort nirgends die rede von einer ansteigenden Flanke, also von low nach high. Im Internet laß ich, dass ich beim ersten Schritt nach dem ich >15ms gewartet habe erst einmal E=0 setze. Danach lege ich RW und RS auf 0 um zu signalisieren, dass nun daten kommen, die ins steuerregister geschrieben werden. Danach warte ich eine kurze zeit. Dann setze ich E=1. Mit der steigenden Flanke werden beide werte gelesen. Das Display weiß nun was zu tun ist und mit der nächsten fallenden Flanke werden die Werte an DB übernommen. Dannach soll ich >4,1ms warten. Danach wieder dasselbe. E=0. Kurz warten. Dann RS=0 RW=0. Kurz warten. E=1. kurz warten. An DB 4-7 meine Befehle anlegen, E=0. Es wird übernommen. Dann warte ich 100us. Und wieder das gleiche... Hiermit habe ich dann 3x D5 und D4 auf 1 gesetzt und den Rest auf Null. So, nun stelle ich auf 4Bit datenbus um. Dafür schreibe ich eine Hex2 also 10 rein. DB5 also auf 1 und DB4 auf0. Der Rest liegt auf Null. Ist für mich bis hierher verständlich. In deinem text-lcds wird nun der schritt system set ausgeführt. Im Tutorial von Sprut.de wird das in 10 Schritten getan. Wohl deshalb, weil man ja nun im 4 Bit modus ist und die beiden Nibbles geteilt übertragen muss. Ausserdem wird das display dort noch ein und aus- geschaltet sowie gelöscht. Das letzte was ich dann schreiben müsste währe nurnoch display on. Dann sollte das Display anspringen... Ich bin mir eignetlich ziehmlich sicher, dass es dann so funktioonieren sollte. Das mit dem Compiler und wegoptimieren von schleifen kann natürlich sein...Ich werde am besten mal einen echten Timer verwenden.
Stephan wrote: > Hannes Lux wrote: >> Ich kann kein C, ich programmiere in Assembler, aber nur AVRs. Man liest >> hier aber immer wieder, dass C-Compiler Warteschleifen wegoptimieren und >> auch sonst ein gewisses Eigenleben entwickeln. Einziger Weg, Sicherheit >> zu haben, ist das Überprüfen des vom C-Compiler erzeugten >> Assemblercodes, dazu sollte man aber etwas Assembler können. > > "Eigenleben". Hallo. Da wird was optimiert (schneller, kleiner, besser), > nur weil du die C-Syntax nicht verstehst und noch nie was programmiert > hast, Woher willst Du wissen, ob ich "noch nie was programmiert" habe? Ich habe schon einige Dinge programmiert, aber eben nicht in C oder BASCOM, sondern in AVR-Assembler. Und natürlich auch nicht für 8051er oder PICs, sondern für AVRs. Und ob Du es glaubst oder nicht, meine Programme funktionieren, meine LCDs machen das, was sie sollen. Und das alles mit eigenem (ASM-)Code, entwickelt aus den Angaben in den Datenblättern, also nicht durch Verwendung irgendwelcher Bibliotheken irgendwelcher Herkunft. > heisst das nicht das der Compiler etwas falsch macht. Das habe ich auch nicht behauptet. Ich habe lediglich behauptet, dass es sehr vorteilhaft ist, wenn man seinen Compiler (falls man denn einen benutzt) kennen sollte bzw. sein Ergebnis (in ASM) überprüfen sollte. > Am besten bleibst du doch bei deinem Assembler, Ja sicher bleibe ich bei Assembler, die von mir benutzten AVRs bleiben doch auch bei ASM (bzw. Maschinenvode) und lernen doch auch kein C. Assemblerprogrammierung ohne C-Kenntnisse geht ganz gut, C-Programmierung ohne ASM-Kenntnisse aber scheinbar nicht oder nur begrenzt. > da wirst du nicht vom C > ueberfordert. Da verwechselst Du wohl was... Ich bin nicht der, der Hilfe sucht, Du sprichst also den falschen an. Wenn ich ein Verständnisproblem habe, dann gehe ich den Dingen auf den Grund, versuche also aus den vorhandenen Quellen die nötigen Informationen zu ziehen und die Zusammenhänge zu verstehen. Dann bin ich auch in der Lage, mir die notwendigen Routinen (in ASM) zu schreiben. Das dauert zwar meist etwas länger, hat aber den kleinen Vorteil, dass ich über jedes Byte meines Codes Bescheid weiß. Nichts gegen C, wer es kann, soll damit glücklich werden. Aber wer C wirklich kann, der kann auch etwas ASM... ...
Oliver D. wrote: > Womit mir immer noch nicht geholfen wäre... Wenn Du vermutest, dass Dein Compiler die Warteschleifen nicht korrekt umsetzt, dann solltest Du Dir als erstes den vom Compiler erzeugten Code in ASM anzeigen lassen und überprüfen, ob der Compiler das gemacht hat, was Du von ihm erwartest. Solange diese Unsicherheit da ist, lohnt es sich nicht, über den Rest nachzudenken. Und da ich mich (bezüglich Mikrocontroller) nur in der Niesche AVR-Assembler auskenne, kann ich Dir auf dem 8051 leider nicht helfen. ...
Hmm ok. Ich setz mich mal ebend dran mit einem echten Timer die wartezeiten zu programmieren. .... Damit ich den fehler von seiten des compilers her ausschliessen kann.
Probiers doch mal mit volatile: statt: int i; ... for(i=0;i<100;i++); machst du einfach: volatile int i; ... for(i=0;i<100;i++); und der compiler kuerzt dir nix weg. Ach ja Hannes, nur weil du auf ASM beschraenkt bist, musst du nicht beleidigt sein.
So, ich habe hier mal was mit timer programmiert. Ich habe mich dabei zu 100% an die anleitung von sprut.de gehalten. Es müsste so funktionieren, tut es aber nicht. Timing ist auch genug drinne!
Hier auch einfach mit volatile. Funktioniert ebenfalls nicht :(
hallo du hast da was mit dem Enable E falsch verstanden. Du setzt deine Datenleitungen und machst dann kurz Enable an, um den Controller zu sagen das er die Daten jetzt verarbeiten kann. E=0; DB7=0; DB6=0; DB5=1; DB4=1; //Daten setzen warten E=1; warten E=0; // Enable an und aus warten nächster Block
Hast du das an meinem Code erkannt? Ich dachte das es soo richtig ist. Erst E=0. Dann RS=0 und RW=0. Dann setze ich E=1. Durch die steigende Flanke + RS und RW nimmt der HD controller an, dass nun in steuerregister geschrieben wird. Dann lege ich an die DBs meine daten an. Ich setze E=0. Bei der negativen Flanke werden die Daten eingelesen.
Wie schon 10mal erwähnt in dem Thread erwähnt, der Display Controller übernimmt immer von low nach high die Daten. Du setzt erst e=1 und änderst dann die Bits und setzt e=0. Erst e=0, dann die Bits setzen und dann erst e=1; void display_init (void) { wait (500); E=0;// E auf 0 Setzen. //initialisieren f?it RS=0; //Interface auf 8 bit setzen tst_nop(); DB7=0; DB6=0; DB5=1; DB4=1; tst_nop(); tst_nop(); tst_nop(); E=1;//Bei wechsel von low auf high wird die flanke erkannt und mit R/Wlow ein Schreibzugriff sowie mit RS=0 // die Daten als Kommande verstanden und in den Steuerregister geschrieben. E=0;
???? Also das tut mir jetzt leid, dass ich hier etwas falsches schreibe, aber auf Sprut.de steht: Im Moment der Low-High-Flanke von ENABLE liest das Dislplay die Werte von RS und R/W ein. Ist zu diesem Zeitpunkt R/W=0, dann liest das Display mit der folgenden High-Low-Flanke von ENABLE den Datenbus ein (Schreibzyklus). War aber R/W=1, dann legt das Display ein Datenword auf den Datenbus (Lese-Zyklus), solange bis die High-Low-Flanke von ENABLE das Interface wieder deaktiviert. Schreiben zum Display Die folgende Abbildung zeigt einen Schreibzugriff auf ein Display. 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. Liegt zu diesem Zeitpunkt R/W auf Low, dann weiß das Display, daß ein Schreibzugriff erfolgt, und bereitet sich darauf vor, mit der High-Low Flanke von ENABLE die Daten vom Datenbus ( DB0..DB7 ) einzulesen. Dazu muß das Display aber noch wissen, wohin diese Daten geschrieben werden sollen. Liegt RS auf low, so werden die Daten als Kommando verstanden, und in ein Steuerregister geschrieben. Liegt aber RS auf High, so handelt es sich um Daten, die angezeigt werden sollen, und in den Textpuffer (DDRAM) zu schreiben sind. (oder um die Definition eines neuen Zeichens) Ist also das, was auf Sprut.de steht, falsch?!?! Denn dort steht ja drin, das man erst RS und RW mit positiver flanke lesen soll. Bei der negativen werden dann die die daten vom datenbus gelesen.
Und was soll das bedeuten? Du setzt erst e=1 und änderst dann die Bits und setzt e=0. Erst e=0, dann die Bits setzen und dann erst e=1; Das widerspricht sich doch.
Hi! >Wie schon 10mal erwähnt in dem Thread erwähnt, der Display Controller >übernimmt immer von low nach high die Daten. Das ist ein ganz schlimmer Irrtum. Mit HL werden die Daten übernommen, jedenfalls bei HD44780 & Co. E kann übrigens immer auf H stehen, nur zur Datenübernahme muss es mal auf L. Viel Erfolg, Uwe
LOL Also kann mir nunmal jemand die korrekte Reihenfolge geben? Ist es richtig, dass ich zumindest fürs schreiben in den steuerregister: E=0; RS=0; RW=0; E=1; DB7.. DB6.. DB5.. DB4.. E=0; schreiben muss? Ist das so vom ablauf her korrekt?
Also ich setze zuerst, während E noch auf L ist, RS und die Daten (RW ist fest auf L, da ich kein Busy-Flag abfrage), dann warte ich einige Takte, dann setze ich E auf H, warte wieder einige Takte und setze danach E wieder auf L. Und das funktioniert. ...
@Oliver nein das ist noch nicht richtig so. Du stellt zuerst die Daten richtig ein (E steht auf E=0): RS.. RW.. DB7.. DB6.. DB5.. DB4.. dann sagst du dem Displaycontroller, dass die Zustände jetzt da sind und er sie einlesen/bearbeiten kann: E=1; kurz warten E=0; (erst durch das setzen und rücksetzen von E liest der Displaycontroller die Daten die auf RS,RW,DB7 usw. sind) dann wartest du deine Vorgeschriebene Zeit ab. Jetzt kannst du Datenleitungen auf den nächsten gewüschten Zustände setzen: RS.. RW.. DB7.. DB6.. DB5.. DB4.. jetzt musst du dem Controller wieder sagen das die Daten fertig sind und er sie einlesen kann: E=1; kurz warten E=0; so geht das jetzt jedesmal weiter (das siehst du auch im tut., da kommt nach jeder Befehlseingabe [lcd_enable(); und _delay_ms(5);])
Ok Dankeschön. Ich probier es nachher aus. Aber was mich wundert ist, dass es in dem Tutorial von sprut.de, welches ja auch hier auf der seite verlinkt ist, etwas anders steht! .... Egal. Ich probiers nachher aus. Danke nochmal.
Hmm funktioniert immer noch nicht... auch nicht mit timer. Die Zeiten sind dabei schon ziehmlic lang eingestellt...
Vielleicht hilft dir das ja weiter, ist allerdings für einen Mega8
1 | .equ F_CPU, 3686400 |
2 | .include "AVR.H" |
3 | ;--------------------------------------------------------------------------- |
4 | ; Reset- und Interruptvektoren ; VNr. Beschreibung |
5 | rjmp main ; 1 POWER ON RESET |
6 | reti ; 2 Int0-Interrupt |
7 | reti ; 3 Int1-Interrupt |
8 | reti ; 4 TC2 Compare Match |
9 | reti ; 5 TC2 Overflow |
10 | reti ; 6 TC1 Capture |
11 | reti ; 7 TC1 Compare Match A |
12 | reti ; 8 TC1 Compare Match B |
13 | reti ; 9 TC1 Overflow |
14 | reti ; 10 TC0 Overflow |
15 | reti ; 11 SPI, STC Serial Transfer Complete |
16 | reti ; 12 UART Rx Complete |
17 | reti ; 13 UART Data Register Empty |
18 | reti ; 14 UART Tx complete |
19 | reti ; 15 ADC Conversion Complete |
20 | reti ; 16 EEPROM Ready |
21 | reti ; 17 Analog Comperator |
22 | reti ; 18 TWI (I²C) Serial Interface |
23 | reti ; 19 Store Program Memory Ready |
24 | ;--------------------------------------------------------------------------- |
25 | ; Start, Power ON, Reset |
26 | main: ldi r16,lo8(RAMEND) |
27 | out SPL,r16 ; Init Stackpointer LO |
28 | ldi r16,hi8(RAMEND) |
29 | out SPH,r16 ; Init Stackpointer HI |
30 | rcall LCD_init |
31 | rcall LCD_clear |
32 | ;--------------------------------------------------------------------------- |
33 | mainloop: rcall wait |
34 | ldi r16,'H' |
35 | rcall LCD_data |
36 | ldi r16,'a' |
37 | rcall LCD_data |
38 | ldi r16,'l' |
39 | rcall LCD_data |
40 | ldi r16,'l' |
41 | rcall LCD_data |
42 | ldi r16,'o' |
43 | rcall LCD_data |
44 | ldi r16,' ' |
45 | rcall LCD_data |
46 | |
47 | rcall LCD_line2 |
48 | |
49 | ldi r16,'W' |
50 | rcall LCD_data |
51 | ldi r16,'e' |
52 | rcall LCD_data |
53 | ldi r16,'l' |
54 | rcall LCD_data |
55 | ldi r16,'t' |
56 | rcall LCD_data |
57 | ldi r16,' ' |
58 | rcall LCD_data |
59 | |
60 | rcall LCD_home |
61 | |
62 | rjmp mainloop |
63 | ;=========================================================================== |
64 | ; hier Unterprogramme und Interruptroutinen zufügen |
65 | ;--------------------------------------------------------------------------- |
66 | wait: push r24 |
67 | ldi r24,0x13 ; hier delay einstellen 13 = ca. 20yS |
68 | w1: subi r24,0x01 |
69 | rcall wait20ms |
70 | brcc w1 |
71 | pop r24 |
72 | ret
|
73 | ;--------------------------------------------------------------------------- |
74 | wait5ms: ldi r16,255 |
75 | ldi r17,26 |
76 | w5ms: dec r16 |
77 | brne w5ms |
78 | dec r17 |
79 | brne w5ms |
80 | ret
|
81 | ;--------------------------------------------------------------------------- |
82 | wait20ms: ldi r16,255 |
83 | ldi r17,104 |
84 | w20ms: dec r16 |
85 | brne w20ms |
86 | dec r17 |
87 | brne w20ms |
88 | ret
|
89 | ;--------------------------------------------------------------------------- |
90 | LCD_init: sbi DDRD,2 ; LCD RS = OUT |
91 | sbi DDRD,3 ; LCD E = OUT |
92 | sbi DDRD,4 ; LCD D4 = OUT |
93 | sbi DDRD,5 ; LCD D5 = OUT |
94 | sbi DDRD,6 ; LCD D6 = OUT |
95 | sbi DDRD,7 ; LCD D7 = OUT |
96 | cbi PORTD,2 ; LDC RS = Low |
97 | |
98 | ; warte bis PowerUp |
99 | ldi r18,20 |
100 | powerup: rcall wait5ms |
101 | dec r18 |
102 | brne powerup ; Power-Up Wartezyklus min 30 ms |
103 | |
104 | ; sende Resetsequenz kompatibel zu HD44780 Industriestandard |
105 | ldi r16,0b00110000 ; Reset-Sequenz Teil 1 |
106 | out PORTD,r16 |
107 | rcall LCD_enable ; Enable-Impuls |
108 | rcall wait5ms |
109 | ldi r16,0b00110000 ; Reset-Sequenz Teil 2 |
110 | out PORTD,r16 |
111 | rcall LCD_enable ; Enable-Impuls |
112 | rcall wait5ms |
113 | ldi r18,100 ; Wartezyklus bei RESET LCD min 100 µs |
114 | resetLCD: |
115 | nop
|
116 | nop
|
117 | nop
|
118 | dec r18 |
119 | brne resetLCD |
120 | ldi r16,0b00110000 ; Reset-Sequenz Teil 3 |
121 | out PORTD,r16 |
122 | rcall LCD_enable ; Enable-Impuls |
123 | rcall wait5ms |
124 | |
125 | ; sende init 1 |
126 | ldi r16, 0b00100000 ; 4 Bit Modus aktivieren |
127 | out PORTD, r16 |
128 | rcall LCD_enable ; Enable-Impuls |
129 | rcall wait5ms |
130 | ldi r16, 0b00101000 |
131 | rcall LCD_cmd ; Function Set 4 Bit, 2 Zeilen, 5x7 |
132 | rcall LCD_off |
133 | rcall LCD_clear |
134 | ldi r16, 0x06 |
135 | rcall LCD_cmd ; Entry Mode Set, increase+shifted |
136 | rcall LCD_on |
137 | ret
|
138 | ;--------------------------------------------------------------------------- |
139 | LCD_data: ldi r18,0b0000100 ; RS = hi |
140 | rjmp LCD_out |
141 | ;--------------------------------------------------------------------------- |
142 | LCD_cmd: ldi r18,0b0000000 ; RS = lo |
143 | LCD_out: mov r17,r16 |
144 | swap r17 |
145 | andi r16,0b11110000 |
146 | or r16,r18 |
147 | andi r17,0b11110000 |
148 | or r17,r18 |
149 | out PORTD,r16 |
150 | rcall LCD_enable |
151 | out PORTD,r17 |
152 | rcall LCD_enable |
153 | rcall wait5ms |
154 | ret
|
155 | ;--------------------------------------------------------------------------- |
156 | LCD_enable: sbi PORTD,3 ; Enable high |
157 | nop ; kurz warten |
158 | nop
|
159 | nop
|
160 | cbi PORTD,3 ; Enable wieder low |
161 | ret
|
162 | ;--------------------------------------------------------------------------- |
163 | LCD_clear: ldi r16,0b00000001 ; Display löschen |
164 | rcall LCD_cmd |
165 | rcall wait5ms |
166 | ret
|
167 | ;--------------------------------------------------------------------------- |
168 | LCD_off: ldi r16,0b00001000 |
169 | rcall LCD_cmd |
170 | rcall wait5ms |
171 | ret
|
172 | ;--------------------------------------------------------------------------- |
173 | LCD_on: ldi r16,0x0E |
174 | rcall LCD_cmd |
175 | rcall wait5ms |
176 | ret
|
177 | ;--------------------------------------------------------------------------- |
178 | LCD_home: ldi r16,0b00000010 ; Display Cursor HOME |
179 | rcall LCD_cmd |
180 | rcall wait5ms |
181 | ret
|
182 | ;--------------------------------------------------------------------------- |
183 | LCD_line1: ldi r16,0b10000000 ; DRAM auf Adresse 0x00 |
184 | rcall LCD_cmd |
185 | rcall wait5ms |
186 | ret
|
187 | ;--------------------------------------------------------------------------- |
188 | LCD_line2: ldi r16,0b11000000 ; DRAM auf Adresse 0x40 |
189 | rcall LCD_cmd |
190 | rcall wait5ms |
191 | ret
|
192 | ;--------------------------------------------------------------------------- |
193 | ; Goto r16 = Adresse (Zeile 1 = 0x00..0x0F, Zeile 2 = 0x40..0x4F) |
194 | LCD_goto: ori r16,0b10000000 ; Goto DRAM auf Adresse r16 |
195 | rcall LCD_cmd |
196 | rcall wait5ms |
197 | ret
|
198 | ;--------------------------------------------------------------------------- |
Kleiner Tipp: Mach den Takt des Controllers mal gaaanz lahm (100Hz z.B.) und häng an jede Daten- und Steuerleitung eine LED. Dann siehst du, was sich wirklich tut und was eben nicht. Sofern dein Controller mit einem solchen Takt noch läuft natürlich. Kannst auch einen Taster an den Takteingang hängen, dann hast du sowas wie Einzelschrittmodus. Nur sollte der dann nicht zu stark prellen. Oder hast du sowas wie einen Logic Analyser?
Ah jo, da sieht man ebenfalls, wie erst die daten bei EN= Low geschrieben werden. Dann kurz mit enable fuktion einmal an und ausgeschatet wird... Ich werde es nun erstmal ordentlich mit timerfunktion etc. programmieren, bevor ich hier weitere Fragen stelle ;)
Ich kenne deine Verdrahtung ja nicht, aber ich würde die nicht genutzen Signaleingänge des Displays alle auf GND legen. Nur um keine Zicken rein zubekommen.
Oliver D. wrote: > So, ich habe hier mal was mit timer programmiert. > > Ich habe mich dabei zu 100% an die anleitung von sprut.de gehalten. > Es müsste so funktionieren, tut es aber nicht. > Timing ist auch genug drinne! nochmal was zu deinem Code vom 09.11.2007 17:41 : void display_init (void) { unsigned int timerstate; LED=0xFF; if(TF0==1) // Bei einem Z�hler�berlauf wird timerstate inkrementiert { timerstate++; } //mindestens 15ms warten, getan durch timestate >= 20 if(timerstate>=20 && timerstate <= 23) { EN=0;//Low setzen LED=0; }usw. das is ja schön und gut mit deinem timer, aaaber da solltest du mal mindestens eine while-Schleife oder so drum setzen, sonst rennt dein Programm genau einmal komplett durch "display_init" ohne irgend eine if Bedingung zu erfüllen und springt wieder zurück zu main und nichts passiert. nur mal so nebenbei :-)
Hallo, oben siehst du, dass die funktion display init heisst. Sie wird einmal in meinem hauptprogramm ausgeführt. Danach kommt for schleife mit (;;) Das problem kann ich also ausschliessen. Der Tipp mit den LEDs und takt ist ne gute geschichte... Leider habe ich nur ein 11,0592mhz quarz und sonst nix :( Ich werde heute mal alles ordentlich programmieren und dann nochmal reinstellen!
Achja, ist es zwingend erforderlich oder überhaupt machbar, die ports des Displays bei nichtverwenden auf GND zu legen? Ich arbeite ja nur im 4 bit modus und viele pins sind unbenutzt... Sollte man dann alles auf GND legen oder eher nicht?
WUUUUHUUUUUUUUU JABBA DABBA DOOOO ES KLAPPT!!!! Ich habe endlich alles ordentlich programmiert und ich sehe wie das display in den 2 zeilen modus wechsel!!! Oh man geil. Das ist echt toll als Anfänger sowas hinzubekommen und bestärkt einen, einen weiteren nachmittag dran zu arbeiten. Ich poste einfach mal den source code... Vielleicht gibts ja noch jemanden der dasselbe am at89s52 machen will. Danke nochmal an alle, die an mich geglaubt haben ;)
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.