Ist in der Funktion ein Denkfehler?
Die Zeichen die dabei raus kommen sind verschoben oder überhaupt nicht
zu erkennen. Ist bei meiner Berechnung etwas falsch?
Kann sich das mal bitte jemand anschauen?!
Ohne den vollständigen Quelltext ist das schwer zu sagen. Die Werte der
allermeisten Konstanten sind unbekannt und man muss raten, wie du die
Funktion verwendest.
Stefanus F. schrieb:> Ohne den vollständigen Quelltext ist das schwer zu sagen. Die> Werte der> allermeisten Konstanten sind unbekannt und man muss raten, wie du die> Funktion verwendest.
Da hast Du vollkommend recht. Habe noch was vergessen..
1
enumFont_Struct
2
{
3
FONT_BEGIN,
4
FONT_END,
5
FONT_WIDTH,
6
FONT_HEIGHT,
7
FONT_FIRST_CHAR,
8
FONT_CHAR_COUNT
9
FONT_BEGIN_PIXEL,
10
FONT_FIXED_OR_VARIABLE,
11
};
Das sind eigentlich nur die Indexnummern für die Werte aus dem "Font
Array".
Die Funktion rufe ich auch, bevor ich ein Zeichen brauche, in der
Struktur die zurückgegeben wird, sollte dann der Start der Pixel
Informationen und deren einzelnen Breiten stehen..
Wie rufst du die Funktion auf?
Annahme:
Font ist ein zunächst leeres Objekt, dass die Funktion befüllen soll.
ptrFont ist ein Zeiger auf die Font Daten im Header.
Das passt aber nicht zu deinem Code, denn da liest du munter
wechselweise von ptrFont und Font.ptrFont. Frage: Wo sind die Font Daten
(input). In ptrFont oder in Font.ptrFont?
Stefanus F. schrieb:> Wie rufst du die Funktion auf?>> Annahme:> Font ist ein zunächst leeres Objekt, dass die Funktion befüllen soll.> ptrFont ist ein Zeiger auf die Font Daten im Header.>> Das passt aber nicht zu deinem Code, denn da liest du munter> wechselweise von ptrFont und Font. Frage: Wo sind die Font Daten> (input). In ptrFont oder in Font?
Stimmt. Sehe ich gerade.
Jan H. schrieb:> Font.uiCharWidth => ptrFont[(c-Font.ptrFont[FONT_FIRST_CHAR])+OFFSET_SETTING_INFOS]; //> Breite des Zeichens> Font.uiIndexBegin = Font.ptrFont[FONT_PIXEL_BEGIN]; // Offset (ab> hier beginnen die Pixel Daten)
Du meinst mit Sicherheit das? Ist ein wenig sinnlos, muss ich ändern.
Jedoch ist beides eine Referenz auf den Zeichensatz.
Jan H. schrieb:> Du meinst mit Sicherheit das?
Ja genau, das.
Du kannst das Ganze ja mal in einem Debugger oder Simulator durchsteppen
und dabei schauen, ob die Berechnungen die erwarteten Werte ergeben.
Oder du gibst sie zum Debugging auf einem seriellen Port aus.
Stefanus F. schrieb:> Jan H. schrieb:>> Du meinst mit Sicherheit das?>> Ja genau, das.>> Du kannst das Ganze ja mal in einem Debugger oder Simulator durchsteppen> und dabei schauen, ob die Berechnungen die erwarteten Werte ergeben.> Oder du gibst sie zum Debugging auf einem seriellen Port aus.
Habe es angepasst.
>Ist in der Funktion ein Denkfehler?>Die Zeichen die dabei raus kommen sind verschoben oder überhaupt nicht>zu erkennen. Ist bei meiner Berechnung etwas falsch?
Ja, deine Berechnung ist falsch. Bei deiner Berechnung der Bytes
pro Zeichen kommt immer der gleiche Wert raus. Die Anzahl der Bytes
pro Zeichen ist aber nicht immer gleich. Du wirst schon die Werte
unter // char widths auswerten müssen statt Font.ptrFont[FONT_WIDTH].
Neuer Versuch:
Font.uiIndexBegin += (ptrFont[charNum + OFFSET_SETTING_INFOS] * 2 )
Die 2 da hinten. Für den Courier müsste da eine 4 stehen.
Du berücksichtigst die Höhe des Fonts dort nicht.
holger schrieb:> Neuer Versuch:>> Font.uiIndexBegin += (ptrFont[charNum + OFFSET_SETTING_INFOS] * 2 )>> Die 2 da hinten. Für den Courier müsste da eine 4 stehen.> Du berücksichtigst die Höhe des Fonts dort nicht.
Es geht da wirklich nur um die Weite des Zeichens. Die Höhe ist ja Fix.
>Es geht da wirklich nur um die Weite des Zeichens. Die Höhe ist ja Fix.
Ja, klar ist die fix. Aber mit der zwei hinten kannst du nur Zeichen
von 9 bis 16 Pixel Höhe auswerten. Die Höhe ist aber 26Pixel.
holger schrieb:>>Es geht da wirklich nur um die Weite des Zeichens. Die Höhe ist ja Fix.>> Ja, klar ist die fix. Aber mit der zwei hinten kannst du nur Zeichen> von 9 bis 16 Pixel Höhe auswerten. Die Höhe ist aber 26Pixel.
Habs mit "*4" versucht, genau das gleiche.
Du lieferst nicht gerade gute Informationen um Dir zu helfen, ist Dir
das klar?
* Dein "enum Font_Struct" enthält andere Werte als Du im Code benutzt
(z.B. FONT_BEGIN_PIXEL vs. _FONT_PIXEL_BEGIN)
* Auch in Deinem "angepassten" Code geht weiterhin ptrFont und
Font.ptrFont munter durcheinander.
Weißt Du eigentlich, wie die Font-Daten organisiert sind?
Anhand des Zeichens 33 (das Ausrufungszeichen) habe ich durch
ausprobieren herausbekommen, dass die Daten wohl spaltenweise von oben
nach unten abgelegt sind, das lsb der Bytes ist dabei oben.
Spaltenwechsel ist immer an einer Bytegrenze, d.h. beim vorliegenden
Font sind die höherwertigsten 6 Bits jedes vierten Byte "don't care".
Nehmen wir mal an:
1
#define _FONT_WIDTH 2
2
#define _FONT_HEIGHT 3
3
#define _FONT_FIRST_CHAR 4
4
#define _FONT_PIXEL_BEGIN 6
5
#define _FONT_FIXED_OR_VARIABLE 7
Anzahl Bytes pro Spalte ist also:
1
bytes_per_col=(((ptrFont[_FONT_HEIGHT]-1)/8)+1);
Für den Offset musst Du alle Zeichenbreiten vor dem gesuchten addieren.
Bist Du sicher, dass Du die Pixeldaten dann auch richtig ausgegeben
bekommst, wenn Dir die Routine den Offset richtig berechnet hat? (ich
hab' da so meine Zweifel... ;-)
Jan H. schrieb:> Habe es angepasst.
..und es ist nach wie vor zumindest für mich herzlich unleserlich. Was
willst du mit diesem Code eigentlich bezwecken? Was bedeutet
"GetPixelStart" und wozu sollte man sowas brauchen?
Also, ich sehe das GANZ anders:
Für ne grafische Darstellung braucht man eine Funktion, die ein
Textzeichen an einer bestimmten Stelle auf einer grafischen Oberfläche
(z.B. Display) zeichnen kann. Im Allgemeinen sollte dies in einer Farbe
möglich sein, die irgendwo vorgegeben ist. Dazu kommt, daß das
Textzeichen in einem gewünschten Font gezeichnet werden soll. Für das
Zeichnen von Zeichenketten (Strings) ist es wünschenswert, daß diese
Funktion die Breite des aktuellen Zeichens zurückliefert. Also sieht so
eine Funktion erstmal etwa so aus:
Und diese Funktion soll mit den verschiedensten Fonts zurecht kommen,
also müssen die Fonts eine gewisse Struktur haben, aus der man möglichst
leicht ermitteln kann, was da alles an Zeichen vorhanden ist, wie groß
so ein Zeichen ist, wo der zugehörige Glyph steht und so weiter.
Ich habe das bei meinen Fonts so gehandhabt:
1
/* Beschreibung des verwendeten Font-Formates:
2
zuerst kommt der Font-Header in folgendem Format: */
3
4
#define Fontheadersize 6
5
structFontheader
6
{byteCapitals;/* Hoehe der Grossbuchstaben */
7
byteHeight;/* Font-Gesamthoehe */
8
byteAscent;/* Hoehe ueber Null-Linie */
9
byteDescent;/* Tiefe unter Null-Linie */
10
charChMin;/* kleinstes vorhandenes Zeichen */
11
charChMax;/* groesstes vorhandenes Zeichen */
12
};
13
14
/* danach kommen unterschiedlich viele Char-Entries.
15
eigentlich ist 'Disp' ein 16 bit Offset, aber der
16
Font muss bei BigEndian und LittleEndian-CPU's
17
gleichermassen funktionieren, deswegen die explizite
18
Aufteilung in DispHi und DispLo */
19
20
#define Charentrysize 4
21
structCharEntry
22
{byteDispHi;/* Hi vom Displacement ab Fontbeginn */
23
byteDispLo;/* Lo vom Displacement ab Fontbeginn */
24
bytedX;/* Breite in Pixeln */
25
bytedY;/* Hoehe in Pixeln */
26
};
27
28
/* danach kommen die Pixel. Jeder CharEntry (s.o.) zeigt
29
auf den Beginn des zu seinem Char gehörigen Bitmusters.
30
Jedes Bitmuster beginnt an einem ganzen Byte, aber innerhalb
31
geht es je nach Zeichenbreite asynchron zu den Bytegrenzen */
Und die Funktion, die mithilfe eines so aufgebauten Fonts Text auf die
Glotze schreiben kann geht so (hier für Monochrom):
/* aus dem Font die Breite, Höhe und Pixel entnehmen */
17
FHE=(structFontheader*)Font;
18
if((Ch<FHE->ChMin)||(Ch>FHE->ChMax))Ch=0;
19
elseCh=Ch-FHE->ChMin;
20
CHE=(structCharEntry*)((long)FHE+Fontheadersize);
21
CHE+=Ch;
22
w=(CHE->DispHi<<8)|CHE->DispLo;
23
Pix=(byte*)((long)FHE+w);
24
25
/* bott setzen */
26
bott=top+CHE->dY;
27
if(bott>lcdhoehe-1)bott=lcdhoehe-1;
28
29
/* die Register sind jetzt:
30
bott = zeigt jetzt hinter die unterste zu schreibende Zeile des Zeichens
31
Pix = Zeiger auf zugehörige Pixel im Font
32
FHE, CHE haben sich (fast) erledigt
33
Nun die ersten Fontpixel und die Maske laden
34
*/
35
pixw=*Pix++;
36
w=1;
37
38
/* Y - Zeichen-Zyklus */
39
while(top<bott)
40
{/* X - Zeichen-Zyklus */
41
dX=0;
42
while(dX<CHE->dX)/* Zeichenbreite in Pixeln */
43
{if(pixw&w)CgPixel_at(X+dX,top,mode);
44
++dX;
45
w=(w<<1)&0xFF;
46
if(!w)
47
{pixw=*Pix++;
48
w=1;
49
}
50
}
51
++top;
52
}
53
returnCHE->dX;
54
}
So geht das - und so ein Font ist von hause aus proportional, hat also
je nach Zeichen unterschiedliche Zeichenbreiten. Natürlich kann man
damit auch Courier12 machen, indem man die Zeichenbreite eben beim
Fontmachen konstant läßt. Ebenso kann man damit auch monochrome Icons
und Piktogramme machen, die Schreibfunktion kommt mit allen Formaten
zurecht, solange der Font korrekt ist.
Den ganzen Krempel hatte ich hier schon mal gepostet, ebenso dazu einen
kleinen Font-Compiler.
W.S.
Erstmal danke euch beiden für die super Erklärung.
Wenn ich den Index richtig berechnet haben sollte, bin ich bis jetzt
soweit mit der Ausgabefunktion.
Ich vermute mal das es hier auch noch einige Sachen gibt die fehlerhaft
sind.
1
voidSsd1306PutChar(charc,int16_ty,int16_tx)
2
{
3
Font=calcFontStart(c,Font,Font.ptrFont);
4
5
/* Höhe des Zeichens in "Pages" aufgeteilt ( Page = 8 Pixel )
Ich würde hier nicht einzelne Pixel ausgeben, sondern möglichst größere
Blöcke von Bytes. Sonst dauert das ja "ewig". Kannst du nicht direkt in
den Pufferspeicher schreiben, anstatt den Umweg über Ssd1306DrawPixel()
zu nehmen?
W.S. schrieb:> int ZeichneChar(char c, int x, int y, irgendwas* Font, int Farbe)> {...
Kaum. Im allgemeinen will man nicht bei jedem Zeichen Font oder Farbe
wechseln.
Das Interface stimmt nicht. Font und Farbe stellt man einmal für
zukünftige Ausgaben ein.
leo
Stefanus F. schrieb:> Ich würde hier nicht einzelne Pixel ausgeben, sondern möglichst größere> Blöcke von Bytes. Sonst dauert das ja "ewig". Kannst du nicht direkt in> den Pufferspeicher schreiben, anstatt den Umweg über Ssd1306DrawPixel()> zu nehmen?
Klar kann man das. Wollte aber auch mal die Pixel Variante versuchen und
verstehen.
Habe es ja vorher so gehabt.
Jan H. schrieb:> Wollte aber auch mal die Pixel Variante versuchen und verstehen.
Bei mir sind die Bytes im Font genau so ausgerichtet, wie im Speicher
des Display (Jedes Byte stellt 8 Pixel dar, die untereinander stehen,
also ein vertikale Linie ergeben). Wenn die Zeile Text "zufällig" genau
passend ausgerichtet ist, kann ich einfach die Bytes aus dem Font 1:1 in
den Pufferspeicher übertragen. Wenn nicht, teile ich den Text in obere
und untere Hälfte auf, bevor ich die beiden halben Zeilen in den
Pufferspeicher übertrage.
Aber die Sache mit dem Aufteilen hätte ich mir schenken können. Da bin
ich übers Ziel hinaus geschossen (von wegen Eierlegende Wollmilchsau).
In der Praxis genügt es, acht Zeilen mit fester y-Position zu haben. Wer
will schon Text dazwischen ausgeben?
Damit bekomme ich jetzt definitiv den richtigen Anfang meines gesuchten
Zeichens, des Weiteren scheibe ich die ganzen Informationen wie ( Höhe,
Breite , Start ) in eine Struktur.
Der Zeiger zu dem Array, ist jetzt nicht mehr Teil der Struktur. Der
Zeiger wurde global ausgelagert.
Wenn das mit dem Zeichen der einzelnen Pixel sauber klappt, werde ich
deine Lösung auch vorziehen. Wie Du schon sagtest, frisst das um längen
nicht so viele Ressourcen.
Was kann ich an der Ausgabefunktion noch verändern / verbessern?
Diese soll die Pixel in ein "VRAM" schreiben, dass später an einer
anderen Stelle, wenn es fertig befüllt ist, übertragen werden.
Zeichen in den VRAM schreiben ->
1
voidSsd1306PutChar(charc,int16_ty,int16_tx)
2
{
3
Font=GetFont(c);
4
5
/* Höhe des Zeichens in "Pages" aufgeteilt ( Page = 8 Pixel )