Hallo, auch! Ich bräuchte mal Hilfe von den Profis hier, da ich auch nach Google und Forensuche keine Lösung für mein Bescheidenes Problem finden kann... Ich habe eine Standard 2x16-Display (Hd44780 o.ä.) an einem AT89S8252 im 8-Bit-Modus im betrieb. Mit Assembler läuft das auch alles wunderbar, nur in C haperts halt. Hat jmd. zufällig einen Lauffähigen C-Code zur init. und evtl. noch ein Ausgabebeispiel für Textstrings. Am liebsten natürlich für den 89s8252. Besten Dank schonmal! Gerne auch direkt an: bayluga@freenet.de
Wo ist das Problem? Setz doch einfach dein ASM-Code in C um... Fertigen Code wirst du kaum finden, ohne ihn auf dein System anpassen zu müssen. Poste doch einfach mal deinen ASM-Code, und was du in C draus gemacht hast, dann kann dir geholfen werden. Ralf
Puh, habs dann doch irgendwie geschafft, dass der Apparat irgendwas anzeigt : ) Habe es jetzt jahre ohne C geschafft, aber wenns halt komplizierter wird, kommt man mit .asm dann doch nicht mehr so weit. Ich hab mal den src soweit angehängt und hätte da noch ne Frage oder zwei an Ralf (und wer auch immer das noch liest): - Warum wird das erste Zeichen des Textstrings nicht angezeigt? und - Wie krieg ichs hin, einen Dezimalwert auszugeben? (z.B. 4stellig) Konnte für beides keinen Beispielcode finden. Vielen Dank, Kollegen: ) Thomas.
...Habe es jetzt jahre ohne C geschafft, aber wenns halt komplizierter wird, kommt man mit .asm... Mal rein interesse halber, was geht in ASM nicht ?
Gehen tut natürlich alles. Die Frage ist nur, ob man den Überblick behält. Aber glaub mir, ich bin der ALLERLETZTE, der Assembler nicht zu schätzen wüsste : )
Hi Thomas, sorry für die späte Rückmeldung. Zu deinen beiden Problemen: 1. Zeichen fehlt: Führe doch bitte mal den printf-Befehl zweimal hintereinander aus und sag Bescheid, ob das erste Zeichen immer noch fehlt. 2. Dezimalzahl ausgeben: Ich gebe jetzt mal folgendes vor: - Vierstellige Dezimalzahl heisst, der an die C-Funktion übergebene Parameter ist ein INT. Also sind maximal 5 Stellen möglich. Der zweite Parameter gibt die Position an. Du musst jetzt folgendes machen: 1. Stelle = Zehntausender Du teilst den int durch zehntausend. Das Ergebnis gibst du auf dem Display aus. Ist das Ergebnis 0, so gibst du anstatt einer Zahl ein Leerzeichen aus. Du musst dir merken, ob du eine Zahl oder ein Leerzeichen ausgegeben hast, damit die nächste Stelle korrekt angezeigt wird (Tausender), wenn das Teilen dort eine Null ergibt. Damit sorgst du für eine Unterdrückung der Vorlauf-Nullen. Und das Schema geht bis hin zu den Einern. Ich hoffe, ich konnte es verständlich beschreiben. Bitte um Rückmeldung. Ralf
Hallo, Ralf! Vielen Dank für Deine Antwort. Tja, also das mit dem fehlenden Zeichen hat sich erledigt. Und um ganz ehrlich zu sein, hab ich das mit der Teilerei nicht wirklich verstanden. Kann mann das nicht über modulo machen? Das "Fehlende Zeichen" war übrigens ein Cursorsteuerungsproblem. Das Display ist ein 2x16 mit HD44780 (standard) und laut datenblatt hat zeile 1 die adressen 00h bis 0Fh und zeile zwei geht von 40h bis 4Fh. Ich hab zur Cursorpositionierung eine Funktion geschrieben, die nicht funktioniert, bzw. funktioniert sie nur für die 2te Zeile, wenn man statt 40h einfach C0h nimmt. Das soll einer verstehen. Ich häng den Funktionscode einfach mal an, vielleicht fällt Dir was dazu ein. Hatte das gleiche Phönomen auch schon in assembler. Eigentlich ist mir ja egal, ob die 2te zeile jetzt 40h oder C0h "heisst", nur kann ich halt z.b. das 3te zeichen der 1ten zeile ansprechen. Idee dazu? Solange beschäftige ich mal mit der Teilerei. Vielen Dank schonmal! Thomas
Achso.. hier die Cursorfunktion : ) void move (int cline, int crow) // Funktion für Cursorbewegung { // move (zeile 1...2, Zeichen 1...16) char pos; if(cline==1) pos=0x00; if(cline==2) pos=0x40; pos=pos+crow-1; RS=0;RW=0;P2=pos;EN=1;EN=0; busychk(); RS=1; }
Also, bezüglich der Sache mit 0x40 und 0xC0, ich hab jetzt leider keine Zeit, deinen Code zu prüfen, aber vielleicht komm ich am Wochenende dazu. Allerdings hab ich zwei Links gefunden, die evtl. weiterhelfen können: http://ouwehand.net/~peter/lcd/lcd.shtml http://www.8052.com/tutlcd.phtml Wegen der Teilerei: Ja, das was ich geschrieben habe, ist doch MODULO: Durch 10000 teilen, das Ergebnis wird ausgegeben, wenn es ungleich 0 ist, ansonsten ein Leerzeichen. Das mit 10000 multiplizierte Ergebnis des Modulo ziehst du von deinem Wert ab. Dann kommt genau die gleiche Sache mit den 1000ern, dann die 100er, usw. Ralf
Besten Dank für die Links, Ralf. Nach dem Tutorial auf 8052.com müsste mein Code eigentlich laufen. Obere Zeile also 0x80...0x8F und untere 0xC0...0xCF, aber leider gehts trotzdem nur in der unteren... Wäre super, wenn Du am WE kurz Zeit dafür fändest. Kannst mir das gerne auch per mail senden, falls der Thread für "Könner" zu langweilig wird. bayluga@freenet.de Grütze, Thomaas
Okay, ich guck mal was ich hinkrieg.
Übrigens, kleine Korrektur:
> Ja, das was ich geschrieben habe, ist doch MODULO:
Das ist nicht ganz richtig, ich hab in der Eile Müll geschrieben. Es
ist eine Mischung aus Teilen ohne Rest und Modulo.
Wenn du es nicht hinbekommst, sag Bescheid...
Ralf
Hi Thomas, bist du weitergekommen? Guck mal unter den Artikeln, da gibts auch was zum 44780, vielleicht hilft dir das auch schon weiter ?!? Ralf
Hi, Ralf! Habs erst heute mal wieder Zeit, mich damit zu befassen. Die Cursorsteuerung funktioniert nach wie vor nur für die untere Zeile, in der oberen kann ich immer nur 1. Zeichen ansprechen. Ich muß da irgendwo nen ganz ganz dämlichen Denkfehler drin haben... Werde noch n bisschen dran rumfrickeln. Th
Hi Thomas, wie läufts denn? Bist weitergekommen? Wegen deinem Cursor-Problem, ich kenn mich mit den HD44780 nicht so aus, ich benutze Grafikdisplays mit T6963C-Controller, aber ein Freund hat gemeint, die Adresse 0x40 für die zweite Zeile ist richtig, aber das Bit 7 spielt da noch ne Rolle. Und wenn du bei 0x40 das Bit 7 setzt, dann kommt ja 0xC0 raus... Gucks dir mal im Datenblatt an, was das sein könnte... Ralf
Hallo, Ralf. In der Tat isses so, mit dem C0. Das Bit 7 muss gesetzt sein, damit der LCD-Controller "weiss", dass das eine Datenposition ist. Du hast das mit dem 0xC0 richtig erkannt, denn der zu sendende Wert ist immer 80h (Bit7) + Position. Bei 40h für Zeile 2 Ergibt sich 0xC0. Zeile eins hat aber "Positionswerte" von 00h..bis..0Fh, also dürfte dann ja Stelle eins 80h haben, stelle zwei 81h u.s.w. Das klappt aber leider nicht. Und keiner weiss warum : )
Hi Thomas, > also dürfte dann ja Stelle eins 80h haben, stelle zwei 81h u.s.w. Das > klappt aber leider nicht. So wie ich es sehe, hast du ja dann eigentlich keinen Fehler mit dem 0xC0, sondern mit dem 0x00, denn ich kann im Datenblatt zum 44780 auf die schnelle keine Instruktion entdecken, die 0x00 ist... Erklärs mir bitte nochmal genau, was kommt denn raus, wenn du mit 0x80, 0x81 usw. arbeitest??? Ausserdem ist mir noch was aufgefallen, deine MOVE-Funktion ist so geschrieben, dass die Zeilenangabe 1 oder 2 sein muss. Deine Spaltenangabe würde aber 0 als erstes Zeichen der Zeile akzeptieren. Ist das so beabsichtigt??? Ralf
Hallo Ralf! Danke, dass Du Dich so reinhängst! Hier erstmal die aktuelle move-funktion: void move (int cline, int crow) // Funktion für Cursorbewegung { // move (zeile 1...2, Zeichen 1...16) char pos; if(cline==1) pos=0x80; if(cline==2) pos=0xC0; pos=pos+crow-1; RS=0;RW=0;P2=pos;EN=1;EN=0; busychk(); // Fkt. prüft busy-flag RS=1; } Wir sind uns einig, dass der Wert, der den Cursor positioniert sich zusammensetzt aus: 0x80 (Bit7 High) PLUS der im Datenblatt angegebenen Konstante für die Entsprechende Stelle (Also 0x00...0x0F für die obere und 0x40...0x4F für die untere Zeile). Im klartext bedeutet das, dass der tatsächlich an das Display zu übermittelnde Wert 0x80...0x8F für oben und 0xC0...0xCF für unten ist. Das klappt auch. Allerdings nur für die Zweite Zeile. Das heisst, 0xC2 schiebt den Cursor an Pos. 3 in der 2ten Zeile. Aber in der ersten funktioniert das prinzip eben nicht. Egal, welchen wert von 0x80 bis 0x8F ich sende, der Cursor steht IMMER an 1er Stelle in der 1ten Zeile. Das ist mein Dilemma. Zu der Frage mit der Spaltenangabe: Zeichen 1 bis 16 einzugeben geht schon klar, da in der 3. Zeile von unten ja wieder 1 subtrahiert wird. Thomas.
> ...da in der 3. Zeile von unten ja wieder 1 subtrahiert wird.
Okay, in deiner LCD2.txt die du gepostet hast, war das noch nicht.
Machen wir das mal Hardcore:
Oben hast du irgendwo erwähnt, dass du Assembler-Code hast, der
funktioniert. Poste bitte mal diesen Assembler-Code, und deine aktuelle
C-Software. Und ich sollte wissen, welchen C-Compiler du verwendest
(Keil?).
Ich wills mir mal auf meinem System angucken.
Ralf
Hallo, Ralf. Nach einer Woche hab ichs endlich mal wieder geschafft, mich mit was anderem als der Studiererei zu beschäftigen. Wir machens also mal Hardcore: Ich hab eben mal lauffähigen assemblercode zusammengekloppt, IDE ist natöööörlich Keils µV3. Und siehe da: In asm macht der apparat, was er soll: nämlich den Cursor an die befohlene Adresse setzen. Nur wo ist da jetzt der unterschied zu meiner C-funktion, die da oben irgendwo steht??? Grüsse, Thomas
> char pos;
Wenn du auf Byteebene arbeitest, dann nimm immer
unsigned char
vor allem wenn du wie hier
pos=pos+crow-1;
Arithmetik machst.
Deine Berechnung könnte man auch kürzer schreiben:
unsigned char pos;
pos = 0x80 | // Bit 7 für 'Set Cursor'
( ( cline - 1 ) << 6 ) | // Bit 6 fuer Zeile 1 oder 2
( crow - 1 ); // und dann noch die Bits fuer
// die Spalte
Aber das wichtigste: unsigned char, unsigned char, unsigned char!
Vielen Dank, KH! Aber leider ist das Resultat das gleiche... Positionierung Zeile 2 (also move(2,X);) klappt wunderbar, nur Zeile eins (move(1,X);) will nicht. ganz egal, welchen wert ich für x wähle, der text beginnt immer in spalte 1. Irgendwie ergibt das keinen Sinn... Thomas
Hmm. Das ergibt wirklich keinen Sinn. Eigentlich sollte das so klappen. Knappes Timing?
Okay, es geht doch. Das Problem ist jetzt aber: Ich hab das immer getestet, indem ich die Funktion zwei mal hintereinander aufgerufen habe und beim ersten mal koordinaten für line1 und in der 2ten funktion koordination für line2 mitgegeben habe. In etwa so: .... move(1,3); printf...; move(2,4); printf...; ... Ich hab das jetzt einfach mal andersrum gemacht, also in etwa so: ... move(2,3); printf...; move(1,3); printf...; ... Und es hat sich dabei folgendes herausgestellt: Mit dem der beiden ersten move-aufruf stimmt was nicht, denn die Daten werden danach immer an pos 1,1 geschrieben. Muss wohl irgendwie mit ner RS-Vertauschung oder so zu tun haben. Jedenfalls zweifel ich jetzt nicht mehr an meinem Verstand sonder nur noch an meiner sorgfalt.
das fehlende wort lautet *tusch*: ersten! Mit dem >ERSTEN< der beiden ersten move-aufrufe stimmt was...
Juhuu! Das Problem mit der Cursoposition ist auf ingenieurs-mässige Art und Weise gelöst. Nämlich gepfuscht : ) Ich lass halt die move-funktion einmal sinnlos in der initialisierungssequenz mitlaufen und danach geht das ja dann. Stellt sich direkt die nächste Frage: Wie ist das mit den Variablen, die Dezimalwerte enthalten und diese auf dem LCD dargestellt werden sollen? Sagen wir mal, eine variable "wert" existiere mit dem dezimalwert 3,14 und ich möchte, daß der dezimale inhalt dieser variable auf dem lcd ausgegeben wird. Die Vorgehensweise: float wert; void main (void) { wert=3,14; wert=putchar(wert); printf("%cPi gerundet= "); printf("%f",wert); } bringt's nicht. Vorschläge werden dankend entgegengenommen : )
> printf("%cPi gerundet= "); Ich denke mal das ist ein Tippfehler beim posten :-) Muss natürlich printf( "Pi gerundet= "); heissen. > bringt's nicht. Was heist das? Beim gcc, musst du eine andere Library benutzen, wenn du float Zahlen mit printf ausgeben willst. Mach ich aber nie, daher weis ich auch nicht auswendig welche das ist, bzw. wie man die Umschaltung macht. Stöbere mal im GCC Forum, 'printf' 'Library' 'float'. Jörg hat das schon öfters erklärt.
Da smit dem wert=3,14; klappt nicht, wenn dann musst du 3.14 schreiben. Du musst erst in einen Buffer schreiben. char buffer[17]; // dein display ist ja nur 16 lang, also reichen 17 char *cp; snprintf(buffer, 17, "PI=rund %f", wert); cp = &buffer[0]; // oder einfacher cp = buffer; move(1,1); while(*cp != '\0') { putchar(*cp++); }
snprintf(): die sichere Alternative zu sprintf. Man gibt zusätzlich noch die Größe des bereitgestellten Buffers an. Dadurch ist gewährleistet, dass sprintf den Buffer nicht überrennt. Sei C-99 eine Standardfunktion.
Besten Dank! sprintf funktionert bestens. Ich durchschau zwar den Mechanismus nicht wirklich, aber das Resultat zählt. Cheereo, Thomas
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.