Hi Leute!
Ich nehme hier gerade in 4x20 HD44780 in Betrieb. Klappt auch alles,
also keine Frage zur Ansteuerung an sich, sondern eher über die
geschickteste Variante, die Daten hin zu transferieren.
Ich arbeite mit dem Busy-Flag, also ohne Delays. Obwohl das Busy-Flag
natürlich auch einem Delay gleichkommt, da ich ja warten muss, bis das
Display fertig ist mit dem letzten Befehl.
Jetzt ist die Frage, ob ich mit einen Zeichenpuffer mit 80 Zeichen
anlege und per Timer-Interrupt immer im bestimmten Abstand das ganze
Array nacheinander durchtickere, also quasi
1
ISR
2
{
3
disp_out( buffer[counter++] );
4
}
oder ob ich wirklich die Sachen nur ans Display schicke, wenn ich es
auch gerade verändern will. Da dann also
1
jump_to( 1, 5 );
2
disp_string_out( "TESTSTRING" );
In der ersten Variante würde ich zwei 80-Zeichen-Buffer nehmen. In den
einen schreibe ich meine Daten, der andere dient der ISR als
Datenquelle. Nach einem abgeschlossenen Buffer-Transfer dann den neuen
Bufferinhalt rüberkopieren. Hier könnte ich ohne Busy-Flag arbeiten,
indem ich ein Intervall nehme, welches länger als die Verarbeitungszeit
des Displays ist.
Bei der zweiten Variante würde ich halt nach jedem Zeichen aufs
Busy-Flag warten, wodurch ich durchs
1
while( LCD_BUSY );
Wartezyklen im Code habe.
Mir ist klar, dass die Wartezeiten hier nicht sehr groß sind, jedoch
geht es mir mehr um die "schönere" Variante. Was meint ihr, bzw. was
bevorzugt ihr und warum?
Gruß, Denis
@ Denis (Gast)
>Ich arbeite mit dem Busy-Flag, also ohne Delays. Obwohl das Busy-Flag>natürlich auch einem Delay gleichkommt, da ich ja warten muss, bis das>Display fertig ist mit dem letzten Befehl.
Eben, das spart kaum was.
>Jetzt ist die Frage, ob ich mit einen Zeichenpuffer mit 80 Zeichen>anlege und per Timer-Interrupt immer im bestimmten Abstand das ganze>Array nacheinander durchtickere, also quasi
Kann man machen. Hat den Vorteil, dass das Programm sehr schnell Daten
in den "Framebuffer" schreiben kann.
>oder ob ich wirklich die Sachen nur ans Display schicke, wenn ich es>auch gerade verändern will. Da dann also>jump_to( 1, 5 );>disp_string_out( "TESTSTRING" );
Ist auch eine Möglichkeit, wenn man vorher prüfen kann, ob sich
angezeigte Werte geändert haben, nur dann überschreibt man Teile des
LCDs.
>In der ersten Variante würde ich zwei 80-Zeichen-Buffer nehmen. In den>einen schreibe ich meine Daten, der andere dient der ISR als>Datenquelle. Nach einem abgeschlossenen Buffer-Transfer dann den neuen>Bufferinhalt rüberkopieren. Hier könnte ich ohne Busy-Flag arbeiten,>indem ich ein Intervall nehme, welches länger als die Verarbeitungszeit>des Displays ist.
Genau.
>Mir ist klar, dass die Wartezeiten hier nicht sehr groß sind, jedoch>geht es mir mehr um die "schönere" Variante. Was meint ihr, bzw. was>bevorzugt ihr und warum?
Ist eine Frage der Anwendung. In meinem aktuellen Prokelt habe ich ein
kleines Menu. Die statemachine dazu wird alle 10ms aufgerufen und
durchlaufen. Am Ende werden alle Anzeigeparameter auf eine Veränderung
geprüft. Ist die positiv, gibt es einen Update des gesamten LCD. Für
diese Sache ausreichend.
Wenn die Menus komplexer werden, könnte es sein, dass viele Stellen im
Programm auf das LCD schreiben. Dann ist ggf. die 1. Variante besser. So
oder so muss man aber sinnvollerweise dafür sorgen, dass das LCD nicht
zu oft neu beschrieben wird, weil man dann ggf. nur flimmernde Zeichen
hat die keiner ablesen kann. Ausserdem sind die klassischen LCDs nicht
sonderlich schnell, die verschwimmen bei einem Dutzend Hz
Wiederholfrequenz. Erst recht, wenn es kalt wird.
Hi,
Ich habe mein eigenes kooperatives Multitasking geschrieben, da kann ich
Busy Waits nicht brauchen. habe dann auch einen Display Manager
implementiert, der mir jede meiner 4 Zeilen verwaltet. Damit kann ich
dann z.b in die Zeile 4 Debug Infos von irgendeinem anderen interrupt
ausgeben.
es hängt also davon ab, was du brauchst bzw in Zukunft brauchen wirst.
LG, Mario
So sehr lang sind die Wartezeiten ja auch nicht.
also es kommt drauf an, was der Rest deines Programmes tun soll. Hast du
genug Zeit, dann frag das Busy-Flag überhaupt nicht ab, sondern warte
einfach pauschal ein paar Mikrosekunden. Hast du extrem wenig oder gar
keine Zeit, dann schaufele deinen Text in einen String und versuche in
der Grundschleife deines Programmes, selbigen ins Display zu bekommen.
immerzu:
if (lcdnotbusy && nochwasauszugeben) GibEsAus();
machdensonstigenkram();
goto immerzu;
W.S.
Hey!
Danke für die schnellen Antworten. Wie handhabt ihr das denn mit den
Signalzeiten? Für den Enable-Puls (high-Zeit) sind im Datenblat z.B. min
1us angegeben. Ich arbeite mit 8MHz. Da ist ein Takt gerade mal 125ns.
Also 8 mal schneller. Und acht Takte dauert ein High->Low nicht. Macht
ihr da auch Delays rein?
Denis schrieb:> Danke für die schnellen Antworten. Wie handhabt ihr das denn mit den> Signalzeiten? Für den Enable-Puls (high-Zeit) sind im Datenblat z.B. min> 1us angegeben. Ich arbeite mit 8MHz. Da ist ein Takt gerade mal 125ns.> Also 8 mal schneller. Und acht Takte dauert ein High->Low nicht. Macht> ihr da auch Delays rein?
Natürlich.
Tatsächlich ist neben falscher Verkabelung das Nichteinhalten der
Mindestzeiten bei der LCD Steuerung eine der Hauptursachen hier im
Forum, warum eine LCD-Ansteuerung nicht funktioniert.
Karl Heinz Buchegger schrieb:>> Also 8 mal schneller. Und acht Takte dauert ein High->Low nicht. Macht>> ihr da auch Delays rein?>> Natürlich.> Tatsächlich ist neben falscher Verkabelung das Nichteinhalten der> Mindestzeiten bei der LCD Steuerung eine der Hauptursachen hier im> Forum, warum eine LCD-Ansteuerung nicht funktioniert.
Aber es ist nicht so schlimm, wie sich das jetzt anhört. Denn
tatsächlich ist eine Ausgabe auf ein LCD etwas, dass aus Sicht des µC
nur alle 'heiligen Zeiten' mal passiert. Mehr als 3 oder 4 Updates pro
Sekunde sind aus ergonomischer Sicht auf einem LCD nicht sinnvoll, weil
sowieso kein Mensch eine Zahl ablesen kann, die sich schneller als das
verändert.
Arbeitest du das ganze Jahr über durch und machst Weihnachten mal eine
halbe Stunde Pause, dann wirkt sich das auf die Jahresarbeitszeit so gut
wie gar nicht aus.
Das ist klar. Mir geht es ja auch nicht darum, dass die Updaterate
möglichst hoch ist. Ich will nur nicht unbedingt die halbe Zeit der
Displayansteuerung mit warten verbringen. Auch wenn es zeitlich
sicherlich kein großes Ding ist.
Wie gesagt, mir geht es eher um die eleganteste Lösung. Deshalb wollte
ich mal fragen, wie ihr das löst.
Denis schrieb:> Das ist klar. Mir geht es ja auch nicht darum, dass die Updaterate> möglichst hoch ist. Ich will nur nicht unbedingt die halbe Zeit der> Displayansteuerung mit warten verbringen.
Genau darum geht es.
Es ist eben nicht die 'halbe Zeit', sondern 'ferner liefen'
> Wie gesagt, mir geht es eher um die eleganteste Lösung.
Das ist immer so eine Sache. Eleganz liegt zu einem nicht unerheblichen
Teil im Auge des Betrachters :-)
Persönlich hab ich bis jetzt die Framebufferlösung noch nie benutzt (und
auch noch nie vermisst). Ich weiß aber, dass es sie gibt (und
klarerweise auch wie man sie implementiert). Für mich hat sich daraus
noch nie ein erkennbarer Vorteil ergeben und mit den paar Verzögerungen
konnte ich bisher leben, sprich - sie waren unmerkbar gering.
>Wie gesagt, mir geht es eher um die eleganteste Lösung. Deshalb wollte>ich mal fragen, wie ihr das löst.
Ich hab mal ne State Maschine für eine 4 Bit Ansteuerung
geschrieben die ohne Delays auskommt. Das Programm
selbst war mein Delay. Benutzt hab ich das aber nie.
Bei den meisten Programmen tuts halt ein kleines Delay.
>Persönlich hab ich bis jetzt die Framebufferlösung noch nie benutzt (und>auch noch nie vermisst). Ich weiß aber, dass es sie gibt>Ich hab mal ne State Maschine für eine 4 Bit Ansteuerung>geschrieben die ohne Delays auskommt.
Da wurde logischerweise auch ein Framebuffer benutzt.
Irgendwie cool das ganze, aber den Code würde ich keinem
Noob geben;) Da kommen zu viele Missverständnisse auf.
Die meisten kommen ja nicht mal mit der Standard Lösung klar.
Alles klar Leute!
Ich danke euch für heute. Ich werde jtzt mal die einzelnen Varianten
testen und gucken, was mit am Ende besser gefällt. Ich werde berichten.
Bei mir wird ein Buffer benutzt.
Ein Timer-Interrupt mit 1 ms schickt jeweils zwei halbe Bytes (4-bit
Schnittstelle) ohne Warteschleife zwischen den Nibbles zum Display. Die
Anfangsadressen der Zeilen werden dabei gleich mit korrigiert.
Aus Sicht des Hauptprogramms ist das LCD damit ein Bereich im RAM.
Wenn man aus verschiedenen Programmteilen auf das LCD schreibt, ist die
Interruptmethode besser.
Man spart sich das ewige Positionieren des Kursors und muß nicht drauf
achten, zu oft auszugeben.
Einen 2.Puffer braucht man nicht.
Hier ein Beispiel:
Beitrag "Formatierte Zahlenausgabe in C"
Habe ich denn mit einem Puffer nicht unter Umständen das Problem, dass
ich gerade was ändere, während es ausgegeben wird. Dann könnte ich halb
neuen, halb alten Text in der Zeile haben.
Denis schrieb:> Habe ich denn mit einem Puffer nicht unter Umständen das Problem, dass> ich gerade was ändere, während es ausgegeben wird. Dann könnte ich halb> neuen, halb alten Text in der Zeile haben.
Das war bei den alten PCs schon so. Wenn dort direkt in den
Bildschirmspeicher geschrieben wurde, dann war für ein paar ms noch der
halbe alte und schon der halbe neue Inhalt zu sehen. Keine Problem: da
kommt das Auge nicht mit...
Wenn auf einem 20x4 Display jede ms 1 Zeichen geschrieben wird (die
langsamen Befehle clear display und return home braucht man nicht,
man dreht ja nur an der DDRAM Adresse), dann kommt man mit 80 ms auf
12Hz Updaterate, und das reicht auf jeden Fall aus. Und weil die Zeichen
nur überschrieben werden, gibt es das bekannte Flackern nicht. Das tritt
ja nur auf, wenn vor dem Schreiben erst mal das Display gelöscht wird.
Ich nehme einen Bildschirmspeicher im Controller, kopiere den laufend
aufs Display und kann auf diese Art sogar eine Art Paging machen: im
Speicher mehrere Bildschirmseiten beschreiben und nur eine davon
anzeigen. Da klappt sogar Scrollen ganz einfach: ich lege 40
Bildschirmzeilen an und gebe 4 davon aufs Display aus...
Denis schrieb:> Mir ist klar, dass die Wartezeiten hier nicht sehr groß sind, jedoch> geht es mir mehr um die "schönere" Variante. Was meint ihr, bzw. was> bevorzugt ihr und warum?
Ich benutze einen Kommandopuffer (also keinen Framepuffer) und einen
Timerinterrupt mit einer Periode des 1..4fachen der kürzesten "langen"
Wartezeit des LCD. Alle längeren Wartezeiten werden als Vielfache der
Basisperiode ausgedrückt (die richtigen Faktoren werden zur Entwurfszeit
berechnet).
Der Kommandopuffer ist als Ringpuffer ausgeführt und nichtblockierend
(von einer nur wenige Takte langen Synchronisationssequenz abgesehen).
Vorteile:
-Schreiben ist zu jeder Zeit möglich, also auch direkt aus ISRs.
-Jede geschriebene Kommandosequenz ist "atomar", kommt also entweder
ganz
und ungestört beim Display an oder garnicht.
-Timerinterrupt kann fast immer als "Zweitverwertung" implementiert
werden.
Nachteil:
-Kommandopuffer ist zwar konfigurierbar, aber auf jeden Fall endlich.
D.h.:
es kann die Situation eintreten, daß eine Kommandosequenz nicht
abgesetzt
werden kann.
Denis schrieb:> Ich will nur nicht unbedingt die halbe Zeit der> Displayansteuerung mit warten verbringen. Auch wenn es zeitlich> sicherlich kein großes Ding ist.
Mußt du doch auch nicht. Wenn der µC auch noch andere Dinge zu tun hat,
kannst du die immer zwischen schieben. Wenn du die Ausgabe-Task in so
großen Zeitabständen triggerst, dass der Display-Controller garantiert
fertig ist, braucht da niemand zu warten. Und wegen 1µs Enable-Puls,
lohnt es nicht, irgendwelchen Zirkus zu veranstalten, nur um da um die
Wartezeit.
Die "halbe Zeit" mußt du also überhaupt nicht waren. Wenn du die
Befehlsdauer, gemessen in deinem Task-Takt halbwegs gut abschätzen
kannst. Ansonsten lohnt es, wie schon gesagt, an der Stelle nicht
beliebig rumzuoptimieren. Insgesamt fällt die Prozessorlast nicht auf
und solange du programmtechnisch dafür sorgst, dass andere Dinge nicht
im Ablauf gestört werden und die Ausgabe so selten erfolgt, dass der
Betrachter nicht durch wildes Flackern genervt wird, ist alles gut.
Thomas_H schrieb:> Bei mir wird ein Buffer benutzt.>> Ein Timer-Interrupt mit 1 ms schickt jeweils zwei halbe Bytes (4-bit> Schnittstelle) ohne Warteschleife zwischen den Nibbles zum Display. Die> Anfangsadressen der Zeilen werden dabei gleich mit korrigiert.>> Aus Sicht des Hauptprogramms ist das LCD damit ein Bereich im RAM.
genau so mache ich das auch. Bin damit immer gut gefahren.
Ist aber nicht immer die Lösung der Wahl. Kommt immer auf den Zweck an
und ob man genug Speicher dafür hat.
Und wenn man ein etws moderneres LCD wie z.B die DOGM nimmt, steuert man
die mit SPI an. Dort gibt es kein Busy Flag mehr! Dann feuert man
einfach ein einzelnes Byte raus (bis zu 4 Mbit/s) und fertig. Macht
bischen mehr als 2us/Bytes, also praktisch nix.
c-hater schrieb:> D.h.:> es kann die Situation eintreten, daß eine Kommandosequenz nicht> abgesetzt> werden kann.
Und was ist dann der Vorteil daran?
Mit dem Framepuffer kann das nicht passieren.
Jede Ausgabetask schreibt direkt in den SRAM an die Stelle, wo der Text
erscheinen soll.
Also wenn man schon auf BUSY warten will, dann doch gefälligst vor der
Ausgabe eines Zeichens und nicht hinterher. Es sei denn, man wollte
unbedingt sicherstellen, daß immer nur einer von beiden gleichzeitig
arbeitet: das Display oder der Prozessor.
Ich tendiere dazu, ein LCD-Display in Zeitrastern zu schreiben, z.B.
alle 200ms, viel schneller kann das Auge sowieso nicht betrachten.
Bei meiner DCF77-Uhr gibt es ein vollständiges Display-Update jede
Sekunde, das reicht dort.
Ich gewöhnte mit auch an, stets das gesamte Display zu refreshen, der
Inhalt steht immer in einem Spiegelrambereich, und der wird einmal
vollständig ausgelöst.
In den Anfangsbastelzeiten schrieb ich ja noch beliebig nicht
zeitsynchron einzelne Zeichen ins Display. Das gibt aber häßliche
Flimmereffekte bei etwas seitlicher Betrachtung, und dazu fand ich
später in Literatur auch den Hinweis, daß man den Inhalt genau deswegen
komplett updatet.
Mit dem Busy-Flag lief ich auch schon mal Ausfällen auf. Ein Stecker vom
µC zum Display hatte einen Wackler, dann bleibt alles µC und Display
stehen. Dort wählt man evtl. doch besser die Wartezeitmethode, oder
einen Timeout-Timer, falls das Busy-Flag nicht im erwarteten Zeitraum
kommt.
Aber im Grunde, zur Threadfrage, macht man es so, wie man es braucht. Es
gibt wohl keine Universallösung.
Meine Displays flackern unangenehm, wenn man sie ständig neu beschreibt.
Auch wenn ich immer wieder die gleichen Zeichen übertrage.
Das würde ich also besser lassen. Übertrage nur dann, wenn sich die
Anzeige ändert.
Stefan Nie schrieb:> Meine Displays flackern unangenehm, wenn man sie ständig neu beschreibt.> Auch wenn ich immer wieder die gleichen Zeichen übertrage.
Das schrieb ich ja bereits.
Peter Dannegger schrieb:> Und was ist dann der Vorteil daran?
Determinismus:
Der Caller erfährt, daß seine Ausgabe den Benutzer nicht erreichen wird
und er erfährt auch, warum nicht. Er hat also z.B. die Option, wichtige
Nachrichten selbst zu "puffern", um sie zu einem späteren Zeitpunkt
loszuwerden. Unwichtige hingegen kann er einfach verwerfen.
Effizienz:
Wenn es hingegen nichts (neues) auszugeben gibt, sinkt der
Rechenzeitverbrauch der Ausgabe auf einen unerheblichen Wert. Die Frage,
ob die Queue leer ist, kostet nur zwölf Takte in der Timer-ISR.
Universalität:
Das Schema handelt auch problemlos die Initialisierung ab oder das
Setzen von Custom-Zeichen, diese Sachen wahlweise sogar parallel für
mehrere Controller gleichzeitig. Bei zwei 4x27-Displays von Pollin steht
man also nicht eine gute halbe Sekunde im Dunkeln, weil die vier
Controller der zwei Displays initialisiert werden müssen. Das dauert
vielmehr genauso lange, als wäre es nur ein Controller. Und natürlich
kann der Atmel in der ganzen Zeit auch schon andere Sachen tun, und
dabei sogar Ausgaben an die noch garnicht fertig initialisierten
Displays tätigen. Solange halt der Kommandopuffer reicht.
Und dessen Größe ist, wie schon gesagt, konfigurierbar. Im schlimmsten
Fall, wenn man nicht in der Lage ist, die Mitteilungswut seiner
Programme zu zähmen, muß man halt einfach einen größeren Controller
nehmen. Das wäre wohl die Lösung der C-Programmierer...
c-hater schrieb:> Er hat also z.B. die Option, wichtige> Nachrichten selbst zu "puffern", um sie zu einem späteren Zeitpunkt> loszuwerden. Unwichtige hingegen kann er einfach verwerfen.
Ach Du meine Güte.
Das wäre mir viel zu kompliziert, bei jeder Ausgabe extra noch den
Returnwert abfragen und behandeln zu müssen.
Ich mag nicht gerne den Code unnütz aufblähen und das Programm
unübersichtlicher machen.
Im Framebuffer verwerfen sich veraltete Ausgaben automatisch (werden
überschrieben), ganz ohne jede zusätzliche Codezeile.
c-hater schrieb:> Wenn es hingegen nichts (neues) auszugeben gibt, sinkt der> Rechenzeitverbrauch der Ausgabe auf einen unerheblichen Wert.
Ginge mit Framebuffer auch.
Aber da die CPU-Last eh <1% ist, lohnt sich der zusätzliche Aufwand
einfach nicht.
Jede Ausgabe müßte dann eine Variable auf die Puffergröße setzen und der
Interrupt müßte sie testen und auf 0 runter zählen.
c-hater schrieb:> Bei zwei 4x27-Displays von Pollin steht> man also nicht eine gute halbe Sekunde im Dunkeln, weil die vier> Controller der zwei Displays initialisiert werden müssen.
Das LCD-Init mache ich bequemer Weise gleich im Init, ohne Interrupts
mit Delay.
Ich hab dann zwar den Code für die Byteausgabe doppelt, spare aber durch
die viel einfachere Verwaltung umso mehr Code ein.
Habe ich mehrere LCD-Controller, lege ich alle E-Signale auf einen Port
und speichere in einer Variable die Maske dafür. Dann kann man bis zu 8
Controller simultan initialisieren, spart ja Zeit und Flash.
Hallo Leute!
Ich krame mal diese etwas ältere, aber dennoch sehr interessante
Geschichte wieder aus - ich stehe gerade vor der selben Frage...und die
Interruptlösung finde ich ganz chick, zumindest erstmal gedanklich.
Aber eine Frage habe ich dazu noch (bevor ich losprogrammiere und am
Ende alles wieder lösche, weil ich das gewünschte nicht erreiche):
Wenn ich das Display auch für Eingaben nutzen will und dann zum Beispiel
in einer Zeile stehen habe "SET VOLTAGE: 00.0 V" und möchte jetzt per
Encoder oder was auch immer den Wert 00.0 ändern, dann würde es sich
anbieten, wenn ich den Cursor, welcher mir ja direkt zu jedem Zeichen
migeliefert wird, benutze. Also würde dann zum Beispiel bei einem
Tastendruck der Cursor unter der ersten 0 aufleuchten, damit ich weiß,
dass ich eben grad an dieser Stelle bin.
ABER: Wenn ich einen Framebuffer kontinuierlich ausgebe, dann wird beim
HD44780 doch auch nach jedem Zeichen die DDRAM-Adresse inkrementiert und
damit rutscht doch auch der Cursor immer eins weiter, oder täusche ich
mich? Wie würde ich in dem Fall einen statischen Cursor unter der ersten
0 bekommen? Jedesmal vor der entsprechenden Stelle ein- und ausschalten
oder wie?
Hoffe, es ist klar, was ich meine.
Gruß, Dietmar
Hi
>ABER: Wenn ich einen Framebuffer kontinuierlich ausgebe, dann wird beim>HD44780 doch auch nach jedem Zeichen die DDRAM-Adresse inkrementiert und>damit rutscht doch auch der Cursor immer eins weiter, oder täusche ich>mich? Wie würde ich in dem Fall einen statischen Cursor unter der ersten>0 bekommen? Jedesmal vor der entsprechenden Stelle ein- und ausschalten>oder wie?
Cursor einfach nicht einschalten.
MfG Spess
Dietmar schrieb:> Jedesmal vor der entsprechenden Stelle ein- und ausschalten> oder wie?
Ja - oder danach, damit man den Cursor möglichst lange sieht, setze ich
ihn beim Verlassen des LCD Refresh.
Matthias Sch. schrieb:> Ja - oder danach
Ja sorry, dumm formuliert, natürlich vor der entsprechenden Stelle ein,
und danach wieder ausschalten. Nur das würde bei einem Timer-Interrupt
von sagen wir mal zwei Millisekunden nur eine sehr kurze Zeit sein, in
der eben diese eine Stelle mit Cursor zu sehen ist.
Gibt es da ne elgantere Lösung, oder ist das Verfahren mit dem
Framebuffer dafür schlichtweg ungeeignet?
>Gibt es da ne elgantere Lösung, oder ist das Verfahren mit dem>Framebuffer dafür schlichtweg ungeeignet?
Warum sollte der ungeeignet sein? Man könnte die Zahl selbst
z.B. blinken lassen indem man sie im Framebuffer in einem
zeitlichen Wechsel löscht und wieder einträgt.
holger schrieb:> Man könnte die Zahl selbst> z.B. blinken lassen indem man sie im Framebuffer in einem> zeitlichen Wechsel löscht und wieder einträgt.
Ja klar, das ist die andere Variante. Die geht, war nur ne Frage wegen
dem Cursor, weil ich Geräte hier stehen habe, bei denen es mit dem
Cursor gemacht wird. Und bei genauerem Hinsehen habe ich gerade
entdeckt, dass man in dem Display (2x20 Zeichen) irgendwie auch einen
Durchlauf erkennen kann. Sehr schwach, aber sichtbar wenn man ganz nah
dran geht und vom richtigen Winkel drauf guckt.
@ Dietmar (Gast)
>Ja klar, das ist die andere Variante. Die geht, war nur ne Frage wegen>dem Cursor,
Geht so nicht, weil dann das Blinken "durcheinander" kommt. Im
Zweifelsfall, probier es aus, geht ja schnell.
> weil ich Geräte hier stehen habe, bei denen es mit dem>Cursor gemacht wird.
Die machen halt keinen dauerhaften Refresh sondern nur bei Änderungen.
> Und bei genauerem Hinsehen habe ich gerade>entdeckt, dass man in dem Display (2x20 Zeichen) irgendwie auch einen>Durchlauf erkennen kann. Sehr schwach, aber sichtbar wenn man ganz nah>dran geht und vom richtigen Winkel drauf guckt.
Das ist das Multiplexing vom LCD, das macht es selber. GGf. mit einer
Interferenz von der LED-Hintergrundbeleuchtung, die vielleicht mit
PWM arbeitet. Hab ich hier auch mit einem DOGM LCD. Fällt aber ur
bei bestimmten Blickwinkeln auf.
ich benutze den Framebuffer bisher ausschließlich. Das gute daran ist
für mich, das ich nicht zwischen Steuer und Nutzdaten unterscheiden
muss.Ich lege die Bytes ab und sage mit einem Flag das es Steuer oder
Nutzdaten sind. Allerdings kann das beim 8051 mit 128 Byte RAM und
4x20er Display schnell eng werden. Ist rein eine Sache des persönlichen
Geschmacks und der Anforderungen an das Timing der ges. Baugruppe.
das Blinken eines Cursors erfolgt dann logischer Weise im RAM !
20h, Wert, 20h, Wert .......... etc.pp logische Verknüpfungen
Ein Beispiel hatte ich mal in die Codesammlung gestellt.
Beitrag "Serielles LCD/Keypad Interface" .......... weiter unten
Dietmar schrieb:> Nur das würde bei einem Timer-Interrupt> von sagen wir mal zwei Millisekunden nur eine sehr kurze Zeit sein, in> der eben diese eine Stelle mit Cursor zu sehen ist.
Ich nehme mal an, dass du das Display für menschliche Benutzer und nicht
für Fliegen benutzen möchtest. Dann reicht ein Update alle 1/10 s. Wenn
du also, ggf. bei abgeschaltetem Cursor, das Gesamtdisplay
aktualisierst, dann den Cursor auf das zu "cursernde" Zeichen stellst
und anschaltest, hat er fast 100 ms Zeit zum leuchten, bei einem
Duty-Cylce von über 90%.
der Denkfehler liegt darin, das der Cursorwechsel (blinken) auch mit 1ms
geht, das das Display ja 16,32 oder mehr stellen hat, die ausgegeben
werden, bevor der Cursor sein "Gesicht" 1 Mal wechselt.
Pro Interrupt wird ja nur EIN Zeichen ausgegeben.
Stephan Henning schrieb:> Pro Interrupt wird ja nur EIN Zeichen ausgegeben.
Ja schon, aber in der nächsten Millisekunde kommt ja schon das nächste
Zeichen, welches keinen Cursor merh hat, oder was verstehe ich grad
nicht?
@ Dietmar (Gast)
>Ja schon, aber in der nächsten Millisekunde kommt ja schon das nächste>Zeichen, welches keinen Cursor merh hat, oder was verstehe ich grad>nicht?
Er setzt den Cursor nach JEDER Zeichenausgabe auf die gleiche Stelle
zurück. Aber ob das dann normal blinkt ist fraglich. Probieren.
Mhh...das geht doch aber eigentlich garnicht. Wenn ich an (nur mal
beispielhaft) Stelle 5 von den gesamten 32 Stellen den Cursor haben will
und nun einen Puffer von 32 Zeichen habe, dann lasse ich ja den gesamten
Puffer von 0 bis 31 einmal komplett ausgeben, also wandert auch der
Cursor einmal komplett durchs Display. Also nach jedem einzelnen Zeichen
geht da ja eigentlich nicht, weil selbst wenn ich ihn händisch da hin
stellen würde, dann wäre beim nächsten Zeicheninterrupt der Buchstabe an
der falschen Stelle. Oder ich müsste dann erst wieder den Cursor auf die
ursprüngliche Position bringen, damit es von da weiter geht.
Jetzt kommt mir grad mal die Frage auf, ob wir vom selben reden...mit
einem Zeichen meine ich, dass alle 1ms ein Timer-Interrupt kommt,
welcher genau einen Buchstaben aufs Display schreibt. Also in 32ms wäre
dann das ganze Display geschrieben. Oder meint ihr per Interrupt einmal
auslösen, dass alle 32 Zeichen geschrieben werden?
@ Dietmar (Gast)
>Mhh...das geht doch aber eigentlich garnicht. Wenn ich an (nur mal>beispielhaft) Stelle 5 von den gesamten 32 Stellen den Cursor haben will>und nun einen Puffer von 32 Zeichen habe, dann lasse ich ja den gesamten>Puffer von 0 bis 31 einmal komplett ausgeben,
Aber verteilt über 32 Interrupts.
>also wandert auch der>Cursor einmal komplett durchs Display.
Nein. Den kann man vor der Ausgabe abschalten.
> Also nach jedem einzelnen Zeichen> geht da ja eigentlich nicht, weil selbst wenn ich ihn händisch da hin>stellen würde, dann wäre beim nächsten Zeicheninterrupt der Buchstabe an>der falschen Stelle.
Jain, weil . . .
> Oder ich müsste dann erst wieder den Cursor auf die>ursprüngliche Position bringen, damit es von da weiter geht.
Genau! Aber ganu dort wird es echt auswändig. Denn man müsste
Cursor ausschalten
Cursor neu setzen
neues Zeichen ausgeben
Cursor rücksetzen
Cursor einschalten
Macht satte 5 Befehle a 40us, sprich 200us. Damit sind 20% des 1ms
Timerintervalls mehr oder weniger sinnlos mit Warten vertrödelt. Nicht
wirklich gut. Eine Softwareemulation ist hier deutlich effizienter.
Zumal die Hardwareversion (LCD blink den Cursor selber) wahrscheinlich
nicht funktioniert, wegen der vielen Cursorzugriffe.
>Jetzt kommt mir grad mal die Frage auf, ob wir vom selben reden...mit>einem Zeichen meine ich, dass alle 1ms ein Timer-Interrupt kommt,>welcher genau einen Buchstaben aufs Display schreibt.
Ja.
> Also in 32ms wäre>dann das ganze Display geschrieben.
Genau.
>Oder meint ihr per Interrupt einmal>auslösen, dass alle 32 Zeichen geschrieben werden?
Nein.
Falk Brunner schrieb:> Jain, weil . . .>>> Oder ich müsste dann erst wieder den Cursor auf die>>ursprüngliche Position bringen, damit es von da weiter geht.>> Genau! Aber ganu dort wird es echt auswändig. Denn man müsste>> Cursor ausschalten> Cursor neu setzen> neues Zeichen ausgeben> Cursor rücksetzen> Cursor einschalten
neee neee.
Ich toggle die RAM Zelle, so das es entweder der Zahlenwert ist oder
eben
20h für ein Leerzeichen oder einen Block FFh. Ein Cursor wäre genauso
gut möglich. Das toggeln mache ich dann aber im Sekundentakt.
@ Stephan (Gast)
>>> Oder ich müsste dann erst wieder den Cursor auf die>>>ursprüngliche Position bringen, damit es von da weiter geht.>>> Genau! Aber ganu dort wird es echt auswändig. Denn man müsste>> Cursor ausschalten>> Cursor neu setzen>> neues Zeichen ausgeben>> Cursor rücksetzen>> Cursor einschalten
Ich meinte hiermit, wenn man die Cursorfunktion des LCDs nutzen will.
>neee neee.>Ich toggle die RAM Zelle, so das es entweder der Zahlenwert ist oder>eben>20h für ein Leerzeichen oder einen Block FFh. Ein Cursor wäre genauso>gut möglich. Das toggeln mache ich dann aber im Sekundentakt.
Du meinst eine Cursorfunktion in der uC Software. Das ist was anderes
und hier deutlich sinnvoller.
Vielen Dank!
Ich werde auf den LCD-Cursor verzichten! Ich werde ebenfalls den
Software-Cursor verwenden, entweder blank oder voll gefüllt - mal
schauen, was besser aussieht.
Jetzt teste ich das mal, dann melde ich mich nochmal.
Falk Brunner schrieb:> @ Stephan (Gast)>> Ich meinte hiermit, wenn man die Cursorfunktion des LCDs nutzen will.>>>neee neee.>>Ich toggle die RAM Zelle, so das es entweder der Zahlenwert ist oder>>eben>>20h für ein Leerzeichen oder einen Block FFh. Ein Cursor wäre genauso>>gut möglich. Das toggeln mache ich dann aber im Sekundentakt.>> Du meinst eine Cursorfunktion in der uC Software. Das ist was anderes> und hier deutlich sinnvoller.
Jepp, alles klar.
Auf die Idee den vom LCD zu nutzen würde ich gar nicht kommen, um den
muss ich mich ja kümmern. Da bin ich viel zu faul zu. :-))