Forum: Mikrocontroller und Digitale Elektronik Wie macht ihr das mit GLCD und Fonts


von Martin R (Gast)


Lesenswert?

Hallo

Habe ein 128x128 GLCD Optrex und habe horizontal 8 Bit zu besetzten
vertikal habe ich 1 bit.

Ich benutze Fontgenertor und er macht mir für jeden einzelnen
Buchstaben und Zahl ein Hexcode draus.

den übertrage ich ans Display geht auch nur ein Problem sind die
Horizontalen Abstände, diese kommen durch die 8bit breite =8 punkte
horizontal.je nach größe der Fonts kommen auch 16Bit vor. dann wird der
abstand immer größer.

Wie würdet Ihr fonts mit variablen text ans display übertragen ohne das
Problem des Horizontalen abstands zu haben???

Gruß

Ich benutze C

von Hagen (Gast)


Lesenswert?

In meiner GLCD habe ich das so gelösst:

1.) Fonts sind Spaltenweise codiert, also die Bitdaten stellen
senkrecht die Spalten eines Zeichens dar.Das macht aber keinen
Unterschied und man kann dies auch horiziontal codieren.

2.) die Bits eines Zeichens sind sequientiell im Font codiert. Egal ob
ein Zeichen nun 5 Bit oder 11 Bit breit ist, es sind immer 5 oder 11
Bits pro Zeile eines Zeichens codiert.

3.) das bedingt also das im Font irgendwo, am besten im Header, klar
definiert wurde wie breit ein Zeichen in Bits/Pixeln nun tatsächlich
ist. Ich habe dazu im Font zwei wichtige Werte
a) die maximale Fontbreite/höhe in Pixel um Fixed Fonts zeichnen zu
können
b) eine Tabelle zu allen im Font gespeicherten Zeichen mit deren Pixel
=Bitbreite.

4.) die Zeichenhöhe ist pro Font für alle Zeichen gleich.

Die eigentlichen Fontdaten sind nun ganz einfach gespeichert.
Angenommen ein 12x15 Pixelfont:

- Zeichenhöhe 15 Pixel im Header
- maximale größe eines Zeichens ist 12x15 Pixel, ergibt 12x15 = 180Bits
= (180 + 7) / 8 = 23 Bytes.
- ein 9x15 Pixel Zeichen in diesem Font speichert in der
Zeichenbreitentabelle also eine 9. Es belegt in den Daten (9x15 + 7) /
8 = 17 Bytes am Stück.

Um nun einen Zeiger beginnend von den Zeichendaten auf das gesuchte
Zeichen zu positionieren macht man folgendes:

Lade sequientiell jede Zeichenbreite aus der Zeichnbreitentabelle bis
zum Zeichen X -1, wobei X das zu zeichnende Zeichen ist.
Rechne DataPointer = DataPointer + (Zeichenbreite[i] * Zeichenhöhe + 7)
/ 8, wobei Datapointer am Anfang dieser Schleife auf das erste byte der
Zeichendaten zeigt.

Am ende der Schleife zeigt DataPointer also exakt aufdas 1. Bit des
gesuchten Zeichens. Nun wird Byteweise eine 16 Bit breite Variable mit
den Datengefüllt. Das befüllen erfolgt dabei immer in Schüben a 8 Bit.
Das entnehmen der Daten aus dieser Variable erfolgt aber immer mit
Zeichenbreite Bits. bei einem 12x15 Zeichen also maximal mit 12 Bits.
Da aber der LCD Datenstrom aus Bytes besteht entnimmt man normalerweise
nur bis zu 8 Bits.

Dies hört sich im ersten Moment ziemlich ineffizient an, ist es aber
garnicht. Man kann dies sehr gut auf die MCU hin optimieren und die
wenigen Schleifen entschädigen dafür dann bei der besseren Datendichte
pro zeichen. Man spart also eine Menge Speicher für den Font.

In meiner GLCD habe ich noch zusätzlich eine Komprimierung eingebaut
die quasi eine RLE Codirung mit Mini-Fuffman ist. Das bringt bei großen
Fonts minimal 50% bis zu 200% Speichereinsparung. Und der Witz dabei ist
das die Zeichenroutine, obwohl sie komplexer ist, denoch schneller
zeichnet als bei unkomprimierten Fonts. Dies liegt daran das man
weniger Daten aus dem FLASH etc.pp. nachladen muß pro Pixel den man
zeichnen muß.

Am besten einfach mal hier in der CodeLib nach Nokia 6100GLCD suchen.

Gruß Hagen

von Peter D. (peda)


Lesenswert?

Ich habe nur einen Zeichensatz 5*7, d.h. 5 Byte pro Zeichen. Die
wirklich benötigten Spalten haben das 8. Bit gesetzt.


Peter

von Hagen (Gast)


Lesenswert?

Quatsch, was ich erzähle da:

DieZeichendaten sind OHNE Bitlücken sequientiell gespeichert. D.h. wenn
das erste Zeichen eines 12x15 Pixelfonts 9 Pixel Breite hat und das
zweite Zeichen 11 Pixel dann sieht das in den Daten so aus. Zuerst
kommen 12x15 Bits für Zeichen #1 und dann sofort 9x15 Bits für Zeichen
#2 und dann 7x15 Bits für Zeichen #3.
In der Breitentabelle steht drinnen 9,11,7.
Wenn wir Zeichen #3 zeichnen wollen dann so:

BitOffset = 0;
for (i=0; i < gesuchtes Zeichen - erstes Zeichen; i++) {
  BitOffset += Font.Zeichenbreite[i] * Font.Zeichenhöhe;
}

nun steht in BitOffset als das 1. Bit an dem Zeichen #3 beginnt. Wir
errechnen nun den Byte Zeiger auf die ersten Bitdaten für Zeichen #3.

ByteDataPointer = &Font.PixelData + BitOffset / 8;
BitOffset = BitOffset % 8;

In BitOffset steht jetzt der Rest <= 7 Bits drinnen der noch vom
Zeichen #2 drinnen steht.

BitData = *ByteDataPointer++;
BitData = BitData << 8;
BitData = BitData | *ByteDataPointer++;

Nun stehen in BitData die ersten 16 - BitOffset Bits des Zeichens #3
drinnen und noch BitOffset Bits aus dem Zeichen #2, die schieben wir
einfach raus:

BitData = BitData << BitOffset;

Nun steht in den obersten 8 Bits von BitData die ersten 8 Bits vom
Zeichen #3 und können an das LCD gesendet werden.

Man lädt jetzt succesive in BitData mit *ByteDataOffset++; die nächsten
8 Bits nach wenn die untersten 8 Bits von BitData rausgeschoben wurden.
Mit Hilfe der Zeichenbreite für Zeichen #3 weiß man auch ab wann man in
die nächste Pixelzeile springen muß.


Gruß Hagen

von Hagen (Gast)


Lesenswert?

@Peter:

das ist ja auch nicht verwerflich ;) wenn man esnur einfach benötigt.

Ich gehe aber davon aus das der Fragesteller seinen Zeichensatz als
proportionalle Schrift darstellen möchte, d.h. jedes Zeichen kann
unterschiedlich breit sein und die Abstände zwischen den Zeichen soll
dementsprechend auch immer gleichgroß zb. 1 Pixel sein.
Bei einem Fixed Font wäre das aber nicht möglich.

Meine obige Erklärung bezieht sich exakt auf meine Erfahrungen wie ich
dies in meiner GLCD gelösst habe.

Hinzukam aber noch die Erschwernis das ich auch farbige Fonts in der
gleichen Datenstruktur speichern wollte und mit der gleichen
Zeichroutine auch zeichnen wollte. D.h. mit obiger Methode eines
sequientiell gepackten Bitstreams sind:

- Farbfonts mit variabler Bittiefe möglich, also 1 Bit Monorchrom, 2Bit
= 4 Farben, 3 Bit == 8 Farben usw,
- die Daten aufs minimale gepackt da keinerlei Leerbits entstehen
- die daten rein sequietiell ohne Repositioniereungen ladbar, also
optimiert für serielle Speicher
- der Font ist eine proportionale Schrift die aber sehr wohl immeer
noch als fixed Schrift gezeichnet werden kann. Dazu einfach die
fehldenen Bits von fixed Pixelbreite - Zeichenbreite mit Nullen
auffüllen.
- eine RLE Komprimierung ist enthalten.

Gruß Hagen

von Peter D. (peda)


Lesenswert?

"Ich gehe aber davon aus das der Fragesteller seinen Zeichensatz als
proportionalle Schrift darstellen möchte"


Ich doch auch:

Werden alle 5 Spalten benötigt, enthalten 5*7 Bits den Code und alle 5
8. Bits sind gesetzt. Werden weniger Spalten benötigt, sind die
überzähligen Bytes 0.

Ich multipliziere lieber einmal mit 5, als jedesmal sämtliche Zeichen
erst durchzählen zu müssen.

Müßte zuerst ja lustig sein, wenn eine Laufschrift mal schneller, mal
langsamer ist, je nachdem, wie weit hinten die Zeichen in der
Zeichentabelle stehen (auf die Dauer würde es aber nerven).


Peter

von Hagen (Gast)


Lesenswert?

@Peter:

der Overhead zur Positionierung der Daten kann meiner Meinung nach
vernachlässigt werden. Das zeigte sich ja auch im Praktischen bei
meiner GLCD. Bisher hat sich noch keiner der Nutzer darüber beschwert.

Im Gegensatz steigt aber der Speicheraufwand, bzw. die
Speicherverschwendung dramatisch an wenn man einen proportionalen Font
mit fester Bitbreite abspeichert.

Bei größeren Fonts mit sehr unterschiedlichen Zeichenbreiten, zb. das i
mit 3 Pixeln das M aber mit 13 Pixeln bei einem 13x15 Pixelfont, macht
sich eine ineffiziente Codierung sehr wohl im Speiocherverbrauch
bemerkbar.

Dies multipliziert sich dann auch noch mit der benutzten Farbtiefe,
falls man nicht nur monochrom darstellen möchte.

Alleine das bringt bei einem 4 Farben 9x12 Font schon 50% weniger
Speicherverbrauch.

Zusätzlich kommt noch der Fakt das man wenn man Hardware SPI benutzt eh
16 MCU Takte warten muß bis die Daten raus sind. Diese 16 Takte reichen
vollkommen aus um quasi schon im Hintergrund die nächsten Daten zu
laden und zu Bitshiften.

In meiner GLCD mache ich zb. in diesen 16 Takten das komplette Laden
der nächsten Daten, die Dekodierung der RLE Komprimierung, die
Umwandlung dieser Daten in die reale Farbtabelle und noch das
Pixelgenaue Clipping der Anzeige. Durch die RLE Komprimierung ergibnt
sich aber ein Ratio von 0.5 bis runter auf 0.1 beim Laden der nächsten
Bits. D.h. je mehr succesive Bits im Zeichen die gleiche Farbe haben um
so weniger muß der Dekodierer real neue Daten nachladen. Logisch, er
dekodiert nur einmalig die Information "zeichne jetzt 16 Pixel in
Frabe rot". Das wären schon 32 Bits an Information also unkomprimiert
4 Bytes die man nachladen müsste, meistens aus langsammeren
Speichernedien,

Gruß Hagen

von Hagen (Gast)


Lesenswert?

Ach übrigens hat das noch anderer Vorteile:

Man möchte zb. einen String wie "-0.1234 mA" rechtsbündig ausgeben.
Dazu muß man aber aber erstmal die linke X Position dieses Strings
berechnen, wenn man nich von rechts nach links zeichnen möchte oder
kann.

Um nun die Breite dieses Strings ausrechnen zu können benötigt man die
Pixelbreite für jedes Zeichen. In meiner Font Struktur sind diese ja
als Tabelle im Header gespeichert.

Je nachdem ob man nun die Zeichenroutine für Fixed oder Proportional
eingestellt hat gibt es zwei Arten dieser Berechnung:

1.) fixed Fonts = Stringlänge * (Font.Zeichenbreite +1).
2.) proportionale Fonts = für jedes Zeichen im String addiere
Font.Breitentabelle[Zeichen] +1.

Bei Peters Speichermethode wäre dies nicht möglich ohne die realen
Fontdaten separat zu laden und zu analysieren, mal abgesehen vom
höheren Speicherverbrauch.


Gruß Hagen

von Martin R (Gast)


Lesenswert?

Hallo

Also ich blicke da nicht durch.

Mein Optrix mit 1SED 1335 macht 8bit breite wenn ich an Adresse 0x0000
schreibe 11111111=0xff dann zeigt das Display  einen Strich von 8
punkten.

wenn ich ein L Schreibe
                0x00, 0x00,   /*  [           ]  */
    0x30, 0x00,   /*  [  **       ]  */
    0x30, 0x00,   /*  [  **       ]  */
    0x30, 0x00,   /*  [  **       ]  */
    0x30, 0x00,   /*  [  **       ]  */
    0x30, 0x00,   /*  [  **       ]  */
    0x30, 0x00,   /*  [  **       ]  */
    0x30, 0x00,   /*  [  **       ]  */
    0x30, 0x00,   /*  [  **       ]  */
    0x30, 0x00,   /*  [  **       ]  */
    0x30, 0x00,   /*  [  **       ]  */
    0x30, 0x00,   /*  [  **       ]  */
    0x3F, 0xC0,   /*  [  ******** ]  */
    0x00,0x00,   /*  [           ]  */

habe ich 6 punkte leerraum und besetzte 16 bit also 16 punkte es werden
aber nur 10 genutzt wenn ich ein zweites L Schreibe dann beginnt es ab
17 stelle ich kann es nicht an 12 stelle schreiben weil der
speicherzugriff auf 8bit breite läuft

startadresse 0x000 schreibe 0xff adresse 0x001 schreibe 0xff =
................

ich kann nicht einfach an position X=2 springen geht nicht nur immer an
1,8,16..128

einfach wäre es wenn man sich ein bild erstellen könnte bitmap und es
einließt das die anzuzeigenden werte beinhaltet müsste natürlich
realtime aus den ergebnissen generiert werden.

Ich verzweifle ich muß mir anscheinend ein anderes display kaufen wo
ich  punkt weise ansprechen kann x und y achse.


Danke

von Hagen (Gast)


Lesenswert?

Jetzt wird dein eigentliches Problem klarer.

Du hast auf Grund des Displays keinen wahlfreien Zugriff auf das
DisplayRAM. Ich kenne dein Display leider nicht, aber schaue mal im
Datenblatt ob du die 8 Pixel die du verändern möchstes wieder aus dem
Display auslesen kannst. Wenn ja dann musst du per Bit Maskenbeide
Bytes -> die neuen Bits und die im DisplayRAM miteinander verknüpfen
und dann zurückspeichern.

Gruß Hagen

von Jörg B. (joerg_b)


Lesenswert?

Das Display von Martin R ist ein Optrex DMF5008 mit SED1335 Controller.


Ich habe es auch und bin auch am überlegen wie ich nen Zeichensatz
völlig frei positionieren kann.

von Olaf (Gast)


Lesenswert?

Bist du sicher das du da nicht falsch liegst? Der SED1335 ist ja ein
ziemlich leistungsfaehiges Teil. Den habe ich bisher nur an groesseren
Displays gesehen, aber nicht an einem kleinen 128x128er.

Ich hab den allerdings schon programmiert und soweit ich mich erinnere
kann er die Zeichen nicht pixelweise dimensionieren wenn man den
eingebauten Zeichensatz benutzt. Ich hab deshalb damals mit einem
eigenen Zeichensatz gearbeitet und die Pixel persoenlich gesetzt.
Ausserdem sah der eingebaute Zeichensatz auch ziemlich aermlich aus und
zwar wegen der Luecke zwischen zwei Zeichen. Im Textmode hinterlaesst
das Dingen wirklich nur den Eindruck eines billigen Textdisplays.

Olaf

von Jörg B. (joerg_b)


Lesenswert?

Laut Datenblatt zum GLCD ist es ein SED1335 und verbaut ist ein SED1330
(also kompatibel).

Ärmlich trift es ziemlich gut ... vorallem wenn man mit 8bit
Zeichenbreite arbeitet um im Grafiklayer nicht zuuuu viel rechnen zu
müssen.

Ich habe vor beliebige Fonts mit variablen Breiten völlig frei zu
positionieren. Da geht eh nix mehr mit dem internen Zeichengenerator.

Jörg

von Olaf (Gast)


Lesenswert?

Vielleicht wird es dich dann interessieren das 1330/1335 wegen ROHS
abgekuendigt sind? Es gibt wohl ein Nachfolgemodel der auch
'irgendwie' kompatible ist. Allerdings habe ich den noch nicht
begrabbelt.

Olaf

von Martin R (Gast)


Lesenswert?

Hallo

Ja so siehts aus ziemlich ärmlich.

ich habe mir gedanken gemacht und bin gerade dabei mir einen
Lückencleaner zu programmieren.


teile die hexzahlen auf in 4bit breite 2*4=8.
und lese immer nur die letzten 4 bit aus und rechne von hex in binär


so habe ich zum bsp

11100000 und vergleiche diese werte auf die font höhe.


    0x00, 0x00,   /*  [           ]  */   00000000
    0x30, 0x00,   /*  [  **       ]  */   00000000
    0x30, 0x00,   /*  [  **       ]  */   00000000
    0x30, 0x00,   /*  [  **       ]  */   00000000
    0x30, 0x00,   /*  [  **       ]  */   00000000
    0x30, 0x00,   /*  [  **       ]  */   00000000
    0x30, 0x00,   /*  [  **       ]  */   00000000
    0x30, 0x00,   /*  [  **       ]  */   00000000
    0x30, 0x00,   /*  [  **       ]  */   00000000
    0x30, 0x00,   /*  [  **       ]  */   00000000
    0x30, 0x00,   /*  [  **       ]  */   00000000
    0x30, 0x00,   /*  [  **       ]  */   00000000
    0x3F, 0xC0,   /*  [  ******** ]  */   11000000
    0x00,0x00,   /*  [           ]  */    00000000


man kann sehen die lücke ist 6 bit breit einfach zu viel.
ich lese jetzt vertikal und wenn alles vertikal 0 ist dann muß dies
weg(ich lasse 2 bit als lücke).

also muß ich 4 bit wegnehmen für die 4 bit setzte ich den nächsten
buchstaben oder zahl dran und dort mache ich das gleiche ich nehme den
abstand weg.

am ende hat man ein muster als wenn ich das display mit einem bitmap
fülle dabei bin ich auf dei idee gekommen haeb mir mit dem Font den ich
benutzetn will in paint ein 128x128 pix bitmap erstellt und mit
fontgenerator das hex array generieren lassen und dort ist der abstand

2 pix groß was auf dem display perfekt aussieht so wie ich es haben
will.

ich denke das ist die einzige möglichkeit für das diesplay schön wäre
es wenn man frei zu greifen könnte.

Gruß

Martin.

Es ist ein Optrex DMF 5008 von Pollin 2,95€ echt preiswert und sieht
gut aus mit Hintergrundbeleuchtung leider ist der W50 Inverter ein
bischen laut kostet 3,65 für Business Kunden.

von Peter K. (klaus77)


Lesenswert?

Hallo Martin,

ich bekomme mein Display Optrex 5008 nicht zum Fliegen. Ich sehe nur
zwei Striche beim Reset und dann nichts mehr.

Könntest Du vielleicht Deinen Code posten ?

Ich habe schon viel mit dem Init probiert, aber es läuft nix. Auch die
Hardware habe ich schon zweimal zusammengelötet...

Gruß,
Peter

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.