Forum: Mikrocontroller und Digitale Elektronik Schrift für Grafikdisplay, Text ausgeben


von Thorsten (Gast)


Angehängte Dateien:

Lesenswert?

Hallo zusammen,

ich versuche mich gerade an einem GLCD Display 128*64 Pixel, Controller 
SSD1305.

Ich habe einen Beispielcode aus dem Netz genommen und ein wenig damit 
rumexpermentiert. Grundsätzlich funktioniert das auch.

Ich habe nun aber ein Problem mit Schriften.

Bei dem Beispielcode waren zwei Schriften dabei einmal 8x16 und einmal 
6x8. Die Ausgabe funktioniert auch einwandfrei. Ich würde nun gerne noch 
andere Schriften ausgeben, also andere Größe z.B. 4x6 oder so.
Da liegt jetzt mein Problem. Hier im Forum gibt es ja genug Schriften 
für LCDs. Wenn ich mir nun so eine Schrift nehme und ausgebe, 
funktioniert das nicht. Es irgendwas ausgegeben, aber kein Text bei den 
von mir erstellen Schriften.

Wäre klasse, wenn mir da jemand weiterhelfen könnte.

Im Anhang einmal die Datei mit den Schriften und meine Funktionen für 
das Display.

Grüße
Thorsten

von Thorsten (Gast)


Lesenswert?

Ich nochmal,

ganz veressen zu schreiben. Den Code habe ich hier aus dem Forum, leider 
war ich so schlau mir keine lesezeichen zum Thread zu setzen.

Im Code war noch der entsprechende Hinweis. Vielleicht hat es ja schon 
einmal jemand gesehen:
1
 /*--------------------------------------|
2
|File:     lcd.c      |
3
|Date:      August 2011    |
4
|Author:   J. Moertl    |
5
|Description:Source data to control the |
6
|   EA DOGS102-6 lcd module  |
7
|   including init, write and  |
8
|        drawing functions.    |
9
|--------------------------------------*/

Grüße

von Karl H. (kbuchegg)


Lesenswert?

Thorsten schrieb:

> Da liegt jetzt mein Problem. Hier im Forum gibt es ja genug Schriften
> für LCDs. Wenn ich mir nun so eine Schrift nehme und ausgebe,
> funktioniert das nicht. Es irgendwas ausgegeben, aber kein Text bei den
> von mir erstellen Schriften.

Tja. Du musst natürlich schon drauf achten, wie die Fonts aufgebaut sind 
bzw. wie die Funktion, die letzten Endes die Buchstaben ausgibt, die 
Bytes aus den Fonts auseinander nimmt.

> Wäre klasse, wenn mir da jemand weiterhelfen könnte.

Das kannst du auch selber. Blöderweise hat derjenige, der deine Fonst 
gebaut hat, so ziemlich das Dämlichste gemacht, was er hätte machen 
können. Er hat Byteangaben, bei denen es eine Bit-Pixel Korrelation 
gibt, als Dezimalzahlen angeschrieben anstatt als wesentlich näher 
liegenden Hex-Zahlen. Das beschert dir jetzt eine Zusatzarbeit. Aber so 
schlimm ist es auch wieder nicht.

Lass uns mal so einen Font ansehen. Wie beginnt er
1
const unsigned char font_8X16[font_8X16_LEN] PROGMEM =
2
{
3
  70, 86, 32,255,  8, 16,  2, 16,
4
  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
5
  0,  0,  0,252,252,  0,  0,  0,  0,  0,  0, 51, 51,  0,  0,  0,
6
  0,252,252,  0,  0,252,252,  0,  0,  0,  0,  0,  0,  0,  0,  0,
7
....

Auffällig ist, das die erste Zeile anders aussieht, als die anderen. Die 
erste zeile besteht aus 8 Bytes, alle weiteren aus 16 Bytes. Hmm. Die 16 
kommen einem bekannt vor. Was war noch mal die Font-'Größe'? 8 mal 16. 
So, so. Ein Zeichen ist also 8 Pixel breit (oder hoch) und 16 Pixel hoch 
(oder breit). Ob die letztere 16 was damit zu tun hat, dass da jeweils 
16 Bytes pro Zeile sind? Wir werden sehen.
Auffällig ist trotzdem, dass die erste Zeile anders aussieht. Was könnte 
das sein?
Na, ja. So eine Funktion, die Zeichen ausgibt, wird ja wohl ein paar 
Informationen brauchen. Wie zum Beispiel: wie breit ist ein Zeichen. Wie 
hoch ist ein Zeichen. etc. etc. Irgendwo muss diese Inforamtion ja 
stehen. Und da ist es wohl auch naheliegend, dass diese Zeile diese 
Information (und weitere) beinhalten könnte.

Wie könnte man das klären?

Einfach. Du hast ja den Code. Wenn du deiner Codebasis diese Daten 
übergibst, dann wird sich da ja wohl entsprechender Code finden, der 
diese Information ausliest. Und mit ein bischen Glück hat der Autor des 
Codes da vernünftige Variablennamen gewählt, mit denen man was anfangen 
kann.
Schauen wir doch mal in den Code. Was findet sich da?

OK. Der Autor war nicht so freundlich, sondern hat das ein wenig 
versteckt
1
  //calculate positon of data in font array
2
  //(data*Bytes pro Char)-(start of chars * bytes pro char)+bytes for header
3
  font_pos=(data*pgm_read_byte(font + 7))-(pgm_read_byte(font + 2)*pgm_read_byte(font + 7))+8;
4
5
  font_pos-=pgm_read_byte(font + 4); //subtract pixels for one char, because it's added again in loop

font + 7 ist nichts anderes als &font[7]. Also das 8. Byte im Font.

Also das hier
1
// 0   1   2   3   4   5   6   7
2
  70, 86, 32,255,  8, 16,  2, 16,
3
                               ^
4
                               |
Also 16.

Was stand da im Kommentar?
1
  //(data*Bytes pro Char) ....
Bytes pro Char. Ja das könnte hinkommen. Bei einem Font der 16 Pixel 
breit (oder hoch) ist, würde man erwarten, dass jedes Zeichen auch 16 
Bytes breit ist. Passt soweit.

Wie gings weiter im Kommentar
1
     .... (start of chars * bytes pro char) ....
das korrespondiert recht augenscheinlich mit dem hier
1
    .... (pgm_read_byte(font + 2)*pgm_read_byte(font + 7)) ....
die font + 7 kennen wir schon, also wird wohl font + 2, vulgo &font[2], 
die 'start of chars' sein. Schaun wir mal, was da im Datenfeld steht
1
// 0   1   2   3   4   5   6   7
2
  70, 86, 32,255,  8, 16,  2, 16,
3
           ^
4
           |
32.
Gut. Jetzt wissen wir, das im ASCII Code die ersten 32 Zeichen 
Steuerzeichen sind und die eigentlich darzustellenden Zeichen erst mit 
dem 33. zeichen beginneb. Das trägt daher den ASCII Code 0x20 und ist, 
ASCII Kenner wissen das, ein Leerzeichen.

D.h. die 32 machen durchaus Sinn. Zumindest ist das eine Zahl, mit der 
man was anfangen kann. Da dieser Term vom bisherigen abgezogen wird, 
kann man daraus schliessen, dass die Idee wohl darin besteht, ganz 
einfach eine Tabelle mit den Pixeldaten zu haben. Der ASCII Code eines 
Zeichens ist Index in diese Byte Tabelle. Da jedes Zeichen 16 Byte 
benötigt, beginnt also das Zeichen mit dem Code 0 an Position 0, das mit 
dem Code 1 an Position 16, das mit dem Code 2 an Position 32 usw. usw. 
Der Autor des Codes, will aber die nicht darstellbaren Zeichen nicht in 
der Tabelle haben, verbraucht nur Platz. Also hat er die ersten 32 
Zeichen einfach ausgelassen. D.h. aber er muss eine Korretur anbringen. 
Denn das erste darstellbare Zeichen (wir erinnern uns, das war ein 
Leerzeichen), hat ja den Code 32. Damit dessen Beschreibung in der 
Tabelle an der Position 0 startet, muss er also vom vbisherigen 16*32 
wieder abziehen, damit die Rechnung ergibt, dass das Zeichen mit dem 
Code 32 an der Position 0 in der Tabelle anfängt, das mit dem Code 33 an 
der Position 16, das mit dem Code 34 an der Position 32, das mit Code 35 
an der Position 48, usw. usw.

Und zu guter leztzt zählt er in dieser c-Zeile noch 8 dazu
1
font_pos=(data*pgm_read_byte(font + 7))-(pgm_read_byte(font + 2)*pgm_read_byte(font + 7))+8;
im Kommentar steht da lapidar: wegen der Header Größe.
Nun die Header-Größe, das ist nichts anderes als die Font-Beschreibung 
in der ersten Zeile. Und das sind 8 Bytes. Stimmt auffallend überein.

Damit ist die Zeile
1
font_pos=(data*pgm_read_byte(font + 7))-(pgm_read_byte(font + 2)*pgm_read_byte(font + 7))+8;
komplett analysiert. Wir wissen was da passiert und warum es passiert 
und wie der Zusammenhang zu
1
const unsigned char font_8X16[font_8X16_LEN] PROGMEM =
2
{
3
  70, 86, 32,255,  8, 16,  2, 16,
aussieht. 2 dieser 8 Angaben können wir bereits deuten. Die 8 die da in 
den Daten vorkommt, die können wir auch einfach mal raten. Da der Font 
ein 8 mal 16 Font ist, wird wohl diese 8 für die Breite (oder Höhe) 
eines Zeichens stehen. Mit deinem 2.ten Font kannst du das ja mal 
kontrollieren.

Aber wie sind die Zeichen aufgebaut.
Nehmen wir das Zeichen mit dem Code 33. Das ist laut ASCII Tabelle ein 
!. Da wir die Indexberechnung ins Array nachvollziehen können, wissen 
wir auch das diese Bytes
1
const unsigned char font_8X16[font_8X16_LEN] PROGMEM =
2
{
3
  70, 86, 32,255,  8, 16,  2, 16,
4
  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
5
  0,  0,  0,252,252,  0,  0,  0,  0,  0,  0, 51, 51,  0,  0,  0,    <--- die hier
wohl irgendwie ein Rufzeichen beschreiben.
Wie gesagt: Dezimal ist hier komplett dämlich, denn hier geht es um 
Pixel. Und wenn wir mal davon ausgehen, dass 1 Pixel eine Entsprechung 
zu einem Bit haben wird, dann muss man diese Zahlen
1
  0,  0,  0,252,252,  0,  0,  0,  0,  0,  0, 51, 51,  0,  0,  0,
in ihrer Bitdarstellung sehen. Mit Hex wäre das leichter umzusetzen, 
aber mit einem Taschenrechner gehts auch so. Lass uns die 16 Zahlen mal 
in ihrer Bitdarstellung ansehen
1
0               00000000
2
0               00000000
3
0               00000000
4
252             11111100
5
252             11111100
6
0               00000000
7
0               00000000
8
0               00000000
9
0               00000000
10
0               00000000
11
0               00000000
12
51              00110011
13
51              00110011
14
0               00000000
15
0               00000000
16
0               00000000

hmm. auf den ersten Blick ist da jetzt noch kein Rufzeichen erkennbar. 
Oder doch? Auffällig ist, dass es da 2 Blöcke gibt. Lass uns die mal 
nebeneinander setzen
1
         00000000   00000000
2
         00000000   00000000
3
         00000000   00000000
4
         00110011   11111100
5
         00110011   11111100
6
         00000000   00000000
7
         00000000   00000000
8
         00000000   00000000

Doch. Ja. Wenn ich den Kopf 90° nach rechts zur Seite drehe, dann kann 
ich da schon ein Rufzeichen erkennen. Der Punkt, das ist der 2 mal 2 
Blick aus 1-sen im linken Block und der Strich geht über die Lücke in 
den Block rechts rein.

Das ist doch schon mal eine Spur. Mal sehen. Ob das woanders auch 
funktioniert.
Ein 'A' hat den ASCII Code 65 dezimal. Mal in die Formel eingesetzt
(65 * 16) - ( 32 * 16 ) + 8
ergibt  536

Im Datenarray mal das Byte an der Stelle 536 suchen.
Das ist die Zeile hier
1
  0,240,248, 28, 28,248,240,  0,  0, 63, 63,  3,  3, 63, 63,  0,
wenn alles klappt, dann müssten wir auf ganz ähnliche Weise ein 'A' 
hervorzaubern können. Also wieder: die Zahlen binär anschreiben
1
0            00000000
2
240          11110000
3
248          11111000
4
28           00011100
5
28           00011100
6
248          11111000
7
240          11110000
8
0            00000000
9
0            00000000
10
63           00111111
11
63           00111111
12
3            00000011
13
3            00000011
14
63           00111111
15
63           00111111
16
0            00000000
der nächste Schritt war, die 16 Zeilen in 2 8-er Blöcke zu zerteilen und 
den unteren Block links vom oberen Block anzuschreiben
1
         00000000  00000000
2
         00111111  11110000
3
         00111111  11111000
4
         00000011  00011100
5
         00000011  00011100
6
         00111111  11111000
7
         00111111  11110000
8
         00000000  00000000

ja, doch. Den Kopf um 90° drehen und ich kann da ein 'A' erkennen. die 
beiden senkrechten, oben die Verbindung und in der Mitte (ganz rechts im 
linken Block) der Querstrich. So
1
           111111  1111
2
           111111  11111 
3
               11     111
4
               11     111
5
           111111  11111
6
           111111  1111

sieht man es noch besser.

Ich denke, damit ist klar, wie der Aufbau der Fontdaten ist.
Zumindest in diesem Beispiel mit den 16 Bytes pro Zeichen. Das sind 2 
Blöcke zu je 8 Bit. Wobei interessanterweise ja auch hier im Header
1
const unsigned char font_8X16[font_8X16_LEN] PROGMEM =
2
{
3
  70, 86, 32,255,  8, 16,  2, 16,

eine 2 vorgekommen ist. Unmittelbar vor der 16, welche ja die Anzahl der 
Bytes pro Zeichen angegeben hat.


Ich denke, du siehst schon, wie man sowas angeht. Jetzt liegt es eben an 
dir, dir die Fontdaten, die du gefunden hast dir auch mal näher 
anzusehen. Entweder man kann die relativ einfach in diese Form hier 
unwandeln, oder aber, wenn das gar nicht geht, dann schreibt man eben 
wieder eine neue Ausgaberoutine. Aber die Anpassung wäre eigentlich 
vernünftiger. Die kann ja auch ein PC-Programm machen.
Hat man den Aufbau der Fontdaten (egal welche) dann erst mal verstanden, 
kann man auf dem Papier nachvollziehen, wie sich daraus letzten Endes 
die schwarzen bzw. weissen Pixel ergeben, dann ist es auch nicht weiter 
schwer, den zugehörigen C-Code zu lesen. Denn der muss ja dann nichts 
weiter tun, als diese Daten in eine Form bringen, wie sie das LCD haben 
will. Dazu muss man natürlich jetzt wieder wissen, wie das LCD seine 
Angaben haben will. Malt dieses ein Byte (also 8 Bit) als eine Spalte 
hin (mit hellen bzw. dunklen Pixeln) oder malt es das als 8 
nebeneinander liegende Pixel hin (also quasi in einer Zeile).

Aber sich hinstellen und 'helft mir' rufen - das ist zu wenig. Ein 
bischen was musst du schon auch selbst tun. So ist das nun mal, wenn man 
programmieren will.

von Th. B. (thbaum)


Lesenswert?

Hallo Thorsten,

ohne Code von dem neuen Font ist das zwar alles nur geraten aber vll 
hilft es weiter. In deinem Beispiel haben die Schriftarten an Pos 0 ein 
paar Einstellungen zum Array

unsigned int font_pos=0; //postion of data within the font array

Prüfe mal ob der neue Font dazu kompatibel ist. Ich habe jetzt nicht 
überprüft ob dein Code mit Fonts umgehen kann die als Höhe kein 
Vielfaches von 8 sind.

Möglich ist auch, dass die Bytedarstellung (Mapping Bit->Pixel) auf dem 
LCD des neuen Fonts eine andere ist.

Gruß Thomas

von OldMan (Gast)


Angehängte Dateien:

Lesenswert?

Hallo Thorsten,

habe mal die Routinen und ein Font dazu angehängt.
Vielleicht hilft Dir das weiter.
Der Code ist gut kommentiert.

von Thorsten (Gast)


Angehängte Dateien:

Lesenswert?

Hallo,

auch wenn ich nun weiß, dass die neue Schrift nicht zu meinem Format 
passt hänge ich sie mal an.

Vielen Dank schonmal. Ich muss mir das mal zu Gemüte führen und sehen, 
dass ich meine Schrift entsprechend angepasst bekomme. Vielleicht gibt 
es ja auch einen entsprechenden FontGenerator oder so.

Grüße

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.