Forum: Mikrocontroller und Digitale Elektronik GLCD Fonts (64x128)


Announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
von Naj H. (janiiix3)


Bewertung
-1 lesenswert
nicht lesenswert
Guten Morgen,

habe hier gesucht, bin leider nur nicht fündig geworden.
Hat jemand schon fertige GLCD Fonts? Alles ab 6x8?

Würde gerne mal ausprobieren wie andere Zeichen auf dem GLCD aussehen.

Danke im vorraus!

von Horst S. (Gast)


Bewertung
1 lesenswert
nicht lesenswert
Heute schon gegoogelt?

von Naj H. (janiiix3)


Bewertung
0 lesenswert
nicht lesenswert
Habe gerade was passen könnte gefunden.
Mir kommen noch ein paar Verständnissfragen auf..

https://github.com/johnmccombs/arduino-libraries/blob/master/glcd/fonts/fixednums7x15.h

In der Headerdatei steht, dass die Zeichen "7x15" groß sind.

Als beispiel die '0'
1
// char '0'
2
0xfc, 0xfe, 0x03, 0xe1, 0x1b, 0xfe, 0xfc,
3
0x0f, 0x1f, 0x36, 0x21, 0x30, 0x1f, 0x0f,

Habe mir die Funkionen geschrieben die mir die Daten zum Display 
schicken.
Wenn ich das "Array für die '0'" jetzt übertragen würde, würde ja nur 
Müll im Display angezeigt werden..

Wie müssten die "for" Schleifen jetzt aussehen?
1
  glcdClear();
2
  while(1)
3
  {
4
    uint8_t i = 0;
5
    glcdGotoXY(2,0);
6
    for (; i < 7 ; i++)
7
    {
8
      glcdSendData(newArray[i]);
9
    }
10
    glcdGotoXY(3,0);
11
    for (; i < 14 ; i++)
12
    {
13
      glcdSendData(newArray[i]);
14
    }    
15
  }

: Bearbeitet durch User
von spess53 (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Hi

>Wenn ich das "Array für die '0'" jetzt übertragen würde, würde ja nur
>Müll im Display angezeigt werden..

Nö, das passt schon. Gilt aber nur für Displays mit senkrechter 
Byteausrichtung und für eine 0 mit Schrägstrich.

MfG Spess

von Naj H. (janiiix3)


Bewertung
0 lesenswert
nicht lesenswert
Okay.

Wie kommt man am besten auf den Anfang der Zahl?
1
void glcdWidthNumb(uint8_t numb, uint8_t x, uint8_t y)
2
{
3
  uint8_t i = numb;
4
  
5
  glcdGotoXY(x,y);
6
  for (; i<(numb+8) ; i++)
7
  {
8
    glcdSendData(swapBits(fixednums8x16[i+6]));
9
  }
10
  glcdGotoXY(x+1,y);
11
  for (; i<(numb+16) ; i++)
12
  {
13
    glcdSendData(swapBits(fixednums8x16[i+6]));
14
  }
15
}

So das man die Funktion mit glcdWidthNumb('1',0,0) aufrufen kann?

von Thomas F. (igel)


Bewertung
2 lesenswert
nicht lesenswert
Jan H. schrieb:
> habe hier gesucht, bin leider nur nicht fündig geworden.

Naja, schlecht gesucht:

Beitrag "Re: LCD Schriftarten ( Fonts in veschiedenen Größen )"

Ein 64x128 Font wie in der Überschrift braucht aber schon ordentlich 
Speicherplatz, 1024 Bytes pro Zeichen!
Da würde ich eher einen kleineren Font wählen und dann in doppelter 
Breite und Höhe ausgeben.

von Naj H. (janiiix3)


Bewertung
0 lesenswert
nicht lesenswert
Thomas F. schrieb:
> Ein 64x128 Font wie in der Überschrift braucht aber schon ordentlich
> Speicherplatz, 1024 Bytes pro Zeichen!
> Da würde ich eher einen kleineren Font wählen und dann in doppelter
> Breite und Höhe ausgeben.

Stimmt habe mich vertan.

Es sollte 6 x 8 heißen.

von W.S. (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Jan H. schrieb:
> habe hier gesucht, bin leider nur nicht fündig geworden.

Da haste aber schlecht gesucht...


Jan H. schrieb:
> for (; i<(numb+8) ; i++)
>   {
>     glcdSendData(swapBits(fixednums8x16[i+6]));

Mir scheint, daß du nicht systematisch an die Sache herangehst.

Also, du hast ein GRAFIK Lcd, ja?
Da solltest du zu allererst dran denken, dein physisches LCD (also die 
Schnittstelle, deren Bedienung usw) vom logischen Display (also 
Bildspeicher mit XXX mal YYY Pixeln) zu trennen. Das macht dir das Leben 
deutlichst leichter, glaub's mir.

Bei deinem logischen Display brauchst du zu allererst eine Funktion zum 
Setzen von Pixeln, etwa so:
void SetzePixel(int X, int Y, byte wie);

Das "wie" gestaltet sich bei monochromen Displays recht einfach: 
schwarz, weiß, invertierend.

Auf diese Funktion zum Pixel Setzen baust du dir nun alle anderen 
Funktionen auf: Textzeichen malen, Rechtecke füllen, Linien zeichnen, 
Kreise zeichnen, Bilder/Icons malen und so weiter.

Dabei merkst du gleich, daß bereits ab der SetzePixel-Funktion das Ganze 
recht hardwareunabhängig wird. Es bleibt eigentlich nur noch die 
Dimension, also wieviele Pixel in X und in Y.

Als zweites brauchst du eine globale bool Variable, die du bei jedem 
Pixel-Schreiben setzt.

Als drittes brauchst du eine Funktion zum blockweisen Übertragen der 
Pixel zum LCD. Die wird in der Grundschleife aufgerufen, wenn die obige 
Variable true ist. Diese Funktion schaufelt den ganzen logischen 
Display-RAM in das Display und setzt obige Variable wieder auf false 
zurück.

So. Damit hast du ein relativ geräteunabhängiges GDI und einen 
"Hardware-treiber" für dein aktuelles Display.

So herum geht das viel besser.

W.S.

von Dominik (Gast)


Bewertung
0 lesenswert
nicht lesenswert
W.S. schrieb:
> Bei deinem logischen Display brauchst du zu allererst eine Funktion zum
> Setzen von Pixeln, etwa so:
> void SetzePixel(int X, int Y, byte wie);

Hallo,
das ist sicher richtig wenn man von potenter Steuerungshardware ausgeht.
Handelt es sich um einen kleinen µC will man sicher eher nicht 6x8=48 
Funktionsaufrufe pro Zeichen, da wird man den Abstraktionslayer doch 
näher in Richtung Hardware legen wollen.
Der andere Quelltext im Thread erinnert auch schwer an einen 8bit AVR 
o.ä.

Jan H. schrieb:
> Wie müssten die "for" Schleifen jetzt aussehen?
>   glcdClear();
>   while(1)
>   {
>     uint8_t i = 0;
>     glcdGotoXY(2,0);
>     for (; i < 7 ; i++)
>     {
>       glcdSendData(newArray[i]);
>     }
>     glcdGotoXY(3,0);
>     for (; i < 14 ; i++)
>     {
>       glcdSendData(newArray[i]);
>     }
>   }

Kommt darauf an. Reine Spekulation:

Handelt es sich um das "Standard"-LCD12864 mit ST7920?
Dann (wie immer) lohnt sich ein tiefer Blick ins Datenblatt, das Teil 
verfügt über 16bit Breite Spalten im Grafikmodus. Bei den gotoxy... ist 
zu beachten, dass sich die unterer Hälfte meist linear an die obere 
anschließt, sprich logisch sind es eher 256x32 Pixel.

Die oben erwähnte 7x15er ist eigentlich 7x16 und macht in sofern Sinn,
dass man ein Zeichen ohne Umwege in einer Spalte platzieren kann.

11111100 11111110 00000011...
sieht aus wie die 3 rechten oberen Zeilen der 0, die müssen dann auch so
platziert werden
0x0F -> 00001111 0x1F -> 00011111
könnte links oben sein,
also muss jetzt 16 bit Zeilenweise der Array[zeile+0] und der 
Array[zeile+8te] Wert aufs Display geschrieben werden.
In welcher Reihenfolge müsste ich jetzt selbst erst ins Datenblatt 
gucken.

Dass man bei so einer Schriftart auch ein normales Text-LCD mit 16x02 
nehmen könnte (wenn das die einzige Grafikanzeige wird) ist denke klar.

Sollen nun aber andere Schriftgrößen angezeigt werden wird es zunehmend 
schwieriger. Bei den angedachten 6x8 passen nämlich 2 2/3 Zeichen in 
eine
16 bit breite Spalte, daher muss man entweder diese Spalte im Speicher 
vorbereiten (+weitere wenn die Zeichen überlappen) oder sich den 
Speicherinhalt vom LCD zurücklesen, anpassen und wieder zurückschreiben.

Gruß Dominik

von Nico W. (nico_w)


Bewertung
0 lesenswert
nicht lesenswert
Dominik schrieb:
> Hallo,
> das ist sicher richtig wenn man von potenter Steuerungshardware ausgeht.
> Handelt es sich um einen kleinen µC will man sicher eher nicht 6x8=48
> Funktionsaufrufe pro Zeichen, da wird man den Abstraktionslayer doch
> näher in Richtung Hardware legen wollen.
> Der andere Quelltext im Thread erinnert auch schwer an einen 8bit AVR
> o.ä.


Das ist doch völlig Banane. Ich habe erst letztens einen Treiber für ein 
ST7735 gebaut auf nem STM mit 72MHz. Da kann es genauso zu langsam 
werden. Liegt aber nicht an der Funktion, sondern was man dem Compiler 
an Optimierungen ermöglicht.


Mit O0, ohne LTO und inlining wird es natürlich arsch lahm, wenn man 
viele Funktionen hat. Aber deshalb drauf zu verzichten? Äh, ne...

von Dominik (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Nico W. schrieb:
> Das ist doch völlig Banane. Ich habe erst letztens einen Treiber für ein
> ST7735 gebaut auf nem STM mit 72MHz. Da kann es genauso zu langsam
> werden. Liegt aber nicht an der Funktion, sondern was man dem Compiler
> an Optimierungen ermöglicht.

Hallo,
war keine Kritik, nur ein Vorschlag, sicherlich kann man das so machen,
kommt wie gesagt auf das System an und was man erreichen will.
Setzt man auf ein langsames Pferd (Atmega mit 8Mhz oder so), wird die 
Performance davon schon profitieren wenn man (bei oben spekuliertem 
Szenario) seine Grafikansteuerung auf die 16bit Felder abstimmt. Wenn 
ich einzelne Bits setze, kann der Compiler da auch nicht auf 16 bit 
Breite optimieren.
Bleiben wir mal beim Beispiel mit dem AVR und dem 128*64er Display,
wenn ich jetzt alle Pixel per Funktion setzen will (z.B. CLRSCR) brauche 
ich 8192 Aufrufe
meiner setPixel(...)-Funktion, nehmen wir mal an, diese operiert auf 
einem
internen Grafik-Speicher:
1
uint8_t pixMap[16][64];
2
void setPixel(uint8_t x, uint8_t y, uint8_t white)
3
{
4
  uint8_t column=x>>3;  //Div 8
5
  uint8_t bit=x&0x07;    //Modulo 8
6
  switch(white)
7
  {
8
    case 1:
9
      pixMap[column][y]|=(1<<bit);
10
    break;
11
    case 0:
12
      pixMap[column][y]&=(uint8_t)(~(1<<bit));
13
    break;
14
  }
15
}
Diese Beispiel-Funktion (ohne Aufrufe) benötigt auf obigem AVR etwas 
über 50 Takte, macht 410.000 Takte nur für das setzen aller Pixel, also 
etwa 1/20 Sekunde...
Kann je nach Anwendung genügen. Aber wahrscheinlich hat der Controller 
ja auch noch irgendeine Hauptaufgabe wenn es nicht unbedingt ein 
dedizierter LCD-Treiber ist.

Es führen viele Wege nach Rom.

Gruß Dominik

von W.S. (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Dominik schrieb:
> das ist sicher richtig wenn man von potenter Steuerungshardware ausgeht.
> Handelt es sich um einen kleinen µC will man sicher eher nicht 6x8=48
> Funktionsaufrufe pro Zeichen, da wird man den Abstraktionslayer doch
> näher in Richtung Hardware legen wollen.

Wenn man selber potent genug ist, um sich seine Probleme selbst zu 
lösen, dann ist dein Vorschlag richtig. Wenn man hingegen schon an den 
Präliminarien scheitert, dann nicht.

In letzterem Falle sollte man eben doch die 48 Aufrufe sich gönnen - 
einfach um wenigstens dazu in der Lage zu sein, das richtige Setzen von 
Pixeln zunächst zu lösen, bevor man sich an höhere Dinge wagt, wie z.B. 
das Verstehen und Anwenden von Fonts.

Nebenbei ist der schiere Aufruf eher kein Thema. Beim Pixelsetzen muß 
man ja noch so einiges anderes machen, z.B. Abprüfen der Bounds (if x<0 
or x>displaybreite or y<0 oe y>displayhöhe dann raus hier..) oder das 
Ausführen der Pixelmodi (if black then machblack else if white then.. 
else if invert then liespixel..xorpixel..setpixel..) - kurzum, die 48 
Aufrufe lohnen sich, damit ein bissel Qualität und Funktionssicherheit 
hineinkommt.

W.S.

von Dominik (Gast)


Bewertung
0 lesenswert
nicht lesenswert
W.S. schrieb:
> Nebenbei ist der schiere Aufruf eher kein Thema. Beim Pixelsetzen muß
> man ja noch so einiges anderes machen, z.B. Abprüfen der Bounds (if x<0
> or x>displaybreite or y<0 oe y>displayhöhe dann raus hier..) oder das
> Ausführen der Pixelmodi (if black then machblack else if white then..
> else if invert then liespixel..xorpixel..setpixel..) - kurzum, die 48
> Aufrufe lohnen sich, damit ein bissel Qualität und Funktionssicherheit
> hineinkommt.

Wie gesagt, viele wegen führen nach Rom, aber wenn das anzunehmende 
Target ein 8bit µC ist, würde ich das nicht machen sondern bereits in 
den aufrufenden Funktionen die Bereichsüberschreitungen verhindern.
Je nach uC kommt sonst neben Geschwindigkeitsproblemen auch gerne mal 
das Ende vom Flash sehr nahe :-)
Im Falle der Programmierung einer Anwendersoftware unter einem gängigen 
Betriebssystem stimme ich dem natürlich zu, da wird man diese 
Überschreitungen meist auch zusätzlich noch zum debuggen catchen.

Dominik schrieb:
> uint8_t column=x>>3;  //Div 8
>   uint8_t bit=x&0x07;    //Modulo 8

Sowas würde ich für eine solche Anwendung dann auch in "Schönschrift" 
programmieren.

Sofern man die setPixel-Variante auf dem µC gehen will, sollte man aber 
zumindest clearScreen/setBackground/setPattern/etc. auf die logischen 
Spalten und Zeilen des Displays umsetzen, damit man dort wenigstens 
nicht jede Variable 8x anfassen muss.

Gruß Dominik

von W.S. (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Dominik schrieb:
> Wie gesagt, viele wegen führen nach Rom, aber wenn das anzunehmende
> Target ein 8bit µC ist, würde ich das nicht machen

Ich auch nicht wirklich. Also was soll das Ganze? Mit einem 
Grafik-Display ist ein kleiner 8 Bitter recht schnell an seinen Grenzen. 
Ich hatte mal aus Wißbegierde ein ALPS LSU7S1011A (von Pollin) mit einem 
PIC16F871 in Assembler angesteuert. Ja, geht, geht auch schnell genug, 
aber ist dennoch ein einziger Krampf, weil eben der µC dafür zu klein 
war.

Also, wenn wirklich Grafik ansteht, dann den Controller danach 
auswählen. Wenn die Grafik nur so etwa 128x64 oder gar nur 96x32 oder so 
beträgt, dann muß der Controller nur genügend RAM mitbringen, in diesem 
Fall so etwa 1K für den Display-RAM und nochwas obendrauf für den Rest 
des Ganzen. Die Geschwindigkeit reicht zumeist völlig aus.

W.S.

von dasrotemopped (Gast)


Bewertung
0 lesenswert
nicht lesenswert
8 bit und Display ist ein weites Feld.
https://atmelcorporation.wordpress.com/2015/05/28/build-an-inexpensive-handheld-gaming-console-with-atmega328/
Auch ein kleiner 8-bit Arduino kann was.

Obwohl ich einen STM32 mit TFT bevorzuge würde ich das pauschale 
Ablehnen eines Displays an einen 8-bitter nicht unterstützen. Der C64 
war ja auch nicht ohne Grund trotz seiner 8-bit ein Grafikwunder zu 
seiner Zeit.

Gruß,
dasrotemopped.

von Dominik (Gast)


Bewertung
0 lesenswert
nicht lesenswert
dasrotemopped schrieb:
> würde ich das pauschale
> Ablehnen eines Displays an einen 8-bitter nicht unterstützen.

Sehe ich auch so, kommt halt immer drauf an, was man machen will,
und wie man es dann genau macht.

Ich habe auch schon ein LCD-Display mit Schieberegister an einen Tiny45 
gefriemelt, ob man sich dann einen Gefallen getan hat oder besser was 
größeres genommen hätte, muss man von Fall zu Fall mit sich selber 
ausmachen.

Gruß Domihik

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.