Forum: Mikrocontroller und Digitale Elektronik LCD Ausgabe


von Tim Kohler (Gast)


Lesenswert?

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

von Klaus (Gast)


Lesenswert?

Und was hat das jetzt mit dem Z-Pointer zu tun?

von Tim Kohler (Gast)


Lesenswert?

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

von Niels H. (monarch2)


Lesenswert?

"\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.

von Tim Kohler (Gast)


Lesenswert?

Dankeschön

Tim

von Tim Kohler (Gast)


Lesenswert?

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

von Hannes L. (hannes)


Lesenswert?

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).

...

von Rennesson (Gast)


Lesenswert?

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

von Tim Kohler (Gast)


Lesenswert?

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

von Niels H. (monarch2)


Lesenswert?

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

von Tim Kohler (Gast)


Lesenswert?

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

von Hannes L. (hannes)


Lesenswert?

> "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?

...

von Tim Kohler (Gast)


Lesenswert?

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

von Niels H. (monarch2)


Lesenswert?

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"

von Tim Kohler (Gast)


Lesenswert?

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

von Hannes L. (hannes)


Lesenswert?

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.


...

von Tim Kohler (Gast)


Lesenswert?

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

von Germo (Gast)


Lesenswert?

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?

von Hannes L. (hannes)


Lesenswert?

> 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.

...

von Simon K. (simon) Benutzerseite


Lesenswert?

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.

von Simon K. (simon) Benutzerseite


Lesenswert?

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!

von Tim Kohler (Gast)


Lesenswert?

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

von Hannes L. (hannes)


Lesenswert?

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
Noch kein Account? Hier anmelden.