Hallo, ich habe ein kleines Verständnis Problem mit dem Z-Pointer. Ich würde gerne den folgenden Text im 2*16 LCD Display anzeigen lassen (inklusive Zeilenumbruch): ------------------------------------------------------------------------ ----------------------------------------------------------- text: .db "AVR-Assembler ist ganz einfach", 0 ; Stringkonstante, durch eine 0 abgeschlossen ------------------------------------------------------------------------ ----------------------------------------------------------- Der obige Text wird höchstwahrscheinlich nicht so angezeigt, oder? Ich meine, in C kann ich eine Ausgabe ziemlich flexibel gestalten. Wie kann ich diesen Text in Assembler mit Zeilenumbruch auf einmal ausgeben? Danke für die Antworten im Voraus. Gruß Tim
Hallo, in der Tat, das hat nichts mit dem Z-Pointer zu tun. Mein Verständnisproblem hat eigentlich etwas mit der LCD Ausgabe zu tun. Tim
"\n" Bietet sich dafür an. "\n" wird vom Assembler zu ASCII 10 interpretiert. Diesen Wert musst du dann nur noch im Programmcode für dein Display interpetieren.
Hallo, also ich weiß nicht ob ich in einem einzigen String, ein Zeilenumbruch hinbekommen kann. Weder "\n" (abgesehen davon, dass es ich in der Doku. von der LCD Anzeige kein "\" Zeichen gefunden habe) geht, noch was anderes. Heißt jetzt die Alternative, dass ich in einem simplen String z.B. "HalloWelt", den Zeilenumbruch zwischen Hallo und Welt, mit einem kompliziertem Adresssetzverfahren anwenden muss? Tim
Analysiere doch mal die Routinen, die du hier findest: http://www.mikrocontroller.net/forum/read-1-262112.html#262228 Da ist sicher auch das dabei, was du gerade suchst. Es dürfte "printf" sein (steht für Print String aus Flash, hat nix mit printf von C zu tun). ...
wenn du von einem mikrocontroller aus einen text am lcd ausgeben willst dann kommt es darauf an wie dein LCD-Treiber geschrieben ist. er sollte normalerweise dafür sorgen, dass nach 16 zeichen in die 2.Zeile 1.pos gesprungen wird. wenn das nicht der fall ist, dann musst du eine routine schreiben die das bewerkstelligt. gruss rennesson
Hallo, mein LCD Treiber ist von diesem Tutorial. Ein Sprung in die 2. Zeile kommt in diesem Treiber nicht vor. Ich glaube, dass ich mein Code improvisieren muss. Danke nochmal, jetzt ist einiges klarer geworden. Gruss Tim
Ich glaub, du hast da was falsch verstanden... "\n" wird vom Assembler nach ASCII 10 übersetzt. Das bedeutet, dein Programm sieht schematisch so aus: .db "Zeile1\nZeile2\n\Zeile3",0 call init_zeiger_auf_String ma1: ld r0,@zeiger cmp r0,#0 beq ende_der_ausgabe cmp r0,#10 beq display_nächste_zeile call r0_als_Zeichen_ausgeben jmp ma1
Hallo, das "\n" Zeichen wird bei mir einzeln abgelesen. Damit wird das "\" als hexadezimale "5C" gelesen. Meine Routine vergleicht das R0 Register mit irgendein Register auf 5C-Gleichheit. Dann wird ein Rcall Unterprogramm aufgerufen, mit dem der Befehl lcd_command, die zweite Zeile anspricht. Weiß nicht ob das umständlich ist, für mich als Anfänger ist das so okay. Jedenfalls findet so ein Zeilenumbruch statt. Eine Frage habe ich noch. Der Befehl "cpse" überspringt eine Befehlszeile, wenn Gleichheit herrscht. Ist es auch möglich, dass zwei Befehlszeilen übersprungen werden? Grüße Tim
> "cpse" überspringt eine Befehlszeile
Compare, Skip if Equal...
Skip überspringt nur eine Zeile...
Willst du mehr überspringen, dann musst du mit CP vergleichen und mit
einem bedingten Sprung BREQ zu einem Label springen...
Hast du dir denn schon mal die Routinensammlung in dem oben angegebenen
Link angesehen?
Hast du keine Fragen dazu? - Hast du alles verstanden?
...
Hallo, nein leider habe ich mir die links noch nicht angeschaut. Mach ich aber noch morgen. Dann werde ich schlauer und melde mich dann wieder. Gruß Tim
Wenn dein Assembler "\n" nicht interpretiert, könntest du auch das Steuerzeichen direkt in den String schreiben: .db "abc, die katze liegt im schnee",10,"und ist der Schnee mal weg" .db 10,"dann liegt sie bald im dreck"
Hallo @Niels Leider klappt es weder mit 10, noch mit \n. Ich habe den Code so eingepflegt, wie du es beschrieben hast, hat sich nichts ausser einem komischen Zeichen getan. Trotzdem Danke. @HanneS Ich habe mir einige Codezeilen von Dir angeschaut, und den Algorithmus für den Programmcounter analysiert. Ein Zeilensprung wird bei mir folgendermaßen realisiert: - Definition eines Zeilensprungzeichens: z.B.: \ = 5C - Vergleich des Zeigers mit "\", in einer Schleife mit dem Befehl "cp" - Wenn Nein, bearbeite die Zeile weiter. - Wenn Ja, springt mein Programm mit "breq pc+4" in das nächste Unterprogramm (z-Flag gesetzt) - Dort wird explizit der Befehl "11000000" gegeben, sprich Zeilensprung, anschließend wird die nächste Zeile bearbeitet. Ich bin jetzt happy. Trotzdem ergeben sich noch einige Fragen: - Ist die Realisierung von Warteschleifen (50µs, 150µs, 300µs...) mit Timern effizienter, als mit der klassischen Variante? Bedeutet mehr Codezeilen, aber..... - Spricht gegen ein Sprung des Programmcounters um 4 Zeilen etwas dagegen? Danke für eure Mithilfe. Gruß Tim
Also ich kann mich nicht erinnern, dass ich etwas wie "\n" oder andere Steuercodes für Zeilenwechsel empfohlen habe, Ich weiß auch garnicht, ob und wie der Assembler damit umgehen sollte, denn ich denke, dass das aus C stammt, nicht aus ASM. Übrigens nutze ich die LCDs nicht "fortlaufend" (automatisch in der nächsten Zeile weiter ausgeben), da die Zuordnung der Ausgabeposition zu den DD-RAM-Adressen meist nicht linear, sondern verschachtelt ist. Oft sind die RAM-Bereiche für die Zeilen auch größer als die physikalisch vorhandene Zeile, was zwar ein Horizontalscrolling erlaubt (nutze ich nicht), aber eben keine unbekümmerte lineare Ausgabe erlaubt. Ich benutze die LCDs auch nicht (wie Zeilendrucker) mit Steuerzeichen zum "Sprung auf die nächste Zeile". Durch die unterschiedliche Verschachtelung von DD-RAM und Ausgabeposition müsste die Ausgaberoutine ja die Ausgabeposition mitverfolgen, um die korrekte "nächste Zeile" ermitteln zu können. Ich benutze die LCD-Ausgabe meist zeilenweise, manchmal sogar nur zeichenweise. Dazu habe ich das LOCATE-Makro, mit dem ich die Ausgabeposition (Zeile, Spalte) festlege. Danach wird Text für maximal eine Zeile ausgegeben. Zum Darstellen von Zeitungstext oder Webseiten ist dieses Verfahren zwar äußerst ungeeignet, aber ich stelle damit meist Benutzerführungen (Menüs, aufgelistete Parameter) dar, dafür ist diese Vorgehensweise ganz gut geeignet. Mir wäre es zwar auch lieber, wenn Text-LCDs wie (uralte) Zeilendrucker ansteuerbar wären, man also einfach Fließtext mit gelegentlichen Zeilenvorschub-Steuerzeichen senden könnte, vielleicht noch mit einem Eingabebuffer (Pipeline) von 1kB, damit man Text senden kann, ohne nach jedem Byte eine Wartezeit einhalten zu müssen, aber die üblichen LCDs sind nunmal nicht so, sie haben nunmal Regeln, nach denen wir uns zu richten haben. Übrigens habe ich den Befehl "Zeilensprung" (11000000) bei den von mir benutzten LCDs noch nicht gefunden. Sprünge (auch bedingte) führen normal zu Labels, auch Sprungmarken genannt (breq sprungziel), die man im Quelltext definiert (Abschluss mit Doppelpunkt). Gibt man die Sprungweite relativ zum PC an (breq PC+4), dann sollte man in ASM schon recht fit sein, denn da warten Fehlerquellen, nicht jeder ASM-Befehl braucht exakt eine Adresse, da verzählt man sich schnell mal... Über "Warteschleifen" diskutiere ich ungern. Sicher, ich habe sie auch verwendet, besonders bei meinen älteren Programmen mit LCD-Ausgabe, von denen hier im Forum etwas herumgeistert. Aber diese Lösung funktioniert nur, wenn das Programm während der LCD-Ausgabe nix anderes mehr zu tun hat. Inzwischen synchronisiere ich die LCD-Ausgabe über einen Timer und schreibe über einen Ringbuffer auf das LCD. Also ich schreibe aus dem Programm die gesamte Zeichenkette hintereinander (ohne Wartezeiten) in den Ringbuffer, aus dem die Zeichen dann im Hintergrund einzeln (über Timer angeschubst) an das LCD gesendet werden. Das erlaubt Ausgabe ganzer Zeilen ohne Warteschleifen oder Busy-Abfrage. Man muss nur darauf achten, dass man nicht zu viel hintereinander ausgibt, also dass der Text noch in den Ringbuffer passt. Übrigens verstehe ich nicht, warum sich viele Programmierer vor der Verwendung von Timern drücken. So ein Timer-Interrupt macht das Programmieren doch bedeutend einfacher. Er synchronisiert den gesamten Programmablauf und weckt den Controller (oder das Programm?) aus dem Sleep. Also bei mir hat so ziemlich jedes Programm einen Timer-Interrupt, der ständig durchklappert. Ohne wäre das Programmieren viel zu umständlich. Man kann mit Timern zwar auch "Warteschleifen" realisieren, sowas braucht man aber nur sehr selten. Meist lassen sich Wartezeiten schon dadurch anders realisieren, dass man die Betrachtungsweise ändert. Statt "warten (und nixtun), bis der nächste Programmteil abgearbeitet werden darf" sollte man "sofort zur Mainloop zurück und Sinnvolleres tun, wenn der nächste Programmteil jetzt noch nicht abgearbeitet werden darf (und später nochmal vorbeischaun). Man muss da aber schon die ganze Denkweise ändern, mit dem Wartescheleifen-Konzept kommt man da nicht weiter. Allerdings gibt es auch Routinen, wo man auf (extrem kurze) Warteschleifen nicht (oder nur schwer) verzichten kann. Die LCD-Ausgabe gehört da aber nicht dazu. ...
Hallo, Ja du hast Recht Hannes. Der Befehl 11000000 taucht bei Dir nicht auf, dafür bei mir. Bitte nicht falsch verstehen, aber ich möchte ab und zu das Rad neu erfinden. Es macht keinen Sinn ein Code vollständig zu kopieren, und dann zu sagen, ich habs geschafft. Lieber ein paar mal auf die Schnauze fallen, und aus einem Gerüst improvisieren. Dazu kommt noch, dass ich die LCD Routinen aus dem Tutorial genommen habe. Aber auf Dein Code kann man aufbauen, und vor allem viel daraus lernen. Da ich mal davon ausgehe dass du ein Profi bist, gehst du Deine Programmieraufgaben sehr systematisch an. Damit meine ich, dass bei komplexen Aufgaben, kombiniert mit engen Zeit- und Speicherressourcen, du die Kapazitäten optimal ausnutzt. Bis ich dass kann, brauche ich noch eine Weile. Trotzdem finde ich es gut, dass solche Leute wie du bereit sind einem zu helfen. Gruß Tim
Hi, ich habe auch ein kleins Problem mit der Ausgabe von Zeichen auf meinem LCD. Ich habe das gute Stück nun endlich initialisiert bekommen, aber Zeichen will es mir nicht anzeigen. Ich habe ein 16x2 LCD und nach der initialisierung habe ich einen blinkenden Cursor (testweise um zu sehen das er das Display initialisiert hat). Programmieren tu ich das gute Stück mit ICCAVR (also C). Ich setze nach der Initialisierung den RS Pin auf high und schreib dann zB den Buchstaben 'H' (0b01001000 oder 0x48) in den PORTA (ich benutze die vollen 8bit). Jetzt noch einmal die negativ Flanke des Enable Pin und dann solle laut Ddatenblatt auf dem LCD ein H sichtbar sein und der Cursor eine Position weiter, aber stattdessen verschwindet der Cursor und das LCD scheint aus zu sein. Hat jemand ne vielleicht eine Idee wo mein Fehler ist? Hab ich was übersehen?
> Da ich mal davon ausgehe dass du ein Profi bist,... Profi bin ich auf keinen Fall. Wenn ich mich als Profi bezeichnen ließe, wie sollte man denn die Leute nennen, die so etwas beruflich machen? Allerdings beschäftige ich mich schon einige Jahrzehnte gelegentlich mit Elektronik, und seit Kurzem auch mit AVRs. Und dann habe ich mir mein Grundwissen in mühevoller Kleinarbeit erarbeitet und nicht im WWW zusammengesucht oder in Foren zusammengefragt. Wobei Letzteres nicht ganz fair von mir ist, aus diesem Forum hier habe ich sehr viel gelernt, allerdings meist durch Mitlesen aus den Fragen Anderer. Auch ich habe meine Fehler selbst gemacht. Und ich verwende grundsätzlich keine unverstandenen fremden Programmschnipsel. Mir ist ein etwas schlechteres, aber selbstgeschriebenes Programm lieber als ein Zusammengeklautes, was ich nicht verstehe. Trotzdem nutze ich auch gute Algorithmen anderer Programmierer, aber dann habe ich sie wenigstens verstanden. Und ich verstehe auch nicht alles auf Anhieb. Die verdammt gute Tastenentprellung aus der Codesammlung habe ich anfangs auch gemieden, weil ich sie nicht auf Anhieb verstanden habe. Inzwischen ist sie bei mir Standard, wobei ich immer per Kommentar auf den Urheber hinweise. Soviel Fairnis muss sein. Dass ich versuche, systematisch an die Sache heranzugehen, hat damit zu tun, das es "Systeme" sind... Da muss man wohl systematisch rangehen, oder? Übrigens bauen meine LCD-Routinen auch auf die des Tutorials auf. Doch ich habe sie an meine Bedürfnisse angepasse, bzw. bin auf halbem Wege. Denn so richtig gefällt mir das noch nicht, aber kommt Zeit, kommt Rat. Allerdings ist es schon besser als mit Warteschleifen. ...
Ich habe das Gefühl Tim hat noch nicht so ganz verstanden..: Eins ist klar, schickst du ein ascii 'a' an das Display, interpretiert der Fontgenerator auf deinem Display dieses 'a' und schreibt ein 'a' auf die Anzeigefläche. ABER: Genau wie 'a' ist auch '\n' (= 10) ein ASCII Zeichen. Dieses ASCII Zeichen gibts aber so nicht im Display ! D.h. du musst einen Treiber bauen, der immer prüft, ob aktuelles Zeichen = 10, wenn nein, direkt auf das Display ausgeben und zum nächsten gehen, wenn doch, dann eine Adress-setz-funktion am Display ausgeben und zum nächsten Zeichen gehen. D.h. du kannst diese 10 nicht direkt ans Display weiterschicken, es kennt vermutlich diesen Code nicht oder schreibt ein komisches Zeichen.
PS: Auch meine eigenen (HD44780-) Display Routinen kennen kein GeheZurNächstenZeile() und auch keine '\n' erkennung. Ich hab ein Init, ein Locate und ein Writestring Befehl und falls benötigt auch noch ein Writechar. Fertig!
Hallo, @Simon. Ich habe das schon richtig interpretiert. Ich dachte auch, dass eine "\n" als ein ASCII Zeichen verstanden wird, hat es aber nicht. Vielleicht hatte ich auch vergessen zu erwähnen, dass ich es mit einem 2x16 LCD Display zu tun habe, der auf einem KS0070B Controller basiert, aber das düfte nicht den Unterschied ausmachen. Ich werde mich in nächster Zeit noch intensiver mit den Codes von Hannes auseinander setzen, da ich in den letzten Tagen erkältungsbedingt ausser Gefecht gesetzt wurde. Gruß Tim
Ich habe nur (noch lange nicht optimalen) Code für HD44780 und (etwas besseren) für MS50530. Mit KS007B habe ich noch nix gemacht. Es wird dir also (auf die Schnelle) nix helfen, dich mit meinem Code zu befassen. ...
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.