Forum: Mikrocontroller und Digitale Elektronik Wie programmiert man Grafiken "richtig" in C


von Attila C. (attila)


Lesenswert?

Ich hab hier eine LED Matrix die Zeichen darstellen soll. Ich würde 
jetzt für jeden Buchstaben eine Funktion schreiben und als Parameter 
eine x/y Koordinate und vielleicht einen RGB Wert übergeben.
Macht man das so?
Und was ist denn wenn man es mit einem Display zu tun hat? "Beschreibt" 
man jedes Pixel einzeln mit xy, Helligkeit und Farbe? Jedes mal einzeln 
für jeden vorkommenden Fall?

von c-hater (Gast)


Lesenswert?

Attila C. schrieb:

> Ich hab hier eine LED Matrix die Zeichen darstellen soll. Ich würde
> jetzt für jeden Buchstaben eine Funktion schreiben und als Parameter
> eine x/y Koordinate und vielleicht einen RGB Wert übergeben.
> Macht man das so?

Eher nicht. Üblich wäre vielmehr ein Satz "Kontextfunktionen", also 
z.B.: setze Position, setze Farbe, ggf. zusätzlich: setze Schriftart, 
setze Schriftschnitt, setze Schriftrichtung usw. usf.

Und dann eine Funktion zur eigentlichen Zeichenausgabe, die als 
Parameter das auzugebende Zeichen bekommt. Alles andere an Information 
bezieht sie aus dem Kontext, den man natürlich ebenfalls übergeben muss, 
allerdings nicht notwendigerweise als Parameter, der Kontext kann u.U. 
auch global sein.

Die Zeichenausgabefunktion malt dann den richtigen Glyph in der 
korrekten Orientierung an die korrekte Stelle und inkrementiert 
typischerweise die Zeichenausgabeposition entsprechend Zeichengröße und 
Ausgaberichtung.

Der Sinn dieser Konstruktion ist, dass man typisch halt Text ausgibt, 
der aus mehr als einem Zeichen besteht.

> Und was ist denn wenn man es mit einem Display zu tun hat? "Beschreibt"
> man jedes Pixel einzeln mit xy, Helligkeit und Farbe? Jedes mal einzeln
> für jeden vorkommenden Fall?

Das hängt dann vom Treiber für das Ausgabegerät ab. Im Minimum stellt 
das eine SetPixel(X,Y,Farbe) zur Verfügung. Bei komplexeren 
Grafiksystemen gibt es aber auch oft Beschleunigungsfeatures, so dass 
die Routine zur Zeichenausgabe nicht jedes einzelne Pixel eines Zeichens 
setzen muss. Aber das überfliegt deinen Horizont wohl noch deutlich. 
Bleib' erstmal bei der Sache, die auf SetPixel() basiert. Da gibt es 
schon genug zu lernen.

von Rainer V. (a_zip)


Lesenswert?

c-hater schrieb:
> Bleib' erstmal bei der Sache, die auf SetPixel() basiert. Da gibt es
> schon genug zu lernen.

Ja, aber so wird er ganz bestimmt keinen "Zeichensatz" hinkriegen...na 
ja, vielleicht ala 7-Segment-Anzeige...aber darauf zielt die Frage doch 
nicht ab.

Attila C. schrieb:
> "Beschreibt"
> man jedes Pixel einzeln mit xy, Helligkeit und Farbe? Jedes mal einzeln
> für jeden vorkommenden Fall?

Ja und nein. Ja, du hast im einfachsten Fall eine Tabelle mit den 
Eigenschaften eines Pixel (falls das das kleinste darstellbare Element 
ist) und baust daraus dann z.B. den Buchstaben "a" wiederum in einer 
Tabelle mit allen deinen Zeichen (oder mit allen möglichen Zeichen). 
Dann brauchst du noch die Zuordnung zu Koordinaten auf deinem 
Anzeigefeld und dann bist du erst mal fertig. Nein, weil eben der 
tabellarische Aufbau eine beliebige aktuelle Tabelle ermöglicht, die 
deine aktuell gewünschte Anzeige beschreibt. Wenn du ein wenig suchst, 
wirst du schnell herausfinden, dass das insgesamt eine gehörig komplexe 
Materie ist...
Viel Spass trotzdem, Rainer

von c-hater (Gast)


Lesenswert?

Rainer V. schrieb:

> Ja, aber so wird er ganz bestimmt keinen "Zeichensatz" hinkriegen...

Wieso nicht? Natürlich kann man basierend auf einer SetPixel-Funktion 
jeden beliebigen Zeichensatz darstellen, sogar einen Vector-Zeichensatz 
(der mit Pixeln naturgemäß eigentlich garnix am Hut hat).

von MaWin (Gast)


Lesenswert?

Attila C. schrieb:
> Macht man das so

Nein.

Man speichert einen font, also die Pixelbilder aller druckbarer Zeichen, 
und schreibt eine Funktion die das n-te Zeichen aus dem font an Position 
x,y klatscht.

Falls es wirklich ein LED moving sign ist, spart man sich sogar den 
Speicher für die Pixel und holt die bits bei jedem Multiplexdurchgang 
aus dem font, speichert also nur den darzustellenden String und dessen 
Anfangspixelposition, denn Fontzugriff ist schnell.

von Irgend W. (Firma: egal) (irgendwer)


Lesenswert?

Attila C. schrieb:
> ch würde
> jetzt für jeden Buchstaben eine Funktion schreiben und als Parameter
> eine x/y Koordinate und vielleicht einen RGB Wert übergeben.
> Macht man das so?

Nö, man baut eine Funktion der man das Zeichen, die position und ggf. 
die Farbe übergibt.
Diese holt dann aus einer Tabelle, in der alle benötigten Zeichen 
abgelegt sind, dass betreffende Zeichen und kopiert das an die passende 
Position in deinem Ausgabe-Puffer.

https://de.wikipedia.org/wiki/Bitmap-Schrift

von Das Huhn (Gast)


Lesenswert?


von Rolf M. (rmagnus)


Lesenswert?

MaWin schrieb:
> Man speichert einen font, also die Pixelbilder aller druckbarer Zeichen,
> und schreibt eine Funktion die das n-te Zeichen aus dem font an Position
> x,y klatscht.

Ergänzend: Mit "klatscht" ist hier gemeint, dass die Pixel des Zeichens 
an die Zielposition im Bidspeicher kopiert werden.

von Adam P. (adamap)


Lesenswert?

Die einen sagen "genau so" muss das gemacht werden, die anderen 
antworten "nööö, so macht man das nicht"... ich würde da einfach mal 
sagen:
Es kommt drauf an wie man etwas ansteuert, wie sehr man es abstrahieren 
möchte und ob man Performance braucht/möchte.

LED Matrix wirst du wohl multiplexen?
Oder nutzt du eine WS2812B LED Matrix, da du von Farbe gesprochen hast?

Kleines Bsp. von meinem OLED (SPI Interface):
Natürlich könnte man dort je Befehl ein Pixel einzeln setzen, was jedoch 
von der Verarbeitung mehr Zeit in Anspruch nehmen würde.

Ich nutze dort das Farbformat RGB565 welches über SPI übertragen wird, 
somit entspricht ein Pixel 2 Byte (Farbinformation).
Für 160x128 Pixel habe ich mir ein Framebuffer angelegt
1
/* RGB565 Format */
2
#define BYTE_PER_PIXEL   2
3
4
#define FB_PIXEL_CNT     (OLED_WIDTH*OLED_HEIGHT)
5
#define FB_SIZE          (OLED_WIDTH*OLED_HEIGHT*BYTE_PER_PIXEL)
6
7
static uint8_t fb[FB_SIZE];

Um mir jetzt für eine Schriftart nicht jedes Pixel einzeln zu Pixeln 
habe ich folgendes Tool benutzt:

http://www.eran.io/the-dot-factory-an-lcd-font-and-image-generator/

Natürlich musst du dir da noch die Funktionen schreiben, die dir dann 
die richtigen Pixel im Buffer setzen oder direkt übertragen/ansteuern.

Ob du nun ein Buffer nutzt oder nicht, wäre der grobe Aufbau z.B. so:
1
led_str(const char *str, uint8_t x, uint8_t y, uint32_t color)
2
   |
3
   |-> led_char(char c, uint8_t x, uint8_t y, uint32_t color)
4
          |
5
          |-> led_pixel(uint8_t *dst, uint32_t color)

Bei led_pixel() zeigt der *dst auf mein Buffer, da die Position im 
Buffer in led_char() berechnet wird. Ein Zeichen besteht ja aus mehreren 
Pixeln :)

Es gibt für verschiedene Aufgabenstellungen auch mehrere Lösungen, da 
muss man einfach selbst abwägen, was für diesen Fall angebracht ist.
Meistens bestimmen die Anforderungen den Lösungsweg.

Aber für eine WS2812B Matrix, würde ich mir wohl auch ein Buffer anlegen 
und dann erst alles im RAM zusammenbastlen und anschliessend 
heraustakten.

Bei der Erstellung von Display Funktionen bin ich immer gut mit dem 
Bottom-up-Prinzip gefahren.

: Bearbeitet durch User
von Peter D. (peda)


Lesenswert?

Attila C. schrieb:
> Ich würde
> jetzt für jeden Buchstaben eine Funktion schreiben

Das ist Quatsch mit Soße. Man schreibt nur eine einzige Funktion, der 
man den Index auf den entsprechenden Eintrag in der Zeichensatztabelle 
übergibt.
Je nach Schriftgröße hat man mehrere Tabellen.
Für den ersten Test nimmt man Putpixel. Und wenn das funktioniert, kann 
man optimierte Funktionen schreiben.
Es kann auch sinnvoll sein, alles erstmal in den RAM zu schreiben und 
dann den RAM in einem Rutsch in das Display zu kopieren.

von A. S. (Gast)


Lesenswert?

> Und was ist denn wenn man es mit einem Display zu tun hat? "Beschreibt"
> man jedes Pixel einzeln mit xy, Helligkeit und Farbe? Jedes mal einzeln
> für jeden vorkommenden Fall?

Verschiedene Displays haben verschiedene Ansteuerungen. Bei manchen 24 
Bit Farbe pro Pixel, bei anderen beschreiben je 1 Byte 8 Pixel an oder 
aus.

Die einfachste Schnittstelle ist jedoch noch immer SetPixel(x, y, 
pixel). Wobei x und y die Koordinaten sind (oft von oben links, aber 
alles ist möglich) und pixel halt 0/1 oder 3 Byte für rgb oder was auch 
immer.


Wenn Du ein Pixel setzen kannst, kannst Du alle setzen.

Das ist die einfachste Schnittstelle zwischen der HW (dem physikalischen 
Display, welche Kommandos oder Pins du brauchst) und einem Grafikpaket 
(dass Fonts enthält und kommandos zum Zeichnen von Kreisen oder 
Rechtecken.

Wenn es dann auf Performance ankommt, dann kannst Du immer noch 
optimieren, aber für einen Anfänger ist es einfacher, über SetPixel zu 
gehen.

von Adam P. (adamap)


Lesenswert?

Na, vielleicht meldet sich der TO ja auch noch einmal zu Wort,
so dass wir evtl. mehr Informationen zu seiner Hardware bekommen.

Sollte er WS2812B LED nutzen, dann wäre der Aufwand gar nicht so groß, 
seine Matrix wie ein Display zu nutzen, ist ja in dem Sinne nichts 
anderes.
(Abgesehen von der Ansteuerung)

Bin gespannt...

von Rainer V. (a_zip)


Lesenswert?

Eigentlich hat der TO ja zwei Fragen gestellt. Da er seine LED Matrix 
nicht näher bezeichnet hat, ist eigentlich alles gesagt. Die zweite 
Frage spricht allgemein von einem Display. Das kann natürlich beliebig 
ausführlich und endlos beantwortet werden. Ich sehe an der Art der 
Fragestellung, dass dem TO das Konzept von Zeichensätzen und Tabellen 
für den Aufbau und die Ausgabe von Schrift oder allgemeiner Grafik auf 
ein Display nicht ganz klar ist. Vielleicht hat er hier jetzt schon 
einige Anregungen für Vertiefung des Themas bekommen. Falls er aber nur 
mit seiner Matrix klar kommen möchte, dann erwarte ich weitere Fragen.
Gruß Rainer

von Johannes S. (Gast)


Lesenswert?

weil man eine WS2812 Matrix genauso wie ein TFT Display betrachten kann, 
funktioniert die Adafruit GFX Lib dafür ganz gut und das gibt es sogar 
fertig:
https://learn.adafruit.com/adafruit-neopixel-uberguide/neomatrix-library

das baut auf die generische GFX Klasse auf, die das mit NeoPixel 
kombiniert. Damit hat man dann Zeichenfunktionen und Character Ausgaben. 
Für Zeichen gibt es die einfachen fixed size Fonts, und wenn das Display 
größer ist, dann kann man die schöneren Fonts mit variabler Zeichengröße 
einsetzen. Dafür gibt es dann auch noch Fontgeneratoren. Da würde ich 
das Rad nicht neu erfinden wollen.

von Sebastian S. (amateur)


Lesenswert?

Zu wenige Informationen zur Anzeige!

Können die Pixel außer an und aus noch andere Kunststückchen?
So Sachen wie Helligkeit und/oder Farbe?

Beim Konzept besteht auch ein "kleiner" Unterschied zwischen Anzeigen, 
die 307 Bildpunkte unterstützen und denen die 5 Millionen im Angebot 
haben.

Können einzelne Bildpunkte bedient werden oder nur Bereiche?

Meine Glaskugel ist leider in der Reparatur.

von Georg (Gast)


Lesenswert?

Attila C. schrieb:
> "Beschreibt"
> man jedes Pixel einzeln mit xy, Helligkeit und Farbe? Jedes mal einzeln
> für jeden vorkommenden Fall?

Ja, natürlich muss man für das Pixel an Position x=38 Y=22 rot eine 
extra Funktion schreiben. Damit man den Überblick behält nennt man die 
zweckmässigerweise SetPixel3822rot. Für ein grosses Display und 
Millionen Farben braucht man halt viele viele Funktionen. :-)

Rainer V. schrieb:
> Ich sehe an der Art der
> Fragestellung, dass dem TO das Konzept von Zeichensätzen und Tabellen
> für den Aufbau

Üblicherweise baut man das hierarchisch auf, man fängt mit einer 
SetPixel-Funktion an, der man Position und Farbe übergibt, dann eine 
Funktion SetCharacter, der man das Zeichen, Position und Farbe übergibt 
und die dann für alle Pixel SetPixel aufruft und die Pixelwerte aus der 
Zeichensatztabelle holt, und dann eine Funktion SetText...

Aber das dürfte den TO heillos überfordern.

Georg

von W.S. (Gast)


Lesenswert?

Rainer V. schrieb:
> Ja, aber so wird er ganz bestimmt keinen "Zeichensatz" hinkriegen...na
> ja, vielleicht ala 7-Segment-Anzeige...aber darauf zielt die Frage doch
> nicht ab.

Nö, genau so funktioniert es bei allen Systemen im Prinzip. Man hat eine 
Start- bzw. Basis-Position, das darzustellende Zeichen in passender 
Codierung und einen Font, der für seine enthaltenen Zeichen die Glyphen 
enthält. Dazu gibt es den Device-Kontext, der die Farbe, Richtung und 
andere globale Attribute vorhält.

Soweit zum Darstellen von Texten.
Das Darstellen von Grafiken (um beim Thema zu bleiben) ist fast gleich, 
lediglich die Farben werden aus den Glyphen geliefert und die 
Hintergrundfarbe ist bei 100% Deckung egal.

W.S.

von c-hater (Gast)


Lesenswert?

Johannes S. schrieb:

> weil man eine WS2812 Matrix genauso wie ein TFT Display betrachten kann,

Es ist zu bezweifeln, dass das wirklich immer so ist. Allein schon die 
Organisation der "Pixeladdressen" kann total unterschiedlich sein. OK, 
bei einem TFT wird's wohl im Allgemeinen darauf hinauslaufen, dass die 
Adressen innerhalb einer Zeile aufsteigend sind mit Increment bpp und 
die Zeilenadressen aufsteigend mit Increment bpp * ppl.

Eine Matrix aus WS28xx-LEDs könnte genauso organisiert sein, muss es 
aber nicht. Insbesondere ist hier die Variante "zig zag" zu 
berücksichtigen (die aus elektrischen Gründen durchaus Sinn ergeben 
kann). Hat man so eine Matrix, fällt man auf die Schnauze.

Dazu kommt noch folgendes Problem: Was ist eigentlich die Zeile, was die 
Spalte. Bei TFTs ist typischerweise die größere Dimension die Zeile, 
weil elektrisch vieles dafür spricht, das so zu handhaben. Bei 
WS28xx-Matrizen hingegen gibt es keine solche Vorzugsrichtung.

Und weiters: TFTs müssen nicht notwendigerweise 24bit-Farben verwenden. 
Es gibt viele, die nur 16bit verwenden.

Sprich: Wer clever ist, trennt die Adressierung logisch komplett von dem 
restlichen Kram...

von Johannes S. (Gast)


Lesenswert?

Die Trennung von Framebuffer und Displayorganisation ist doch in dem 
genannten Link sogar beschrieben, die NeoMatrix kann verschiedene 
umsetzen. Auch bei TFT/LCD können die Daten Zeilen- oder Spaltenweise 
reingeschoben werden müssen. Mit den Adafruit Klassen ist das jedenfalls 
realisierbar. Eine schöne C++ Anwendung.

von Attila C. (attila)


Lesenswert?

OK! Wow! Vielen Dank für die Hilfe! Es handelt sich um eine 
WS2812Matrix.

Ich mache also eine Tabelle pro Buchstaben in der die x/y Koordinaten 
der Buchstaben"teile" aufgelistet sind? Und dann eine Funktion diese 
abfragt und zu der Matrix "schiebt"?

Das ganze soll in C stattfinden. Ich werde jetzt erst mal die ganzen 
links die hier gepostet wurden studieren, denke aber dass ich noch 
einige Fragen haben werde. Es scheint, wie hier einige schon bemerkt 
haben, keine einfache Sache zu sein.

Wegen dem Display habe ich gefragt da ich schon mal auf einem kleinen 
TFT Bildpunkte mit x/y angezeigt bekommen habe aber dann keinerlei Idee 
hatte wie man dann weiter macht? Wie man z.B. , angenommen man hat eine 
Blume "gemalt", diese z.B. dreht ohne jedes mal die ganze Blume neu "zu 
zeichnen". Gibt es dazu Material?

von Erich (Gast)


Lesenswert?

Attila C. schrieb:
> angenommen man hat eine
> Blume "gemalt"

Du solltest dich erstmal mit den "einfacheren" Dingen befassen.
Einzelne Zeichen bzw. Buchstaben einer festen Grösse auf das Display 
schreiben beispielsweise.

von c-hater (Gast)


Lesenswert?

Attila C. schrieb:

> Ich mache also eine Tabelle pro Buchstaben in der die x/y Koordinaten
> der Buchstaben"teile" aufgelistet sind?

Nein, natürlich nicht, das wäre schwachsinnig und ineffizient. 
Schwachsinnig deshalb, weil selbst jemandem wie dir paktisch sofort klar 
sein sollte:

1) Buchstaben können in einem Text mehrfach vorkommen.
2) Text könnte an verschiedenen Stellen ausgegeben werden sollen.

Beides führt sofort zu dem logischen Schluß, dass es kompletter 
Schwachsinn wäre, absolute Positionen bezüglich irgendeines Zielgerätes 
im Zeichensatz zu speichern.

Nein. Ein Zeichensatz hat sinnvollerweise sein eigenes Pixelformat und 
seine eigenes Koordinatensystem. Bei Pixel-Zeichensätzen ist das typisch 
implizit, gespeicheichert werden also nicht Koordinaten, sondern Bits. 
Die Koordinaten (bezüglich des Zeichenursprungs) ergeben sich aus der 
Position der Bits. Bei Vector-Zeichensätzen hingegen werden tatsächlich 
Koordinaten gespeichert. Allerdings auch ohne jeglichen Bezug zum 
Ziel-Device, sondern immer nur relativ zum Ursprung des Zeichens im 
Koordinatensystem des Zeichensatzes.

von Adam P. (adamap)


Lesenswert?

Attila C. schrieb:
> Es handelt sich um eine
> WS2812Matrix.

Dachte ich mir schon...

Attila C. schrieb:
> Ich mache also eine Tabelle pro Buchstaben in der die x/y Koordinaten
> der Buchstaben"teile" aufgelistet sind?

Schau dir dafür lieber den Link an, den ich dir gepostet habe:

"the dot factory" - das Prog. erstellt dir ein array mit bereits allen 
pixeln und für alle Zeichen die du möchtest.

---

ok, wie bereits vermutet, ihm fehlt die Grundlage - aber 
hey...irgendwann muss jeder mal ins kalte Wasser :-D

: Bearbeitet durch User
von Rainer V. (a_zip)


Lesenswert?

Attila C. schrieb:
> WS2812Matrix.

Ist offensichtlich aus der Arduino-Welt. Deshalb empfehle ich erst mal:

https://www.instructables.com/Getting-Started-With-NeoPixle-WS2812-RGB-LED/

Dann warten wir auf weitere Fragen...
Gruß Rainer

von MaWin (Gast)


Lesenswert?

Attila C. schrieb:
> Ich mache also eine Tabelle pro Buchstaben

Nein  du machst eine Tabelle für den ganzen (5x7) font.

bit font[0..255,0..4,0..6];

allerdings packt man bits gerne in bytes oder worte.

von Attila C. (attila)


Lesenswert?

Hallo!

Also: Es ist eine 32*8 WS2812 Matrix. Ich habe jetzt eine Funktion 
"setPixel" gebaut die ich nach dem Neopixel (link siehe oben) Vorbild 
programmiert habe. x geht von links nach rechts und y von oben nach 
unten. Auch die Übergabe der Farbe habe ich nachgebaut (alle 3 Werte in 
einer 16 bit Variable gepackt).

Auch habe ich beim stöbern in den Neopixel Codes einen "Standart ASCII 
5x7 font" gefunden. Dort befindet sich eine recht lange Kette von HEX 
Werten. Ich verstehe nicht was diese Werte darstellen.

Ich habe auch eine andere Tabelle gefunden, 5x8 diesmal, wo jedem ASCII 
Zeichen 4 HEX Werte zugeordnet sind. Auch da erschließt sich mir nicht 
wie daraus ein Buchstabe gemacht wird?

Für ein großes A bräuchte man ja 16 Werte als Koordinaten. Wo verstecken 
sich diese in diesen HEX Codes? Oder denke ich in die völlig falsche 
Richtung?

von Johannes S. (Gast)


Lesenswert?

Wenn du die Nullen und Einsen eines Zeichens in zwei Farben auf Papier 
malst siehst du es vielleicht.

von c-hater (Gast)


Lesenswert?

Attila C. schrieb:

> Also: Es ist eine 32*8 WS2812 Matrix. Ich habe jetzt eine Funktion
> "setPixel" gebaut die ich nach dem Neopixel (link siehe oben) Vorbild
> programmiert habe. x geht von links nach rechts und y von oben nach
> unten. Auch die Übergabe der Farbe habe ich nachgebaut (alle 3 Werte in
> einer 16 bit Variable gepackt).

Was ist denn das schon wieder für ein Quatsch? Deine LEDs können doch 
24Bit-Farben. Da ergibt es absolut keinen Sinn, die Farbe auf 16Bit 
einzudampfen. Benutze uint32_t für die Farbe (und darin nur die unteren 
drei Bytes).

> Auch habe ich beim stöbern in den Neopixel Codes einen "Standart ASCII
> 5x7 font" gefunden. Dort befindet sich eine recht lange Kette von HEX
> Werten. Ich verstehe nicht was diese Werte darstellen.

Dann musst du halt weiter nachdenken. Erkenntnis kannst du nicht aus 
Foren schöpfen, die kannst du nur selbst gewinnen.

> Ich habe auch eine andere Tabelle gefunden, 5x8 diesmal, wo jedem ASCII
> Zeichen 4 HEX Werte zugeordnet sind. Auch da erschließt sich mir nicht
> wie daraus ein Buchstabe gemacht wird?

Gleiches Problem. Was du hier nicht verstehst, kann dir niemand wirklich 
erklären. Das kannst du nur durch selbst Denken lernen

> Für ein großes A bräuchte man ja 16 Werte als Koordinaten.

Wie kommst du darauf? Wieviele Koordinaten es für ein "A" gibt, ergibt 
sich aus dem Zeichensatz. Wenn es ein 5x7-Pixel-Zeichensatz ist, dann 
müssen das mindestens 35 Koordinaten sein, wobei hier, wie schon weiter 
oben gesagt, keine expliziten Kordinaten gespeichert werden, sondern 
Bits. Es sind also im Zeichensatz mindestens 35 Bits für ein "A" nötig. 
Aus praktischen Gründen dürfte der Zeichensatz aber in Bytes organisiert 
sein. Da bleiben aber immer noch mindestens zwei mögliche Lösungen über: 
Es können entweder 5 Bytes sein, die je sieben Nutzbits enthalten oder 
aber 7 Bytes, die je 5 Nutzbits enthalten.

von A. S. (Gast)


Lesenswert?

Johannes S. schrieb:
> Wenn du die Nullen und Einsen eines Zeichens in zwei Farben auf Papier
> malst siehst du es vielleicht.

Karriertes Papier nehmen und für jede 1 im Byte das Kästchen ausmalen.

Links anfangen Bit 0, rechts Bit 7

Nächstes Byte genauso darunter.

Und dann drehen und spiegeln bis ein Zeichen erkennbar ist.

Nicht mit dem Leerzeichen anfangen.

von Rainer V. (a_zip)


Lesenswert?

A. S. schrieb:
> Nicht mit dem Leerzeichen anfangen.

...und jeder nur ein Kreuz...

von Stefan F. (Gast)


Lesenswert?

Attila C. schrieb:
> Auch habe ich beim stöbern in den Neopixel Codes einen "Standart ASCII
> 5x7 font" gefunden. Dort befindet sich eine recht lange Kette von HEX
> Werten. Ich verstehe nicht was diese Werte darstellen.

Jedes Byte entspricht einer vertikalen Reihe von Pixeln. Oben ist Bit 0, 
unten ist bit 6. Bit 7 wird nicht verwendet. Jedes Zeichen besteht auf 5 
solcher Pixelreihen, die erste ist links, die letzte ist rechts.

> Ich habe auch eine andere Tabelle gefunden, 5x8 diesmal, wo jedem ASCII
> Zeichen 4 HEX Werte zugeordnet sind. Auch da erschließt sich mir nicht
> wie daraus ein Buchstabe gemacht wird?

Da besteht halt jedes Zeichen aus 4x8 Pixeln. Wobei in diesem Fall 
meistens eine vertikale Reihe als Abstand zwischen den Buchstaben per 
Software eingefügt wird. Also ist es eigentlich ein 5x8 Font, nur dass 
man das immer leere Byte weg gespart hat.

von Attila C. (attila)


Lesenswert?

Ahaaaaaaaaaaaaa! Wie krass ist das denn? Was es für geniale Sachen gibt!
Vielen Dank für en Input! :-)
Das Ganze jetzt auch noch umzusetzen wird wohl ein separater Spass! :-)

Es soll übrigens ein Anzeige der nächsten 3 Flugzeuge an einem Flughafen 
basierend auf Distanz und den Daten der opensky-network API werden. 
Dieser Thread ist also noch eine Weile "alive"!

von Georg (Gast)


Lesenswert?

Stefan ⛄ F. schrieb:
> Da besteht halt jedes Zeichen aus 4x8 Pixeln

Das ist aber sehr ungünstig und gibt nur schlecht lesbare Zeichen, 5 x 7 
ist so etwa das sinnvolle Minimum. Ich glaube eher er hat sich da 
verzählt und es sind 5 Bytes pro Character.

Georg

von A. S. (Gast)


Lesenswert?

Georg schrieb:
> Stefan ⛄ F. schrieb:
>> Da besteht halt jedes Zeichen aus 4x8 Pixeln
>
> Das ist aber sehr ungünstig und gibt nur schlecht lesbare Zeichen, 5 x 7
> ist so etwa das sinnvolle Minimum. Ich glaube eher er hat sich da
> verzählt und es sind 5 Bytes pro Character.
>
> Georg

Ja, für ein m braucht man 5 Spalten, egal ob klein oder groß. Alles 
andere ginge auch mit 4.

Falls der Zeichensatz wirklich 5x7 ist und das ganze auf 4 byte 
komprimiert (wegen soll in 0 Byte RoM passen), dann wäre mein Tipp oben, 
dass auszukästeln, wohl vergeblich.

von Tam H. (Firma: Tamoggemon Holding k.s.) (tamhanna)


Lesenswert?

Hallo,
du zeichnest im Prinzip eine Rotte von kleinen Bitmaps, immer pro 
Zeichen eines. Also wird aus dem String HURZ die Kombination H U R Z.

Trick dabei ist der Ascii-Code, du kannst Z.B. 'b' - 'a', um 1 zu 
bekommen...wen du nicht einfach alle 255 ASCII-Zeichen als Bitmap 
mitschleppen willst.

Für die Erzeugung der Bitmaparrays empfehle ich den GLCD Font Creator, 
findet sich unter https://www.mikroe.com/glcd-font-creator.

Vollständiges Tutorial, damals mit einer 16x16 LED-Matrix die mir meine 
Ex-LZ aufgeschwatzt hat, findest du unter 
https://www.elektormagazine.de/magazine/elektor-201604/28886.

von W.S. (Gast)


Lesenswert?

c-hater schrieb:
> Da bleiben aber immer noch mindestens zwei mögliche Lösungen über:
> Es können entweder 5 Bytes sein, die je sieben Nutzbits enthalten oder
> aber 7 Bytes, die je 5 Nutzbits enthalten.

Tatsächlich sind es 3..4 mögliche Lösungen:
- 5 Byte, von denen je 7 Bit genutzt werden
- 7 Byte, von denen je 5 Bit genutzt werden
- Bitstream (also wo die Bytegrenzen nicht mit den Pixelpositionen 
übereinstimmen)
- Bitstream komprimiert

W.S.

von Stefan F. (Gast)


Lesenswert?

Hier ist der Font aus meiner OLED Bibliothek:
1
static const uint8_t font6x8 [] PROGMEM = {
2
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // space
3
    0x00, 0x00, 0x00, 0x2f, 0x00, 0x00, // !
4
    0x00, 0x00, 0x07, 0x00, 0x07, 0x00, // "
5
    0x00, 0x14, 0x7f, 0x14, 0x7f, 0x14, // #
6
    0x00, 0x24, 0x2a, 0x7f, 0x2a, 0x12, // $
7
    0x00, 0x62, 0x64, 0x08, 0x13, 0x23, // %
8
    0x00, 0x36, 0x49, 0x55, 0x22, 0x50, // &
9
    0x00, 0x00, 0x05, 0x03, 0x00, 0x00, // '
10
    0x00, 0x00, 0x1c, 0x22, 0x41, 0x00, // (
11
    0x00, 0x00, 0x41, 0x22, 0x1c, 0x00, // )
12
    0x00, 0x14, 0x08, 0x3E, 0x08, 0x14, // *
13
    0x00, 0x08, 0x08, 0x3E, 0x08, 0x08, // +
14
    0x00, 0x00, 0x00, 0xA0, 0x60, 0x00, // ,
15
    0x00, 0x08, 0x08, 0x08, 0x08, 0x08, // -
16
    0x00, 0x00, 0x60, 0x60, 0x00, 0x00, // .
17
    0x00, 0x20, 0x10, 0x08, 0x04, 0x02, // /
18
    0x00, 0x3E, 0x51, 0x49, 0x45, 0x3E, // 0
19
    0x00, 0x00, 0x42, 0x7F, 0x40, 0x00, // 1
20
    0x00, 0x42, 0x61, 0x51, 0x49, 0x46, // 2
21
    0x00, 0x21, 0x41, 0x45, 0x4B, 0x31, // 3
22
    0x00, 0x18, 0x14, 0x12, 0x7F, 0x10, // 4
23
    0x00, 0x27, 0x45, 0x45, 0x45, 0x39, // 5
24
    0x00, 0x3C, 0x4A, 0x49, 0x49, 0x30, // 6
25
    0x00, 0x01, 0x71, 0x09, 0x05, 0x03, // 7
26
    0x00, 0x36, 0x49, 0x49, 0x49, 0x36, // 8
27
    0x00, 0x06, 0x49, 0x49, 0x29, 0x1E, // 9
28
    0x00, 0x00, 0x36, 0x36, 0x00, 0x00, // :
29
    0x00, 0x00, 0x56, 0x36, 0x00, 0x00, // ;
30
    0x00, 0x08, 0x14, 0x22, 0x41, 0x00, // <
31
    0x00, 0x14, 0x14, 0x14, 0x14, 0x14, // =
32
    0x00, 0x00, 0x41, 0x22, 0x14, 0x08, // >
33
    0x00, 0x02, 0x01, 0x51, 0x09, 0x06, // ?
34
    0x00, 0x32, 0x49, 0x59, 0x51, 0x3E, // @
35
    0x00, 0x7C, 0x12, 0x11, 0x12, 0x7C, // A
36
    0x00, 0x7F, 0x49, 0x49, 0x49, 0x36, // B
37
    0x00, 0x3E, 0x41, 0x41, 0x41, 0x22, // C
38
    0x00, 0x7F, 0x41, 0x41, 0x22, 0x1C, // D
39
    0x00, 0x7F, 0x49, 0x49, 0x49, 0x41, // E
40
    0x00, 0x7F, 0x09, 0x09, 0x09, 0x01, // F
41
    0x00, 0x3E, 0x41, 0x49, 0x49, 0x7A, // G
42
    0x00, 0x7F, 0x08, 0x08, 0x08, 0x7F, // H
43
    0x00, 0x00, 0x41, 0x7F, 0x41, 0x00, // I
44
    0x00, 0x20, 0x40, 0x41, 0x3F, 0x01, // J
45
    0x00, 0x7F, 0x08, 0x14, 0x22, 0x41, // K
46
    0x00, 0x7F, 0x40, 0x40, 0x40, 0x40, // L
47
    0x00, 0x7F, 0x02, 0x0C, 0x02, 0x7F, // M
48
    0x00, 0x7F, 0x04, 0x08, 0x10, 0x7F, // N
49
    0x00, 0x3E, 0x41, 0x41, 0x41, 0x3E, // O
50
    0x00, 0x7F, 0x09, 0x09, 0x09, 0x06, // P
51
    0x00, 0x3E, 0x41, 0x51, 0x21, 0x5E, // Q
52
    0x00, 0x7F, 0x09, 0x19, 0x29, 0x46, // R
53
    0x00, 0x46, 0x49, 0x49, 0x49, 0x31, // S
54
    0x00, 0x01, 0x01, 0x7F, 0x01, 0x01, // T
55
    0x00, 0x3F, 0x40, 0x40, 0x40, 0x3F, // U
56
    0x00, 0x1F, 0x20, 0x40, 0x20, 0x1F, // V
57
    0x00, 0x3F, 0x40, 0x38, 0x40, 0x3F, // W
58
    0x00, 0x63, 0x14, 0x08, 0x14, 0x63, // X
59
    0x00, 0x07, 0x08, 0x70, 0x08, 0x07, // Y
60
    0x00, 0x61, 0x51, 0x49, 0x45, 0x43, // Z
61
    0x00, 0x00, 0x7F, 0x41, 0x41, 0x00, // [
62
    0x00, 0x55, 0x2A, 0x55, 0x2A, 0x55, // backslash
63
    0x00, 0x00, 0x41, 0x41, 0x7F, 0x00, // ]
64
    0x00, 0x04, 0x02, 0x01, 0x02, 0x04, // ^
65
    0x00, 0x40, 0x40, 0x40, 0x40, 0x40, // _
66
    0x00, 0x00, 0x01, 0x02, 0x04, 0x00, // '
67
    0x00, 0x20, 0x54, 0x54, 0x54, 0x78, // a
68
    0x00, 0x7F, 0x48, 0x44, 0x44, 0x38, // b
69
    0x00, 0x38, 0x44, 0x44, 0x44, 0x20, // c
70
    0x00, 0x38, 0x44, 0x44, 0x48, 0x7F, // d
71
    0x00, 0x38, 0x54, 0x54, 0x54, 0x18, // e
72
    0x00, 0x08, 0x7E, 0x09, 0x01, 0x02, // f
73
    0x00, 0x18, 0xA4, 0xA4, 0xA4, 0x7C, // g
74
    0x00, 0x7F, 0x08, 0x04, 0x04, 0x78, // h
75
    0x00, 0x00, 0x44, 0x7D, 0x40, 0x00, // i
76
    0x00, 0x40, 0x80, 0x84, 0x7D, 0x00, // j
77
    0x00, 0x7F, 0x10, 0x28, 0x44, 0x00, // k
78
    0x00, 0x00, 0x41, 0x7F, 0x40, 0x00, // l
79
    0x00, 0x7C, 0x04, 0x18, 0x04, 0x78, // m
80
    0x00, 0x7C, 0x08, 0x04, 0x04, 0x78, // n
81
    0x00, 0x38, 0x44, 0x44, 0x44, 0x38, // o
82
    0x00, 0xFC, 0x24, 0x24, 0x24, 0x18, // p
83
    0x00, 0x18, 0x24, 0x24, 0x18, 0xFC, // q
84
    0x00, 0x7C, 0x08, 0x04, 0x04, 0x08, // r
85
    0x00, 0x48, 0x54, 0x54, 0x54, 0x20, // s
86
    0x00, 0x04, 0x3F, 0x44, 0x40, 0x20, // t
87
    0x00, 0x3C, 0x40, 0x40, 0x20, 0x7C, // u
88
    0x00, 0x1C, 0x20, 0x40, 0x20, 0x1C, // v
89
    0x00, 0x3C, 0x40, 0x30, 0x40, 0x3C, // w
90
    0x00, 0x44, 0x28, 0x10, 0x28, 0x44, // x
91
    0x00, 0x1C, 0xA0, 0xA0, 0xA0, 0x7C, // y
92
    0x00, 0x44, 0x64, 0x54, 0x4C, 0x44, // z
93
    0x00, 0x00, 0x08, 0x77, 0x41, 0x00, // {
94
    0x00, 0x00, 0x00, 0x63, 0x00, 0x00, // ¦
95
    0x00, 0x00, 0x41, 0x77, 0x08, 0x00, // }
96
    0x00, 0x08, 0x04, 0x08, 0x08, 0x04, // ~
97
    0x00, 0x3D, 0x40, 0x40, 0x20, 0x7D, // ü
98
    0x00, 0x3D, 0x40, 0x40, 0x40, 0x3D, // Ü
99
    0x00, 0x21, 0x54, 0x54, 0x54, 0x79, // ä
100
    0x00, 0x7D, 0x12, 0x11, 0x12, 0x7D, // Ä
101
    0x00, 0x39, 0x44, 0x44, 0x44, 0x39, // ö
102
    0x00, 0x3D, 0x42, 0x42, 0x42, 0x3D, // Ö
103
    0x00, 0x02, 0x05, 0x02, 0x00, 0x00, // °
104
    0x00, 0x7E, 0x01, 0x49, 0x55, 0x73, // ß
105
};

(Verdammt, ich kriege die Leerzeilen am Ende nicht weg. Die 
Foren-Software stellt das nicht korrekt dar.)

von Julia (Gast)


Lesenswert?

Fiken wird auf jeden Fall richtig mit "C" geschrieben! Ich muss es 
schließlich wissen.

von c-hater (Gast)


Lesenswert?

W.S. schrieb:

> Tatsächlich sind es 3..4 mögliche Lösungen:
[...]
Wenn man so penibel sein will, gibt es noch viel mehr Möglichkeiten. 
Sind aber letztlich alles nur Varianten zweier Grundschemata: 
zeilenweise vs. spaltenweise. Das war, was ich eigentlich ausdrücken 
wollte.

von Attila C. (attila)


Lesenswert?

So! Guten Tag!
Jetzt habe ich das so hinbekommen dass Buchstaben, Zahlen, Zeichen usw. 
aus dem program space ausgelesen werden und korrekt auf der Matrix 
dargestellt werden. Ich gebe dazu die Stelle an in der sich das erste 
byte im Array befindet und lese die folgenden 4 auch aus.

Muss ich jetzt eine weitere ( womöglich switch case ) Tabelle bauen um 
jedem Zeichen, Buchstaben usw. einen Wert zuzuordnen? Also so würde ich 
es machen. Die Frage ist ob man das so macht?

von A. S. (Gast)


Lesenswert?

Attila C. schrieb:
> Muss ich jetzt eine weitere ( womöglich switch case ) Tabelle bauen um
> jedem Zeichen, Buchstaben usw. einen Wert zuzuordnen? Also so würde ich
> es machen.

Was hast Du immer mit Deinem Switch/Case? Ja, man braucht Arrays für 
Fonts, ja, es Switch/Case hat seine Berechtigung, aber was willst Du 
tun?

von Attila C. (attila)


Lesenswert?

Ich mag switch/case.
Ja die fonts hab ich schon im Array. Die bytes für mein großes "A" 
liegen da z.B. an Stelle 325,326,327,328 und 329. Mache ich jetzt eine 
Tabelle und ordne jedem Buchstaben, Zeichen usw. 5 Zahlenwerte zu? Oder 
gibt es da elegantere Wege?

von Matthias L. (Gast)


Lesenswert?

Attila C. schrieb:
> Stelle 325,326,327,328 und 329.

Warum? Das große A sollte an der Stelle array[65] liegen

von Attila C. (attila)


Lesenswert?

65 x 5 = 325

von Matthias L. (Gast)


Lesenswert?

Attila C. schrieb:
> 65 x 5 = 325

Warum mal 5? Mache doch ein zweidimensionales Array

von Attila C. (attila)


Lesenswert?

"Warum mal 5? Mache doch ein zweidimensionales Array"

Könnte man machen aber es beantwortet meine Frage nicht: Muss ich eine 
Tabelle machen bei der ich jedem Buchstaben eine Zahl zuordne damit 
dieser "seine" bytes im Array findet. Oder geht das eleganter?

von Matthias L. (Gast)


Lesenswert?

Attila C. schrieb:
> Muss ich eine
> Tabelle machen bei der ich jedem Buchstaben eine Zahl zuordne damit
> dieser "seine" bytes im Array findet

Das wäre mM nach die eleganteste Lösung. Eine Tabelle, was ja ein Array 
ist. Dort ist Index gleich ASCI-Code. Und in diesem Index steht der 
entsprechende Buchstabe, bwz die Beschreibung wie er aussieht.

von c-hater (Gast)


Lesenswert?

Attila C. schrieb:

> Jetzt habe ich das so hinbekommen dass Buchstaben, Zahlen, Zeichen usw.
> aus dem program space ausgelesen werden und korrekt auf der Matrix
> dargestellt werden. Ich gebe dazu die Stelle an in der sich das erste
> byte im Array befindet und lese die folgenden 4 auch aus.

OK, es scheint sich also um die spaltenweise abgelegte Variante eines 
5xirgendwas-Fonts zu handeln. "irgendwas" dürfte typisch entweder 7 oder 
8 sein.

> Muss ich jetzt eine weitere ( womöglich switch case ) Tabelle bauen um
> jedem Zeichen, Buchstaben usw. einen Wert zuzuordnen? Also so würde ich
> es machen. Die Frage ist ob man das so macht?

Egal ob nun "irgendwas" 7 oder 8 ist. Solange der Zeichensatz lückenlos 
ist, kann man die Startadresse des Glyphs einfach aus dem Zeichencode 
berechnen, der dargestellt werden soll.

Nehmen wir einfach mal an, der Zeichensatz würde 8 Zeilen pro Zeichen 
umfassen und bei dem Zeichen mit dem Code 32, also dem Leerzeichen 
beginnen und bei dem Zeichen 127 enden.

Dann muss man bei der Ausgabe erstmal checken, ob der Code eines 
auszugebenden Zeichens zwischen 32 und 127 liegt. Wenn nicht, wäre die 
typische Lösung ein Ersatzcode für das Zeichen, z.B. 63, also 
Fragezeichen. Nachdem nun das Zeichen erstmal auf seine Darstellbarkeit 
geprüft und notfalls angepasst ist, ist die verbleibende Rechnung ganz 
simpel.

Als erstes zieht man vom Zeichencode den Code des ersten Zeichens ab, 
der überhaupt im Zeichensatz verfügbar ist. Das, was überbleibt, 
multipliziert man einfach mit dem Speicherbedarf eines Zeichens in der 
Tabelle, was bei dir ja offensichtlich 5 Bytes sind.

Für ein grosses 'A' mit Zeichencode 65 würde sich also ergeben:

(65 - 32) * 5 = 165

Du findest deine 5 Bytes für das Zeichen also ab Offset 165 im 
Zeichensatz.

Noch ein Tipp: statt 65 kannst du in C (und Asm) auch 'A' schreiben...

von Attila C. (attila)


Lesenswert?

Mir ist nicht klar wo da die Prüfung stattfindet. Angenommen ich habe 
einen Stream von Buchstaben in dem jetzt ein "A" vorkommt. Wie "merkt" 
ein Array dass es sich um ein "A" handelt (und verweist auf ->65)? Ich 
kann doch jetzt nicht 255 "if" Anweisungen für jedes mögliche ASCII 
schreiben? Oder etwa doch?

von Attila C. (attila)


Lesenswert?

"Noch ein Tipp: statt 65 kannst du in C (und Asm) auch 'A' schreiben..."

Ach das ist ja krass!!! Ist das abgefahren!

Vielen Dank!

von Matthias L. (Gast)


Lesenswert?

Attila C. schrieb:
> Angenommen ich habe
> einen Stream von Buchstaben in dem jetzt ein "A" vorkommt. Wie "merkt"
> ein Array dass es sich um ein "A" handelt (und verweist auf ->65)? Ich
> kann doch jetzt nicht 255 "if" Anweisungen für jedes mögliche ASCII
> schreiben? Oder etwa doch?

WOzu auch? Du nimmst einfach das Zeichen (in einem byte oder char) und 
nutzt das als Arrayindex. Die oben genannten Prüfungen natürlich 
beachten.

char c = ...; // one letter from stream
array[c]...

von Attila C. (attila)


Lesenswert?

Ich hatte das nicht mehr auf dem Schirm dass ASCII ja genau dafür 
gemacht ist, nämlich einem Zeichen genau eine Zahl in der Range 0-255 
zuzuordnen. Und dass man es natürlich auch einfach umkehren kann. Also 
Buchstabe entspricht Zahl.

von c-hater (Gast)


Lesenswert?

Attila C. schrieb:
> Ich hatte das nicht mehr auf dem Schirm dass ASCII ja genau dafür
> gemacht ist, nämlich einem Zeichen genau eine Zahl in der Range 0-255
> zuzuordnen.

Nö, ASCII geht nur von 0..127. Und die ersten 32 Codes sind eigentlich 
nicht "druckbar".

Was du da versuchst umzusetzen, ist was anderes: eine "Codepage".

> Und dass man es natürlich auch einfach umkehren kann. Also
> Buchstabe entspricht Zahl.

Tatsächlich gibt es eigentlich aus Sicht eines Rechenknechts überhaupt 
keine Buchstaben. Der kann nur Zahlen, nix anderes.

von Rainer V. (a_zip)


Lesenswert?

Ich denke, der TO sollte sich noch einmal den Unterschied zwischen der 
Definition eines Zeichens und der Nutzung dieses Zeichens, z.B. "Zeichen 
anzeigen" klarmachen. Er könnte sich auch noch einmal anschauen, wie man 
in so einem gängigen Display (z.B. 2 Zeilen mit 16 Zeichen) "eigene 
Zeichen" definiert. Genau so geht das ja im Prinzip für jedes Zeichen, 
nur dass das Display eben schon definierte Zeichen mitbringt.
Gruß Rainer

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.