Guten abend Freunde der Elektrotechnik!
Wie Ich bemerkt habe, muss Ich ein mega großes Brett vor meinem kleinen
Kopf haben.
Habe hier neben mir ein schönes Grafikdisplay zu liegen. Dort möchte Ich
gerne eine Laufschrift von rechts nach links darstellen.
Der ganze String soll von rechts rein gerollt kommen und links wieder
raus rollen.
Das ist sicherlich mit 2 - 3 schleifen gegessen. Mir fehlt jedoch der
Ansatz und der Ablauf.
Kann mir jemand auf die Sprünge helfen oder gar einen Pseudo Kode
posten?
Es macht allerdings einen beachtlichen Unterschied, ob dein Text
pixelweise oder zeichenweise scrollen soll.
Letzteres schafft man mit einfachen Text- bzw. Array/Listenfunktionen.
Soll er pixelweise scrollen musst du quasi eine Ebene tiefer in die
Rendering-Engine ...
Hallo
Hans Dieter F. schrieb:> Habe hier neben mir ein schönes Grafikdisplay zu liegen.
welches?
Hans Dieter F. schrieb:> Der ganze String soll von rechts rein gerollt kommen und links wieder> raus rollen.
Zeichenweise oder Pixelweise?
gruß Dominik
Frank E. schrieb:> Es macht allerdings einen beachtlichen Unterschied, ob dein Text> pixelweise oder zeichenweise scrollen soll.
Und ob der Font proportional oder monospaced ist...
Frank E. schrieb:> Soll er pixelweise scrollen musst du quasi eine Ebene tiefer in die> Rendering-Engine ...
Nicht unbedingt.
Ich habe das mal so gemacht (schwer zu erklären):
- N Zeichen des Textes zunächst immer um V Pixel weiter nach links
zeichnen
- sobald der Versatz V eine Zeichenbreite beträgt, V=0 und Textzeiger um
1 erhöhen, also beim nächsten Zeichen weitermachen, aber wieder N
Zeichen ausgeben
- an einer fixen Position links und rechts vom Scrollbereich nach jedem
Neuzeichnen einen Block in der Hintergrundfarbe zeichnen. Dieser
verdeckt den Teil des ersten und letzten Zeichens, der "wegscrollen"
soll, und verhindert damit ein "Jittern".
Ein paar Randbedingungen beachten, dann geht das.
Ist für den Controller eine Menge Arbeit, aber was soll's.
Ich hätte - bei ausreichend RAM - mir das Bitmap von der Laufschrift am
Stück in den Speicher gepackt und dann jeweils die relevanten Teile per
CopyRect aufs Display kopiert.
Eine CopyRect() Funktion hat man meistens schon irgendwo rumfliegen für
das Grafikdisplay.
Braucht zwar RAM, ist aber einfacher als sich zu überlegen wo welcher
Buchstabe anfängt und aufhören muss.
Du brauchst doch als allererstes eine Funktion, um einen Text an einer
bestimmten Stelle des Bildschirms anzuzeigen.
Gibt's die auf Deinem System schon, hast Du sie mal ausprobiert und
funktioniert das?
Oder hast Du wirklich nur das Display herumliegen und sonst noch gar
nix?
Daniel schrieb:> Du brauchst doch als allererstes eine Funktion, um einen Text an> einer> bestimmten Stelle des Bildschirms anzuzeigen.> Gibt's die auf Deinem System schon, hast Du sie mal ausprobiert und> funktioniert das?> Oder hast Du wirklich nur das Display herumliegen und sonst noch gar> nix?
Guten Morgen!
Ich kann an bestimmte Positionen schreiben und verschiedene Schriftarten
habe Ich auch schon. Also das ist kein Problem.
Es geht wirklich einfach nur um das scrollen eines Textes.
Also angenommen, diese Funktion heißt lcd_printn(string,
anzahl_zeichen), und sie gibt anzahl_zeichen Zeichen des Strings string
aus.
Weiter angenommen, auf das Display passen 10 Zeichen und du willst
"Guten Morgen" durchscrollen.
Weiter angenommen, du programmierst in C oder verstehst ein Beispiel in
C.
Dann ist es erstmal am einfachsten, Du ergänzt vorn und hinten 10
Leerzeichen für das Rein- und Rauslaufen:
char text[] = " Guten Morgen ";
Na und dann musst du doch einfach nur
- im ersten Schritt beim ersten Zeichen deines Textes beginnend 10
Zeichen ausgeben
- im 2. Schritt beim 2. Zeichen beginnend 10 Zeichen ausgeben
- usw.
for(uint8_t i=0; i<strlen(text-10); i++) {
lcd_printn(&text[i], 10);
/* hier musst du entweder warten oder das Ganze so aufbauen, dass es
zyklisch aufgerufen wird */
}
Peter W. schrieb:> Da würde ich aber wertvollen RAM verschwenden. An sowas habe ich auch> schon gedacht.
Der String muss ja nicht im RAM liegen
>> Es muss doch aber noch andere Möglichkeiten geben..
Du kannst die vorderen und hinteren Leerzeichen auch mit Code erzeugen.
Ob der Speichersparender ist, muss man ausprobieren.
Fang doch erstmal an.
Dr. f. Scrollologie schrieb:>> Genau das ist Mein Problem. Wo?>> Links. In unserem Schriftsystem immer Links, unabhängig von der> Scrollrichtung. (Arabisch rechts)
So wirklich verstanden hast du es wohl nicht.
Hans Dieter F. schrieb:> Also es sollte wirklich Zeichenweise geschoben werden.
Zeichenweise ist suboptimal. Das springt dann zu sehr und ist absolut
unleserlich.
> Pixelweise bzw. Byteweise ist nicht notwendig.
Doch. Du hast 2 Möglichkeiten:
1. Pixel-Matrix des Strings im RAM komplett aufbauen. Braucht mehr RAM,
ist aber etwas einfacher. Rechenzeit ist gering, da die Erstellung
der Matrix nur einmal geschieht.
2. Nur den Ausschnitt, der dargestellt werden soll, berechnen. Braucht
weniger RAM und ist etwas anspruchsvoller. Verbraucht auch mehr
Rechenzeit, da hier für jeden Frame eine Neuberechnung notwendig
wird.
Ich empfehle Dir 2.
Umgesetzt ist das zum Beispiel im Projekt WordClock mit WS2812.
Denkanstöße findest Du im Source, wenn Du in display.c
https://www.mikrocontroller.net/svnbrowser/wordclock24h/src/display/display.c?revision=105&view=markup
nach der Funktion display_set_ticker() suchst.
EDIT:
Die für Dich relevanten Funktionen neben display_set_ticker() sind:
display_show_ticker_char ()
display_ticker_with_offset ()
display_ticker ()
Den Rest in display.c kannst Du getrost ignorieren, weils für Deine
Aufgabe nicht relevant ist.
Frank M. schrieb:> display_set_ticker()Frank M. schrieb:> 2. Nur den Ausschnitt, der dargestellt werden soll, berechnen. Braucht> weniger RAM und ist etwas anspruchsvoller. Verbraucht auch mehr> Rechenzeit, da hier für jeden Frame eine Neuberechnung notwendig> wird.>> Ich empfehle Dir 2.
Ich soll quasie für jedes einzelne Zeichen die Pixel in ein Array
kopieren (hintereinander) ?
Ich habe mir dazu mal eine Funktion geschrieben (hier pseudo):
1
void LcdSetText(int16_t x, int16_t y, const char[] text, ...);
Diese Funktion akzeptiert auch negative Positionen. Die Funktion setzt
anhand des Textes und des Bitmap-Arrays den Text dann in einzelne
1
LcdSetPixel(int16_t x, int16_t y);
und
1
LcdClearPixel(int16_t x, int16_t y);
Funktionsaufrufe um. Diese akzeptieren auch negative Positionen, setzen
es aber nur um, wenn die Position innerhalb des Displaybereichs liegt.
Dadurch kann man sehr flexible Bilder, Texte etc. in den sichtbaren
Bildschirmbereich rein und rausscrollen...
Peter W. schrieb:> ch soll quasie für jedes einzelne Zeichen die Pixel in ein Array> kopieren (hintereinander) ?
Ich würde sie direkt ins Display (durch Pixel setzen/zurücksetzen)
kopieren - an die richtige Stelle. Dann kannst Du auf das Array
verzichten.
Wo Du in display_show_ticker_char()
auf.
Im WordClock-Source wird ein Array für das Display verwendet, weil hier
verschiedene States für Überblendungen und andere Animationen verwendet
werden. Das kannst Du aber getrost ignorieren.
Fabian H. schrieb:> Ich habe mir dazu mal eine Funktion geschrieben (hier pseudo):void> LcdSetText(int16_t x, int16_t y, const char[] text, ...);
Pixel kann ich auch schon gezielt setzen..
Hört sich interessant an. Magst du deine Funktion mal vorstellen?
Frank M. schrieb:> Ich würde sie direkt ins Display (durch Pixel setzen/zurücksetzen)> kopieren - an die richtige Stelle. Dann kannst Du auf das Array> verzichten.
Okay. Diese müssen aber auch zyklisch aufgerufen werden, wo machst du
das?
char A[] = {0x04,0x32,0x21,0x43,0x43};
glcdSetPixel(x,y);
Nun kann Ich ja mit "glcdSetPixel()" einen beliebigen Pixel setzen.
Die Anzahl von Pixel vom Buchstaben "A" müssten 5Bytes(8Bits) * 8 = 320
Pixel sein.
Wie setze ich jetzt von jedem Byte von "A" gezielt die Pixel, wenn ich
bei der "glcdSetPixel()"
nur die Koordinaten eingeben kann?
Peter W. schrieb:> Okay. Diese müssen aber auch zyklisch aufgerufen werden, wo machst du> das?
Hast Du Dir die Funktion display_set_ticker() angeschaut? Da steht doch
drin:
Das ist der simple Fall, dass auf die Ausgabe gewartet werden soll. Hier
gehts dann mit einem simplen Delay. Der andere Fall, dass der Ticker im
Hintergrund ausgeführt wird (ohne Warten) lassen wir mal weg. Das würde
zu weit führen.
Frank M. schrieb:> Hast Du Dir die Funktion display_set_ticker() angeschaut? Da steht doch> drin: if (do_wait)> {> while (*ticker_ptr)> {> display_ticker ();> delay_msec ((display.ticker_deceleration * 1000) / 64);> }> }
Dein Kode ist ziemlich komplex. Muss Ich mir mal in Ruhe anschauen. Wie
sieht es denn mit meiner anderen Frage aus bzgl. "glcdPixelSet"
Peter W. schrieb:> char A[] = {0x04,0x32,0x21,0x43,0x43};> glcdSetPixel(x,y);> Nun kann Ich ja mit "glcdSetPixel()" einen beliebigen Pixel setzen.> Die Anzahl von Pixel vom Buchstaben "A" müssten 5Bytes(8Bits) * 8 = 320> Pixel sein.> Wie setze ich jetzt von jedem Byte von "A" gezielt die Pixel, wenn ich> bei der "glcdSetPixel()"> nur die Koordinaten eingeben kann?
Ich verstehe Dich überhaupt nicht mehr. Du willst eine Laufschrift
anzeigen, weisst aber noch nichtmals, wie Du überhaupt einen einzigen
Buchstaben aufs Display bringst?
Sorry, das Pferd von hinten aufzäumen bringt nichts. Du hättest den
Thread besser "Buchstabe auf Display: Denkanstoß" nennen sollen. Denn
man fängt vorne und nicht hinten an, wenn man eine Aufgabe lösen will.
Und wie ich aus Deinem obigen Beitrag entnehme, willst Du jetzt nicht
nur einen "Denkanstoß", sondern jetzt auch den kompletten Source, wie Du
einen Buchstaben auf Dein Display bringst.
Unter "Denkanstoß" verstehe ich etwas anderes.
Die Funktion display_show_ticker_char() macht doch genau das. Ich rate
Dir, jetzt erstmal zu versuchen, die vier oben genannten Funktionen zu
verstehen, bevor Du uns hier weiter mit Fragen bombardierst.
Frank M. schrieb:> Peter W. schrieb:>> char A[] = {0x04,0x32,0x21,0x43,0x43};>> glcdSetPixel(x,y);>> Nun kann Ich ja mit "glcdSetPixel()" einen beliebigen Pixel setzen.>> Die Anzahl von Pixel vom Buchstaben "A" müssten 5Bytes(8Bits) * 8 = 320>> Pixel sein.>> Wie setze ich jetzt von jedem Byte von "A" gezielt die Pixel, wenn ich>> bei der "glcdSetPixel()">> nur die Koordinaten eingeben kann?>> Ich verstehe Dich überhaupt nicht mehr. Du willst eine Laufschrift> anzeigen, weisst aber noch nichtmals, wie Du überhaupt einen einzigen> Buchstaben aufs Display bringst?>
Strings kann ich Anzeigen lassen das ist alles kein Problem. Ich nutze
für das schreiben von Zeichen nur nicht die Funktion "glcdSetPixel"
sondern schreibe direkt immer 8 Bit. Für "glcdSetPixel" müsste Ich die
Funktion zu oft aufrufen um ein Zeichen da zu stellen. Wir missverstehen
uns!
Peter W. schrieb:> Dein Kode ist ziemlich komplex.
Deine Aufgabenstellung ist auch komplex.
> Muss Ich mir mal in Ruhe anschauen.
Ja. Machs in Ruhe. Sammle Deine Fragen und versuche zunächst, sie Dir am
Ende selbst zu beantworten. Gelingt Dir das, hast Du den Source auch
verstanden. Die vier Ticker-Funktionen bauen aufeinander auf.
> Wie> sieht es denn mit meiner anderen Frage aus bzgl. "glcdPixelSet"
Wie gesagt: schau Dir display_show_ticker_char() an. Das bildet einen
einzelnen Buchstaben an beliebiger Stelle aufs Display ab. Dass die
Funktion so komplex aussieht, liegt daran, dass sie auch Teile eines
Buchstabens ausgeben kann. Das ist nämlich notwendig für den ersten und
letzten sichtbaren Buchstaben Deines Ticker-Textes. Der erste rutscht
links pixelweise raus, während der letzte rechts reinrutscht.
Mehrere Dutzend Leute hier haben sicher schon Schrift gescrollt. Auf
ebenso viele Arten, meist kann das sogar der Grafikchip.
Wenn Du hier Deinen Pseudo-Code postest, wie Du einen String anzeigst,
so haben wir erstmals ein Gefühl, wo Du stehst.
Wenn Du zudem folgende Fragen beantwortest, kann man Dir sogar konkret
helfen:
- reicht vorerst ein (langsames, ruckartiges) Scrollen um jeweils ein
Zeichen. Z.B. falls Du keinen Pixelzugriff hast?
- wird noch mehr auf dem Display angezeigt (drüber, drunter oder
daneben)
- nutzt Du ein Framework (GUI), was vielleicht sogar im Internet
beschrieb en ist?
- Hast Du Zugang zum Grafikchip (entweder weil Du den Treiber selbst
geschrieben hast, oder weil Du dran kommen könntest)
- Nutzt Du eigene Fonts oder etwa Chipinternes?
Achim S. schrieb:> - Hast Du Zugang zum Grafikchip (entweder weil Du den Treiber selbst> geschrieben hast, oder weil Du dran kommen könntest)
- Manche Grafiktchips unterstützen auch nativ das Scrollen.
Achim S. schrieb:> - reicht vorerst ein (langsames, ruckartiges) Scrollen um jeweils ein> Zeichen. Z.B. falls Du keinen Pixelzugriff hast?
Die Lösung mit den einzelnen Pixel setzen ist schon recht Interessant
das würde ich gerne mal ausprobieren.
Achim S. schrieb:> - wird noch mehr auf dem Display angezeigt (drüber, drunter oder> daneben)
Auf dem Display wird noch mehr angezeigt. Es soll ganz unten als
"Newsticker" laufen ( Page 0 ).
Achim S. schrieb:> - nutzt Du ein Framework (GUI), was vielleicht sogar im Internet> beschrieb en ist?
Ich programmiere mit ATMEL Studio 7.x
Achim S. schrieb:> - Hast Du Zugang zum Grafikchip (entweder weil Du den Treiber selbst> geschrieben hast, oder weil Du dran kommen könntest)
Den Treiber habe ich soweit selbst geschrieben. Ich kann also auf alle
Funktionen vom "ST7565R" zugreifen.
Fonts nutze Ich die es auch so im Netz gibt mit den "Font Arrays".
Damit springe ich an Postion (x,y)
Ist das jetzt richtig umgebaut? Du hattest noch eine Variable
"use_target" in dem Source. Brauche Ich diese?
TICKER_COLS ist gleichzusetzen mit der Breite des Displays?
Peter W. schrieb:> Ist das jetzt richtig umgebaut?
Ja, sieht schon ganz gut aus :-)
> Du hattest noch eine Variable> "use_target" in dem Source. Brauche Ich diese?
Nein. Das ist im WordClock-Source eine alternative Pixel-Set-Methode.
Hier nicht relevant. Nimm use_target am besten komplett aus den
Parametern raus. Du musst dann natürlich alle Aufrufe von
display_show_ticker_char() anpassen, also den letzten Parameter
wegnehmen.
> TICKER_COLS ist gleichzusetzen mit der Breite des Displays?
Nein. In display.c findest Du für die WordClock24-Variante:
1
#define TICKER_LINES 8
2
#define TICKER_COLS 8
TICKER_LINES ist die Höhe des verwendeten Fonts in Pixeln, TICKER_COLS
ist die Breite eines Zeichens in Pixel. Die Definition des 8x8-Fonts
findest Du übrigens direkt darunter. Am besten übernimmst Du diese für
Deine ersten Tests.
> while> (start_col + col < WC_COLUMNS)> {> led.matrix[start_line + line][start_col + col] => CURRENT_STATE;> col++;> }>> Müssen hier die Pixel gesetzt oder gelöscht werden?
Gelöscht. Sobald das letzte Zeichen des des Strings ausgegeben wird und
rechts daneben ist noch Platz, muss dieser gelöscht werden, um alte
Pixel-Reste vom Vorgänger-Frame wegzulöschen. Hier könnte man übrigens
noch optimieren, würde aber für den ersten Lauf zu weit führen. First
make it work, then make it fine ;-)
> Was ist mit "WC_COLUMNS"?
WC_ROWS ist die Anzahl der Zeilen des Displays
WC_COLUMNS ist die Anzahl der Spalten des Displays
WC steht hier für "WordClock". Setze die Konstanten auf die Höhe/Breite
Deines Displays per #define. Vielleicht solltest Du Dir da auch noch 2
andere Namen für diese Konstanten ausdenken ;-)
Beispiel:
1
#define DISPLAY_ROWS 320
2
#define DISPLAY_COLUMNS 64
Die Werte sind natürlich nur Phantasiewerte, welche an die tatsächlichen
Pixel Deines Displays angepasst werden müssen.
Peter W. schrieb:> if (ticker_font[ch][line] & (1<<(TICKER_COLS - offset)))>> Was muss ich da abfragen? Das aktuelle Zeichen?
ch ist das aktuelle Zeichen, ja. Aber darum musst Du Dich gar nicht
kümmern, da es ja übergeben wird.
Aber ich sehe, dass Du den Parameter "unsigned char ch" aus der
Parameterliste von display_show_ticker_char() gestrichen hast...
warum?!?
Baue den wieder ein. Sonst läuft das nicht.
Frank M. schrieb:> ch ist das aktuelle Zeichen, ja. Aber darum musst Du Dich gar nicht> kümmern, da es ja übergeben wird.
Das heißt die Abfrage kann raus?
Peter W. schrieb:> Das heißt die Abfrage kann raus?
Nein, die Abfrage darf natürlich nicht raus. Abhängig vom Zeichen wird
hier ein Pixel gesetzt oder ein Pixel gelöscht. Du musst den
Funktionsparameter "unsigned char ch" wieder einsetzen. Warum hast
Du den überhaupt rausgenommen?
Da Du offenbar extreme Probleme hast, einen "Denkanstoß" in ein
laufendes Programm umzusetzen, habe ich das jetzt mal für Dich erledigt.
Im Anhang findest Du ein vollständig compilierbares Programm.
Du musst nur noch die Stellen, die mit "CHANGE HERE" kommentiert sind,
entsprechend an Dein Display anpassen.
P.S.
Der Ticker wird auf Höhe der Display-Mitte ausgegeben. Wenn Du ihn unten
durchlaufen lassen möchtest, musst Du die Zeile
Frank M. schrieb:> Da Du offenbar extreme Probleme hast, einen "Denkanstoß" in ein> laufendes Programm umzusetzen, habe ich das jetzt mal für Dich erledigt.>> Im Anhang findest Du ein vollständig compilierbares Programm.>> Du musst nur noch die Stellen, die mit "CHANGE HERE" kommentiert sind,> entsprechend an Dein Display anpassen.>> P.S.> Der Ticker wird auf Höhe der Display-Mitte ausgegeben. Wenn Du ihn unten> durchlaufen lassen möchtest, musst Du die Zeile start_line => (DISPLAY_ROWS - TICKER_LINES) / 2;>> auf die gewünschte Lage anpassen.
Habe es ausprobiert. Da sollte ja laut deinem Source "Hello World" durch
laufen. Da laufen nur einzelne Pixel durch also kein Zeichen zu
erkennen.
Peter W. schrieb:> Habe es ausprobiert. Da sollte ja laut deinem Source "Hello World" durch> laufen. Da laufen nur einzelne Pixel durch also kein Zeichen zu> erkennen.
Dann stimmt was mit Deinen set/clear-Funktionen nicht. Oder hast Du
einen anderen Font genommen, der evtl. eine andere Breite/Höhe hat?
Ich habe jetzt mal die entsprechenden Stellen, wo CHANGE HERE steht, mit
Werten gefüllt für eine ASCII-Ausgabe, wobei ich die Display-Größe auf
10x40 Pixel gesetzt habe:
1
#define DISPLAY_ROWS 10 // Number of lines of display, CHANGE HERE!
2
#define DISPLAY_COLUMNS 40 // Number of columns of display, CHANGE HERE!
Und dann noch in Funktion display_set_ticker() vor dem
delay_msec()-Aufruf ein
1
show_display();
eingefügt, weil ich der Einfachheit halber für die Text-Ausgabe mit
einem Array matrix[][] arbeite.
Die Ausgabe siehst Du im Anhang. Die einzelnen Frames stehen hier
untereinander.
Irgendwas machst Du falsch.
Frank M. schrieb:> Peter W. schrieb:>> Habe es ausprobiert. Da sollte ja laut deinem Source "Hello World" durch>> laufen. Da laufen nur einzelne Pixel durch also kein Zeichen zu>> erkennen.>>> Irgendwas machst Du falsch.
Erstmal Danke das du dir die Zeit nimmst um Mir zu helfen.
Benutzen tue ich ein 64 x 128 Pixel Display mit einem verbauten ST7565
Kontroller.
Betreiben tue ich das Display anders herum. Das sollte aber erstmal egal
sein. Da ist dann nur die Schrift nicht lesbar bzw. verkehrt herrum.
Die Funktionen um ein Pixel zu setzen bzw. zu löschen sehen bei mir so
aus..
1
voidglcdSetPixel(uint8_tx,uint8_ty)
2
{
3
glcdSetPageColumn(x/8,y);
4
glcdSendData(_BV(7-(y%8)));
5
}
6
7
voidglcdClearPixel(uint8_tx,uint8_ty)
8
{
9
glcdSetPageColumn(x/8,y);
10
glcdSendData(0<<(x%8));
11
}
Bei mir wird ohne einen VRAM gearbeitet, dass sollte jedoch keine Rolle
spielen oder?
Peter W. schrieb:> void glcdSetPixel(uint8_t x, uint8_t y)> void glcdClearPixel(uint8_t x, uint8_t y)
Was sehe ich da? x und y vertauscht.
Drehe das mal rum. Egal, ob jetzt in Deinen Set/Clear-Parametern oder im
Aufruf. Hauptsache, nicht beides ;-)
> Bei mir wird ohne einen VRAM gearbeitet, dass sollte jedoch keine Rolle> spielen oder?
Sollte nicht.
Frank M. schrieb:> Peter W. schrieb:>> void glcdSetPixel(uint8_t x, uint8_t y)>> void glcdClearPixel(uint8_t x, uint8_t y)>> Was sehe ich da? x und y vertauscht.>> Drehe das mal rum. Egal, ob jetzt in Deinen Set/Clear-Parametern oder im> Aufruf. Hauptsache, nicht beides ;-)>>> Bei mir wird ohne einen VRAM gearbeitet, dass sollte jedoch keine Rolle>> spielen oder?>> Sollte nicht.
Ich habe es ein bisschen doof beschrieben in meinen Funktionen.
Ok. Ich kenne Dein Display nicht, kann also nichts näheres zu Deinen
HW-Routinen sagen.
Ist es denn so, dass das Display den jeweiligen Pixel instantan leuchten
lässt oder muss man da noch eine Art Flush senden, damit die
vorangegangenen Pixel-Befehle auch wirksam werden?
Frank M. schrieb:> Ok. Ich kenne Dein Display nicht, kann also nichts näheres zu> Deinen> HW-Routinen sagen.>> Ist es denn so, dass das Display den jeweiligen Pixel instantan leuchten> lässt oder muss man da noch eine Art Flush senden, damit die> vorangegangenen Pixel-Befehle auch wirksam werden?
Da du mich darauf aufmerksam gemacht hast (habe die Pixel funktion sonst
nicht weiter im Betrieb) ist mir aufgefallen das die Berechnung nicht
sauber funtkioniert.
> Da du mich darauf aufmerksam gemacht hast (habe die Pixel funktion sonst> nicht weiter im Betrieb) ist mir aufgefallen das die Berechnung nicht> sauber funtkioniert.void glcdSetPixel(uint8_t x, uint8_t y)> {> glcdSetPageColumn(x/8,y);> glcdSendData((x%8));> }> muss Ich mal forschen woran das liegt..
Kann es sein, dass man die Pixel die gesetzt sind im Displayram vorher
noch auslesen muss und dann verODERN?
Peter W. schrieb:>> Da du mich darauf aufmerksam gemacht hast (habe die Pixel> funktion sonst>> nicht weiter im Betrieb) ist mir aufgefallen das die Berechnung nicht>> sauber funtkioniert.void glcdSetPixel(uint8_t x, uint8_t y)>> {>> glcdSetPageColumn(x/8,y);>> glcdSendData((x%8));>> }>> muss Ich mal forschen woran das liegt..>> Kann es sein, dass man die Pixel die gesetzt sind im Displayram vorher> noch auslesen muss und dann verODERN?
Also das mit dem auslesen fällt wohl flach. Die Pins sind leider nicht
dafür vorgesehen.
Dann könnte Ich ja die Methode mit dem VRAM nehmen?
Peter W. schrieb:> Die Pins sind leider nicht dafür vorgesehen.
Wenn jedes Setzen eines Bits die anderen desselben Bytes wieder
zurücksetzen, ist das natürlich der Grund, warum Du da nur einzelne
Pixel siehst.
Ich habe keine Ahnung, wie der Speicher Deines Displays organisiert ist.
Theoretisch könnte man, wenn man es geschickt anstellt, das Display
byteweise füttern, indem man ein Byte als Buffer nimmt. Aber dann kannst
Du natürlich nur an Bytegrenzen das Display pixelweise ansteuern.
> Dann könnte Ich ja die Methode mit dem VRAM nehmen?
Wie gesagt: ich kenne die HW nicht, von daher sagt mir VRAM auch nichts.
Wenn es ein Speicher ist, den man erstmal füllen kann, bevor man ihn ins
Display kopiert, wäre das natürlich eine Möglichkeit. Dann musst Du
einfach vor der Stelle, wo der Delay-Aufruf steht, den Copy ins
physikalische RAM durchführen.
Frank M. schrieb:>> Dann könnte Ich ja die Methode mit dem VRAM nehmen?>> Wie gesagt: ich kenne die HW nicht, von daher sagt mir VRAM auch nichts.> Wenn es ein Speicher ist, den man erstmal füllen kann, bevor man ihn ins> Display kopiert, wäre das natürlich eine Möglichkeit. Dann musst Du> einfach vor der Stelle, wo der Delay-Aufruf steht, den Copy ins> physikalische RAM durchführen.
VRAM = VideoRam. Genau.
Das man wirklich jedes Pixel einzeln setzt ist bei mir vielleicht auch
ein bisschen zu viel. Es müsste schon reichen wenn Ich jedes Byte
einzeln Übertrage. Nehmen wir an das dass 'A' bei mir im Font 5x8(BxH)
hat.
So kopiere Ich in den VRAM
1
for(uint8_ti=0;i<5;i++)
2
VRAM[i]=font['A][i++];
So hätte ich jetzt das 'A' Byte weise im VRAM dahinter kommen dann noch
die anderen Buchstaben und evtl. Leerzeichen.
Jetzt ist nur die Frage wie Ich das an deinen Funktionen ankopple.
Du meintest.:
> Dann musst Du> einfach vor der Stelle, wo der Delay-Aufruf steht, den Copy ins> physikalische RAM durchführen.
So habe Ich das jetzt verstanden.:
Diesen "VRAM" könnte Ich mir auch sparen indem man das so ähnlich
realisiert wie Du in deinem Quellkode.
Bloß das Ich an meiner Stelle gleich 1 Spalte übertrage (also ein Byte).
Da bei mir das Display so angeordnet ist.
1
|||||||
'|' Stellen ein Byte dar. Es gibt wohl auch Display die Waagerecht
schreiben und nicht wie meins Senkrecht.
Peter W. schrieb:> Diesen "VRAM" könnte Ich mir auch sparen indem man das so ähnlich> realisiert wie Du in deinem Quellkode.
Ja. Das ginge. Man definiert ein Array matrix[][] und setzt dann im
Display direkt immer ein ganzes Byte.
Blöd ist nur, dass bei Deinem Display die Bytes senkrecht stehen. Aber
das bekommt man auch hin. Lass mich mal ein wenig nachdenken, dann kann
ich heute abend eine Lösung posten.
Frage dazu: Ist das LSB oder MSB eines Bytes immer "oben"?
Frank M. schrieb:> Frage dazu: Ist das LSB oder MSB eines Bytes immer "oben"?
Jetzt schreib ihm doch das Programm, so wie er es gerne hätte und gut is
:-)
Frank M. schrieb:> Peter W. schrieb:> Diesen "VRAM" könnte Ich mir auch sparen indem man das so ähnlich> realisiert wie Du in deinem Quellkode.>> Ja. Das ginge. Man definiert ein Array matrix[][] und setzt dann im> Display direkt immer ein ganzes Byte.>> Blöd ist nur, dass bei Deinem Display die Bytes senkrecht stehen. Aber> das bekommt man auch hin. Lass mich mal ein wenig nachdenken, dann kann> ich heute abend eine Lösung posten.>> Frage dazu: Ist das LSB oder MSB eines Bytes immer "oben"?
Habe mir schon eine kleine Routine geschrieben die mir dies umtauscht
also das MSB, LSB. Das sollte kein Problem sein.
Ich lerne hierbei schon sehr viel danke dafür!
Habe eben mal den Source angepasst, siehe Anhang.
Ich nehme mal an, dass das Display 64 Zeilen und 128 Spalten hat und
nicht umgekehrt.
Sonst muss man halt die Werte für
1
#define DISPLAY_ROWS 64 // Number of lines of display, CHANGE HERE!
2
#define DISPLAY_COLUMNS 128 // Number of columns of display, CHANGE HERE!
vertauschen.
In der Funktion show_display() werden die Pixel byteweise ins
Display-RAM kopiert:
1
staticvoid
2
show_display(void)
3
{
4
intx;
5
6
for(x=0;x<DISPLAY_COLUMNS;x++)
7
{
8
glcdSetPageColumn(0,x);
9
glcdSendData(matrix[x]);
10
}
11
}
Hier werden die untersten 8 Pixelzeilen verwendet, wenn ich es richtig
verstanden habe.
Wenn der Text auf dem Kopf erscheinen sollte, liegt es daran, dass die
Bits verkehrt herum gesetzt wurden. Du hattest meine Frage, ob das LSB
oder MSB "oben" erscheint, leider nicht beantwortet.
In diesem Fall müssen die Funktionen set_pixel() und clear_pixel()
derart geändert werden, dass man "line" durch (7 - line) ersetzt wird,
also:
1
staticvoid
2
set_pixel(uint_fast16_tline,uint_fast16_tcol)
3
{
4
matrix[col]|=(1<<(7-line));
5
}
6
7
staticvoid
8
clear_pixel(uint_fast16_tline,uint_fast16_tcol)
9
{
10
matrix[col]&=~(1<<(7-line));
11
}
Es kann auch sein, dass ich die Funktionalität von glcdSetPageColumn()
falsch verstanden habe. Bitte mal den Aufruf in show_display() prüfen.
Du solltest auf jeden Fall noch die Funktion delay_msec() füllen, sonst
geschieht alles so schnell, dass man kaum etwas sehen wird.
Suche ich das aktuelle Zeichen aus meinem Font Array.
und mit f.IndexNum, zeige Ich auf den Startwert vom ersten Zeichen.
Müsste doch eigentlich hinhauen? Ist nur die Frage ob der Aufruf dort an
der richtigen Stelle ist.
Peter W. schrieb:> Rollt die Schrift bei deinem Projekt denn komplett von rechts rein> oder fängt sie auch in der Mitte vom Display an?
Sie rollt von rechts rein. Allerdings hat die WordClock wesentlich
weniger Pixel. Schau mal nach in display_set_ticker(). Da stelle ich 2
Blanks voran. Da solltest Du entsprechend mehr Leerzeichen einfügen -
dann besser in einer Schleife.
Peter W. schrieb:> Wenn ich meinen eigenen Font dort einbauen möchte, kann ich das wie> folgt machen?
Probiere es aus. Ich kenne Deinen Font nicht. Meine Glaskugel ist heute
etwas trüb ;-)
Wenn Dir bei dem Font die kleinen Buchstaben (welche kleinere
Großbuchstaben sind) nicht gefallen, kannst Du auch den anderen
Alternativfont aus display.c für die WordClock12 statt WordClock24
ausprobieren. Der hat echte Kleinbuchstaben.
Frank M. schrieb:> Peter W. schrieb:>> Wenn ich meinen eigenen Font dort einbauen möchte, kann ich das wie>> folgt machen?>> Probiere es aus. Ich kenne Deinen Font nicht. Meine Glaskugel ist heute> etwas trüb ;-)
Es geht nicht direkt um den Font sondern um das lesen vom Font.
Direkt am Anfang deiner Funktion suche Ich das Zeichen aus meinem Font
raus und zeige auf dessen Startadresse im Array.
Dann kommt deine for Schleife und knallt die ganzen Bytes von der
aktuellen Startadresse meines Zeichens in den "VRAM(matrix)" sehe Ich
das richtig?
Das Zeichen bzw. die Startadresse von dem Zeichen wo die "Pixeldaten"
anfangen muss immer nur immer beim Funktionsaufruf gelesen werden oder
muss in der for Schleife noch ein neues Zeichen gelesen werden?
Peter W. schrieb:> Das Zeichen bzw. die Startadresse von dem Zeichen wo die "Pixeldaten"> anfangen muss immer nur immer beim Funktionsaufruf gelesen werden oder> muss in der for Schleife noch ein neues Zeichen gelesen werden?
Es wird der Funktion doch nur ein Zeichen namens "ch" übergeben, wie
soll da in der Schleife noch ein weiteres gelesen werden?
Du solltest erst einmal den Source verstehen, bevor Du da selber Hand
anlegst. Die paar Zeilen sind nicht die Welt.
Frank M. schrieb:> Du solltest erst einmal den Source verstehen, bevor Du da selber Hand> anlegst. Die paar Zeilen sind nicht die Welt.
Genau das ist das Problem. Wie die Schleifen funktionieren, ist mir
bekannt. Nur sich in die ganzen Werte rein zu denken, fällt mir ziemlich
schwer wenn Ich nicht gerade den Kode geschrieben habe.
Peter W. schrieb:> Nur sich in die ganzen Werte rein zu denken, fällt mir ziemlich> schwer wenn Ich nicht gerade den Kode geschrieben habe.
Ein Teufelskreis.
Daniel schrieb:> Ein Teufelskreis.
Fürwahr :-)
Der lässt sich wohl nur durch ein fertiges Programm incl. (Online-)
Hilfe und kostenlosem Support-Vertrag durchbrechen.