Forum: Mikrocontroller und Digitale Elektronik Fragen zu Grafik-LCD 128x64?


von Thomas (kosmos)


Lesenswert?

ich habe mal eine Frage zu diesen Grafik LCDs, bisher habe ich nur diese 
20x2...Teile verwendet.

1. Muss ich bei 128x64 8kByte RAM haben um den kompletten 
Bildschirminhalt vorhalten zu können und ihn dann zu übertragen?

2. Oder kann man wie bisher einzelne Buchstaben/Ziffern übertragen und 
ggf. eine Schriftgröße vorgeben.

Im Prinzip möchte ich nur 2 Temperaturwerte etwas größer darstellen und 
ggf. ein Menü zum durchblättern aufrufen.

Gibts ein gutes Tutorial, das ihr empfehlen könnt?

von Olaf (Gast)


Lesenswert?

> 1. Muss ich bei 128x64 8kByte RAM haben um den kompletten
> Bildschirminhalt vorhalten zu können und ihn dann zu übertragen?

Manche Display koenntest du parallel ansprechen. Dann kannst du sie 
auslesen und brauchst kein internes Ram. Es gibt aber auch viele die 
koennen nur SPI und selbst wenn nicht, man will eigentlich nichts 
parallel machen. Daher brauchst du 128x64Bit.

> 2. Oder kann man wie bisher einzelne Buchstaben/Ziffern übertragen und
> ggf. eine Schriftgröße vorgeben.

Nein. Im Gegenteil du brauchst sogar noch einen Font in deinem Flashrom.

Olaf

von Maxim B. (max182)


Lesenswert?

Thomas O. schrieb:
> 1. Muss ich bei 128x64 8kByte RAM haben um den kompletten
> Bildschirminhalt vorhalten zu können und ihn dann zu übertragen?

Hier geht es nicht um Bytes sondern um bit. Deshalb nur 1 kByte. Aber 
extra RAM braucht man dafür nicht. Man kann immer aus dem Bildschirm 
lesen, modifizieren und zurück schreiben. Das ist notwendig, wenn man 
Byte-"Streifen" des Bildschirms nicht beachten und Zeichen dazwischen 
schreiben will. Ich habe auf meiner Platine DIP128-6 von EA. Ich habe 
drei verschiedene Fonts gemacht und ich kann sie punktgenau platzieren. 
Das ist möglich gerade durch Lesen-Ändern-Zurückschreiben.

Thomas O. schrieb:
> 2. Oder kann man wie bisher einzelne Buchstaben/Ziffern übertragen und
> ggf. eine Schriftgröße vorgeben.
Du muß alles selber machen, aus gespeicherten Muster Punkt für Punkt. 
Fertige Zeichensatz gibt es im Graphik-LCD nicht. Dafür aber hast du 
volle Freiheit. Als Beispiel: in Symbol-LCD ist untere Hälfte von 
Zeichen immer gleich, die obere aber hat viele Varianten, damit man 
nationale Sprachen verwenden kann. So kann man für Deutsch Umläute haben 
oder auch kyrillische Buchstaben für Russisch. Aber nicht gleichzeitig! 
Mit Graphik-LCD hast du alles immer.
Du kannst beliebige Schriftgröße haben. Alles ist in deinen Händen. Du 
bekommst alles, was du einprogrammierst.

von Ben B. (Firma: Funkenflug Industries) (stromkraft)


Lesenswert?

Es sollte inzwischen auch solche Displays geben, die ein wenig 
intelligenter sind und z.B. einen Zeichensatz selbst vorhalten (kenne 
keines, aber ich würde es der DOG-Reihe oder so zutrauen).

Die 8K RAM sind nur empfehleswert wenn Du Änderungen am Display-Inhalt 
vornehmen willst und keine schnelle Schnittstelle hast. Dann macht sich 
so ein Framebuffer gut, ohne mußt Du erst die betroffenen RAM-Zellen vom 
Display in den Controller laden, ändern und zurückschreiben.

Die 8K RAM sind bei einfachen Pixeln auch nur 1Kbyte, da pro Byte acht 
Pixel gespeichert werden. 1K RAM hat fast jeder Controller übrig, auf 
dem sich die Programmierung mit grafischen Displays lohnt.

von Stefan F. (Gast)


Lesenswert?

Mal angenommen, du meinst OLED mit SSD1306 Controller, dann...

kannst du direkt in den Speicher des Displays schreiben. Pufferspeicher 
ist nicht zwingend erforderlich. Über SPI kann man angeblich schreiben 
und lesen (habe ich nicht ausprobiert).

Über die I²C Schnittstelle kann man nur schreiben, nicht lesen. In 
letzter Konsequenz bewirkt dies, dass jede Ausgabe im 8-Pixelzeilen 
Raster erfolgen muss. Damit könntest du zum Beispiel 8 Zeilen Text mit 
einem kleinen Font 8x5 oder 4 Zeilen mit einem großen 16x10 Font 
darstellen. Oder Bilder deren Höhe genau ein vielfaches von 8 ist.

Für Ausgaben mit anderen Abmessungen muss man das RAM auslesen und die 
neuen Ausgaben in das existierende Bild hinein zeichnen. Das geht wie 
gesagt mit I²C gar nicht. Mit SPI geht es, aber ziemlich umständlich und 
langsam.

Deswegen benutzen die meisten Bibliotheken einen Puffer im RAM, auf den 
man jederzeit wahlfreien Zugriff hat. Die Ausgabe wird im RAM 
vorbereitet und dann zum Display gesendet.

128x64 sind 8192 Pixel, also 1 Kilobyte.

von Maxim B. (max182)


Lesenswert?

Wenn man interne Mikrocontroller-SRAM dafür benutzt, geht es wohl etwas 
schneller, wenn man zwischen Byte-Streifen schreiben muß. Aber es geht 
auch ohne SRAM. Hier sind Symbol- und Graphik-LCD etwa gleich: 
Graphik-LCD braucht keine Wartezeit nach jedem Befehl oder 
Datenschreiben. Dafür sind deutlich mehr Zugriffe notwendig: auch wenn 
man innerhalb von Byte-Streifen schreibt (und somit kein Lesen 
notwendig), braucht ein Symbol immer noch 6 Byte (5x8 Symbol + 1 byte 
dazwischen), die einzeln zu schreiben sind.

: Bearbeitet durch User
von Maxim B. (max182)


Angehängte Dateien:

Lesenswert?

Stefan ⛄ F. schrieb:
> Über SPI kann man angeblich schreiben
> und lesen (habe ich nicht ausprobiert).

Man kann mit einfachen Logik-IC aus jedem Bildschirm einen 
SPI-Bildschirm machen. Hier ist ein Beispiel dafür.

R49-R56 sind eigentlich nicht notwendig. Hier sind sie für mögliche 
Fehler beim Programmieren gedacht.

Es werden über SPI immer 2 Bytes geschrieben: Data und Control. Dabei 
ist erste empfangene Byte (falls vorher Bildschirm auf Lesen eingestellt 
wurde) auch Data aus dem Bildschirm. Für Lesen braucht man E-Strob 
zweimal, deshalb braucht Lesen mehr Zugriffe als einfaches Schreiben.

Schreiben:
1
// Treiber fuer Schreiben
2
void graph_128x64_write(u8 data, u8 dienst){
3
4
// liest data aus Puffer, schreibt Data und Dienstport
5
//  spi_intern_start();
6
  spi_master_transmit(data);
7
  spi_master_transmit(dienst);
8
  spi_intern_start();
9
  spi_intern_stop();  
10
11
}
12
13
void graph_128x64_writedata(u8 data, graph_enmode_t haelfte){
14
// haelfte == EN1 > E1, haelfte == EN2 > E2
15
// haelfte == EN12 > E1+E2
16
  u8 temp = GRAPH_128X64_DI;  // DI>1
17
  u8 temp1 = temp;
18
19
  switch(haelfte){
20
    case EN1 : 
21
      {
22
        temp1 |= GRAPH_128X64_E1;
23
        break;
24
      }
25
    case EN2 : 
26
      {
27
        temp1 |= GRAPH_128X64_E2;
28
        break;
29
      }
30
    case EN12 :
31
    default: 
32
      {
33
        temp1 |= GRAPH_128X64_EE;
34
      }
35
36
  }
37
  graph_128x64_write(data, temp);
38
  graph_128x64_write(data, temp1);
39
  graph_128x64_write(data, temp);
40
}

Lesen:
1
// Treiber fuer Lesen/Schreiben
2
u8 graph_128x64_writeread(u8 data, u8 dienst){
3
4
// liest data aus Puffer, schreibt Data und Dienstport
5
  u8 temp = 0;
6
  spi_intern_start();
7
  asm volatile(
8
    "lpm\n\t"
9
  );
10
  temp = spi_master_transmit(data);
11
  spi_master_transmit(dienst);
12
  spi_intern_stop();  
13
  return temp;
14
15
}
16
17
u8 graph_128x64_readdata(graph_enmode_t haelfte){
18
// haelfte == EN1 > E1, haelfte == EN2 > E2
19
20
  u8 data = 0;
21
  u8 temp = (GRAPH_128X64_DI | GRAPH_128X64_RW | GRAPH_128X64_RD); // data read
22
  u8 temp1 = temp;
23
  if(haelfte == EN1){
24
    temp1 |= GRAPH_128X64_E1;
25
  }else{
26
    temp1 |= GRAPH_128X64_E2;
27
  }
28
29
  graph_128x64_write(0, temp);  // E-Doppelimpuls
30
  graph_128x64_write(0, temp1);
31
  graph_128x64_write(0, temp);
32
  graph_128x64_write(0, temp1);
33
  graph_128x64_write(0, temp);
34
  
35
  temp &= ~(GRAPH_128X64_RW | GRAPH_128X64_RD); // data write vorbereiten
36
  data = graph_128x64_writeread(0, temp);  // E > 0, Z>0
37
  return data;
38
}

: Bearbeitet durch User
von Stefan F. (Gast)


Lesenswert?

Maxim B. schrieb:
> Hier ist ein Beispiel dafür.

Du bist auf der falschen Hochzeit, bei den Text-Displays mit HD44780 
Controller oder ähnlich.

Wir sind bei Grafik-Displays, die bereits SPI/I²C on Board haben.

von Ben B. (Firma: Funkenflug Industries) (stromkraft)


Lesenswert?

Also wenn sie echtes SPI in Hardware haben, sollten sie eigentlich 
schnell genug sein, um auch read-modify-write-Zyklen in annehmbarer Zeit 
zu schaffen.

Was sind eigentlich Byte-Streifen?

von Erich (Gast)


Lesenswert?

GOOGLE (Bildersuche) fragen:
    temperature display on graphic lcd example font
    temperature display on graphic lcd example font "source code"

Da findet sich bestimmt was...

von Maxim B. (max182)


Angehängte Dateien:

Lesenswert?

Stefan ⛄ F. schrieb:
> Für Ausgaben mit anderen Abmessungen muss man das RAM auslesen und die
> neuen Ausgaben in das existierende Bild hinein zeichnen. Das geht wie
> gesagt mit I²C gar nicht.

Man kann beliebige Graphik-LCD mit Parallelinterface über 
I2C-Erweiterung anschließen, so wie MCP23017. Das wird zwar langsamer, 
aber grundsätzlich kein Unterschied mit SPI über MCP23S17 (was ich schon 
gemacht habe. Zwar langsamer als mit 74HC-Logik, aber Schreiben und 
Lesen problemlos möglich).

Hier ist die von mir früher erprobte Schaltung. MCP23S17 kann man durch 
MCP23017 ersetzen, somit bekommt man statt SPI I2C, alles andere bleibt 
unverändert (außer Geschwindigkeit natürlich).

: Bearbeitet durch User
von Stefan F. (Gast)


Lesenswert?

Ben B. schrieb:
> Was sind eigentlich Byte-Streifen?

Ein Byte auf der Schnittstelle entspricht 8 Pixeln die untereinander 
stehen. Eine Folge von 128 Bytes füllt 8 Linien auf dem Display, das 
nennt er "Streifen". Ganz oben ist das niederwertigste Bit.

Ein L, dass die ganze Höhe des "Streifens" (8 Pixel) ausfüllen würde, 
hat die Byte-Folge: 255,128,128,128,128,128

In einem echten Font würde man natürlich unten und rechts ein Pixel 
Abstand frei halten, also: 127,64,64,64,64,0

War das verständlich?

von Maxim B. (max182)


Lesenswert?

Ben B. schrieb:
> Was sind eigentlich Byte-Streifen?

Verbreitete Graphik-LCD sind als Zeilen aus vertikalen Bytes 
organisiert. So hat man bei einem 128x64 Bildschirm 8 Byte-Zeilen je 128 
vertikalen Bytes. Die Bytes 0...63 sind mit dem Strob E1 zugreifbar, die 
restlichen mit E2.

Deshalb wenn man Zeichen willkürlich schreiben will, muß man oft auch 
für 5x8-Zeichen zwei Bytes (übereinander) lesen, einige Bit ändern und 
zurückschreiben. Etwas mehr Aufwand, aber alles funktioniert bei mir 
problemlos.

Stefan ⛄ F. schrieb:
> Du bist auf der falschen Hochzeit, bei den Text-Displays mit HD44780
> Controller oder ähnlich.

Du irrst dich. DIP128-6 von EA gehört zu einer sehr verbreiteten Art von 
Graphik-LCD. Nur daß die meisten als Module zum Löten gemacht sind und 
DIP128-6 als DIL eingesteckt sein kann.

: Bearbeitet durch User
von Olaf (Gast)


Lesenswert?

> Also wenn sie echtes SPI in Hardware haben, sollten sie eigentlich

Ach Leute. Lest ihr eigentlich auch mal Datenblaetter?

Die meisten GrafikLCD die man seriell beschreiben kann haben keinen 
Datenausgang. Die kann man wirklich nur beschreiben. Es gibt Ausnahmen, 
aber die sind selten.
Und parallel will man nicht, Aufwand, lahm, Portpinverlust, EMV.

Bei dem was heutige Mikrocontroller an Ram haben ist das aber auch kein 
Problem mehr. Frueher war das anders. So um 2005 hab ich mir mal einen 
Algorythmus geschrieben der Displayinhalte im Ram datenreduziert 
gespeichert hat. Ich hab dabei immer die letzten x (einstellbar) Bytes 
im Ram gehalten und konnte darauf dann Pixelweise zugreifen. Damit kommt 
man erstaunlich weit weil man doch das meiste zusammenhaengend ausgibt. 
So hab ich anstatt 1kb immer nur 200-300Bytes gebraucht.
Aber heute natuerlich alles unnoetig.

Olaf

von Maxim B. (max182)


Lesenswert?

Stefan ⛄ F. schrieb:
> Wir sind bei Grafik-Displays, die bereits SPI/I²C on Board haben.

TO hat darüber nichts geschrieben. Er schrieb nur von Graphik-LCD, der 
er statt bisher benutzten von ihm Symbol-LCD verwenden will.

Es gibt viele solcher Art. Ein paar Beispiele:
https://www.reichelt.de/lcd-grafikdisplay-128x64-pixel-ge-gn-m-bel--lcd-128x64gn-ab-p197566.html?&trstct=pol_5&nbc=1
https://www.reichelt.de/lcd-grafikdisplay-128x64-pixel-bl-ws-m-bel--lcd-128x64bl-aa-p197563.html?&trstct=pol_10&nbc=1
https://www.reichelt.de/lcd-dip-grafikmodul-128-x-64-punkte-lcd-128sw-dip-p53971.html?&trstct=pol_13&nbc=1

von Stefan F. (Gast)


Lesenswert?

Olaf schrieb:
> Bei dem was heutige Mikrocontroller an Ram haben ist das aber auch kein
> Problem mehr.

Es sei denn, man hält wie Manfred am ATmega328 fest. 
Beitrag "Arduino China-ProMini stürzt ab"

Für den sind die 1kB in Kombination mit einer SD Karte zum Problem 
geworden.

von Stefan F. (Gast)


Lesenswert?

Thomas, bevor hier wieder ein unnötiger Streit ausbricht, benenne deine 
Produkte um die es geht.

von Maxim B. (max182)


Lesenswert?

Es gibt auch andere Graphik-Bildschirme, farbig. So wie dieser:
https://www.ebay.de/itm/240x320-2-8-SPI-TFT-LCD-Touch-Panel-Serial-Port-Module-with-PCB-ILI9341-Xs4/283974309434?hash=item421e30163a:g:HHUAAOSwArFbz85E

Die können zwar mehr und haben von Natur aus SPI, Schreiben und Lesen, 
dazu oft auch Touch noch. Aber die sind mit AVR etwas zu langsam: 
deutlich mehr Pünkte, 240 x 320, und jeder Punkt braucht zwei oder drei 
(je nach Einstellung) Bytes über SPI zu schreiben. Ich spiele gerade mit 
so einem. Farbig, aber langsamer... Trotzdem kann man sie auch mit AVR 
verwenden.

: Bearbeitet durch User
von MCUA (Gast)


Lesenswert?

> man will eigentlich nichts parallel machen.
Ist das zu schnell?
Wo liegt das Problem grademal 8 Pins zu nem Bus heraus zu führen?

von Olaf (Gast)


Lesenswert?

> Ist das zu schnell?

Nein, das ist zu langsam. Weil internes Ram krass viel schneller ist als 
wenn du da mit Ports rumwedelst.

> Wo liegt das Problem grademal 8 Pins zu nem Bus heraus zu führen?

Kannst du nicht lesen? Es sind erstmal nicht 8Pins sondern eher 11 oder 
12. Wenn du so einen armseligen Mickrichprozessor hast wo du dir um 1k 
Gedanken machen musst dann hast du auch keine Portpins. Dann darfst du 
auch noch schoen 12Leitungen ueber die Platine, oder gar ein laengeres 
Kabel routen. Damit kannst du dann tolle EMV Probleme haben. Das tut man 
sich nicht an wenn es viel einfacher geht.

Olaf

von W.S. (Gast)


Lesenswert?

Thomas O. schrieb:
> 1. Muss ich bei 128x64 8kByte RAM haben um den kompletten
> Bildschirminhalt vorhalten zu können und ihn dann zu übertragen?

Nein. Wie gesagt, jedes Pixel = 1 Bit. Damit gilt 128*64/8=1024 Byte für 
den Bildspeicher.

Hier wurde auch ein paarmal gesagt, daß man ja den Bildspeicher des 
Displays zurücklesen, modifizieren und wieder hinschreiben kann. Ja, 
geht im Prinzip, ist aber ausgesprochen umständlich und langsam. 
Deswegen wäre mein Rat, daß du dir einen µC gönnst, der genug RAM hat, 
wo du dir einen Bildspeicher von 1 K Größe reservieren kannst, wo du 
freiweg drauf zeichnen, malen, schreiben kannst. Den dann als Block ins 
Display zu schieben, ist garantiert einfacher als sich auszurechnen, was 
man alles zurücklesen, modifizieren etc. muß, um die Kringel auf's 
Display zu kriegen, die man dort haben will.

> 2. Oder kann man wie bisher einzelne Buchstaben/Ziffern übertragen und
> ggf. eine Schriftgröße vorgeben.

Ein Grafikdisplay kann Pixel anzeigen. Wenn du Text anzeigen willst, 
dann brauchs du eine Font dafür. Oder mehrer Fonts, je nachdem, was du 
tun willst. Guck hier im Forum herum, da haben so einige Leute ihre 
Ideen von Fonts und GDI's gepostet - auch ich. Da kannst du dir 
raussuchen, was dir gefällt.

> Im Prinzip möchte ich nur 2 Temperaturwerte etwas größer darstellen und
> ggf. ein Menü zum durchblättern aufrufen.

Ach, etwa so etwas:
https://www.mikrocontroller.net/attachment/434172/Loetstation-3.jpg

Und gegebenenfalls ein Menü? Hast du dir da bereits Gedanken gemacht, 
wie du das machen willst? Jaja, natürlich geht das, aber es ist etwas 
umfänglicher als bei einem Alpha-LCD, wenn es gut aussehen und gut 
benutzbar sein soll.

 > Gibts ein gutes Tutorial, das ihr empfehlen könnt?
Nö.

W.S.

von Erwin E. (kuehlschrankheizer)


Angehängte Dateien:

Lesenswert?

Man braucht nicht unbedingt einen Buffer, solange man sich auf Text 
beschränkt:
Beitrag "SSD1306/1309 Library zum Darstellen von Text auf OLED Displays"
Der Nachteil dieser Lib ist allerdings, dass nur kleine Fonts oder 
hochskalierte damit gehen. Die kleinen Fonts kann ich bei den gängigen 
0,96" kaum lesen, die skalierten schauen prinzipbedingt nicht sonderlich 
schön aus.
Deshalb habe ich mir mal eine Lib gebaut, die größere Fonts, 
Sonderzeichen und Symbole direkt darstellen kann. Das geht auch ohne 
Buffer. Der Speicherbedarf für die Fonts muss nicht mal groß sein, wenn 
man sich auf die tatsächlich verwendeten Zeichen beschränkt.
Irgendwelche Grafiken gehen ohne Buffer dagegen kaum, zumindest nicht 
sinnvoll. Allerdings it es doch fraglich, ob man in der Realität 
Bildchen auf solchen Displays braucht. Falls ja, ist auf jeden Fall ein 
größerer Controller als ein AVR sinnvoll.

von MCUA (Gast)


Lesenswert?

>> Ist das zu schnell?
>Nein, das ist zu langsam. Weil internes Ram krass viel schneller ist als
>wenn du da mit Ports rumwedelst.
Ein einzelner (Pin)Port wird nicht langsamer, wenn es parallel 
rausgeschickt wird als wenn es über SPI rausgeschickt wird.
Zudem gibt es Ports, die mit der gleichen Frequenz wie RAM auch die Bits 
verschicken können.
Also parallel ist (wenn nicht mehrere Gbps auf einer Leitung übertragen 
werden) schneller, nicht langsamer.

Zudem oft auch, weniger Befehle und weniger CPU-Overhead nötig (je nach 
CPU, grade bei kleineren CPUs).

Einen 8-Bit-Bus mit einigen Steuerleitungen zu routen oder zu verlegen 
stellt keinerlei EMV-Problem dar, wenn man es richtig macht.

von Stefan F. (Gast)


Lesenswert?

Was du da schreibst trifft nicht auf die kleinen 8bit Mikrocontroller 
zu, um die es hier zu 90% geht.

von Ben S. (bensch123)


Lesenswert?

Thomas O. schrieb:
> 2 Temperaturwerte

Ganz ehrlich? Wir leben nicht mehr in der Steinzeit, wo soll diese 
Diskussion hinführen? Selbst moderne 8bit Tiny Mikrocontroller haben 
ausreichend RAM um das ganze Bild zwischenzuhalten, vor allem will der 
TO nur zwei Temperaturwerte anzeigen.

Ich habe mit Displays von EA (Dog) und Display Elektronik gearbeitet. 
Bei beiden musste ich den Inhalt im RAM des Mikrocontrollers 
zwischenhalten.

Ist doch aber kein Problem? Genug RAM ist immer da und die Übertragung 
mit SPI ist dann richtig flott. I²C würde ich vermeiden, SPI finde ich 
einfacher, stabiler und weniger fehleranfällig.

Wer natürlich auf Herausforderungen steht und die Ressourcen des 
Mikrocontrollers zu eng wählt, der hat selber Schuld.

W.S. schrieb:
> Deswegen wäre mein Rat, daß du dir einen µC gönnst, der genug RAM hat,
> wo du dir einen Bildspeicher von 1 K Größe reservieren kannst, wo du
> freiweg drauf zeichnen, malen, schreiben kannst. Den dann als Block ins
> Display zu schieben, ist garantiert einfacher als sich auszurechnen, was
> man alles zurücklesen, modifizieren etc. muß, um die Kringel auf's
> Display zu kriegen, die man dort haben will.

So siehts aus. Und bitte programmiere nicht in Assembler ...

: Bearbeitet durch User
von Stefan F. (Gast)


Lesenswert?

Ben S. schrieb:
> Selbst moderne 8bit Tiny Mikrocontroller haben
> ausreichend RAM um das ganze Bild zwischenzuhalten

Nur der eine halt nicht, den eine gewisse italienische Firma verwendet 
hat, um sie alle zu knechten.

von Ben S. (bensch123)


Lesenswert?

Stefan ⛄ F. schrieb:
> Nur der eine halt nicht, den eine gewisse italienische Firma verwendet
> hat, um sie alle zu knechten.

Keine Ahnung welchen du genau meinst, da für mich Arduino wirklich nur 
was für den Einstiegsbastler ist der sich hoffentlich schnell davon 
abwendet.

Aber selbst der ATmega328P hat 2kByte, was für seine Anforderungen 
durchaus reichen sollte. Aber wie gesagt gibt es deutlich bessere 
Alternativen und es gibt auch Arduino mit STM32.

von Stefan F. (Gast)


Lesenswert?

Ben S. schrieb:
> Keine Ahnung welchen du genau meinst, da für mich Arduino ...
> Aber selbst der ATmega328P hat 2kByte

Na also, du weisst es ja doch.

Ja er hat 2kB und das reicht für ein kleines Display. Wenn er sonst 
nicht viel zu tun hat. Das ist aber der Knackpunkt. Dinge mit solchen 
Displays haben sinnvollerweise meistens doch sehr viel mehr zu tun, als 
nur das Display anzusteuern.

> Aber wie gesagt gibt es deutlich bessere Alternativen

ja

von Thomas (kosmos)


Lesenswert?

ich dachte an soetwas
https://www.aliexpress.com/item/4000388237877.html

angegeben ist ein ST9720, werde mir mal das Datenblatt ziehen, klar sind 
ja nur 1 kByte für eine Seite das sieht dann schon besser aus.

von Ben S. (bensch123)


Lesenswert?

Thomas O. schrieb:
> https://www.aliexpress.com/item/4000388237877.html

Kann man (möglicherweise) prinzipiell benutzen.

Schau auch mal hier:
Filtere dort nach 128x64 und SPI. Da gibt dann die unterschiedlichsten 
Modelle mit verschiedenen Dimensionen, LED Beleuchtungsfarbe, etc.
https://www.display-elektronik.de/Products_LCD_Graphic-mono.html

Z.B: DEM 128064F SBH-PW-N

: Bearbeitet durch User
von Manfred (Gast)


Lesenswert?

Erwin E. schrieb:
> Deshalb habe ich mir mal eine Lib gebaut, die größere Fonts,
> Sonderzeichen und Symbole direkt darstellen kann. Das geht auch ohne
> Buffer. Der Speicherbedarf für die Fonts muss nicht mal groß sein, wenn
> man sich auf die tatsächlich verwendeten Zeichen beschränkt.

Magst Du mir dazu etwas mehr verraten und die Lib zeigen?

von MCUA (Gast)


Lesenswert?

SPI-Probleme bei (bisherigen, nicht die allerneusten) AVRs:

1.) SPI -TX hat keinen einzigen Byte-Buffer
...(es kann also nichtmal mit einem Jitter von +- der Länge eines
....ausgeschriebenen (SPI)Bytes in das SPI-Modul geschrieben werden)
...(evtl. kann man (wenn im Master-Mode) taktgenau 'warten' (diese Takte
....gehen aber verloren) und so weitere Bytes an TX rausschicken)
...(selbst ein winziger STM8 ist hier besser, und es gibt faktisch keine
....neuere CPU, die hier nicht wenigstens einen Buffer hat)
2.) Die SPI kann zwar einen EndOfTransm-INT auslösen, nur die
...Interrupt-Möglichkeiten sind sehr schlecht,
...keine setzbaren INT-Prioritäten möglich
...(somit muss u.U. eine riesige Menge (!) an Takt-Cyclen gewartet 
werden
....(was ja genaugenommen schon einen Gau darstellt), bis höher prioris.
....ISRs fertig sind)
3.) DMA oder Ähnliches? gibts nicht.
...(die CPU muss also heran gezogen werden)

Also noch schlechter kann es eine CPU bei SPI-Transfer nicht mehr 
machen!

Man könnte u.a. wenn nötig SPI-Hardware diskret an nen AVR dranhängen.

von Maxim B. (max182)


Lesenswert?

Erwin E. schrieb:
> Man braucht nicht unbedingt einen Buffer, solange man sich auf Text
> beschränkt:

Dann hat Graphik-LCD wenig Sinn.
Wenn man schon von Symbol-LCD zu Graphik-LCD wechselt, sollte Lib 
mindestens können, Linien und einfache Figuren (Viereck und Kreis, 
gestrichen und nicht) zeigen.

Ich verstehe die Panik nicht: auch mit Lesen und schreiben, und quer 
gegen Byte-Zeilen (d.h. doppel so viel schreiben und lesen) schafft Lib 
bei mir mit F_CPU=16MHz 5 ms/Symbol. Gegen 1 ms/Symbol für Symbol-LCD. 
Ja, das ist mehr, aber immer noch zu verkraften. Für vollen Bildschirm 
und 5x8 Zeichen wird das 5 ms  21 Zeichen pro Zeile  8 Zeilen ca. 840 
ms (und nur ein Drittel, wenn man innerhalb von Byte-Zeilen bleibt und 
nichts liest).
Wenn man anders als bei mir Bildschirm nicht über SPI sondern direkt 
anspricht (12 Pins werden gebraucht, aber 10 davon (alle außer E1 und 
E2) können auch andere Geräte bedienen, z.B. andere LCD oder Tasten (für 
Tasten empfehle ich 4k7 Widerstand seriell)), wird nicht viel schneller, 
da LCD-Zyklus mindestens 1 us lang sein sollte, es muß auch viel 
berechnet werden, um ein Symbol aus Flash zu holen und auszugeben.

MCUA schrieb:
> Also noch schlechter kann es eine CPU bei SPI-Transfer nicht mehr
> machen!

Wenn du SPI mit ISR benutzt, schon. Mit SCK = F_CPU/2 hat das natürlich 
wenig Sinn, aber wenn man Bildschirm mit eingebauten SPI benutzt, welche 
oft auf nur 2 MHz oder auch niedriger beschränkt sind, dann kann ISR 
helfen. Daten und Befehle in Puffer und los, CPU macht was anderes, z.B. 
nächste Daten für LCD.

: Bearbeitet durch User
von Stefan F. (Gast)


Lesenswert?

Maxim, deine Zahlen passen vermutlich auf dein Display, aber nicht auf 
ein SSD1306. Das ist so schnell, darauf kann man Animationen und 
Soft-Scrolling darstellen, wenn man Puffer verwendet. Da reden wir von 
ganz andere Zeiten.

von Maxim B. (max182)


Lesenswert?

Stefan ⛄ F. schrieb:
> Da reden wir von
> ganz andere Zeiten.

Aber gängige Symbol-LCD gehören zu "meinen" Zeiten auch. Wenn TO einen 
Symbolbildschirm für einen Graphik-Bildschirm tauschen will, sollte er 
Vergleichbares vergleichen. Erst dann wird klar, was gewinnt man und was 
verliert man, wenn Rechenleistung bei Symbolausgabe aus dem inneren 
Controller von Symbol-LCD auf Mikrocontroller (ATMega wie TO macht) 
überlagert wird.

: Bearbeitet durch User
von Stefan F. (Gast)


Lesenswert?

Maxim B. schrieb:
> Aber gängige Symbol-LCD gehören zu "meinen" Zeiten auch. Wenn TO einen
> Symbolbildschirm für einen Graphik-Bildschirm tauschen will, sollte er
> Vergleichbares vergleichen.

Ja.

von Maxim B. (max182)


Lesenswert?

TO könnte vielleicht versuchen (wenn Geschwindigkeit für ihn so wichtig 
ist) für Bildschirm separaten Mikrocontroller verwenden, der 
Routinenarbeit macht und Eingangspuffer hat. Dann kann 
Haupt-Mikrocontroller ganz bequem z.B. über TWI Befehle senden, so etwa: 
"zeichne mir mal eine Linie von dem Punkt xy bis zu dem Punkt xy" oder 
"schreib mir mal Text "xxx".
Aber das ist eine schon viel anspruchsvollere Aufgabe...

: Bearbeitet durch User
von Erwin E. (kuehlschrankheizer)


Lesenswert?

Maxim B. schrieb:
> Erwin E. schrieb:
>> Man braucht nicht unbedingt einen Buffer, solange man sich auf Text
>> beschränkt:
>
> Dann hat Graphik-LCD wenig Sinn.
> Wenn man schon von Symbol-LCD zu Graphik-LCD wechselt, sollte Lib
> mindestens können, Linien und einfache Figuren (Viereck und Kreis,
> gestrichen und nicht) zeigen.

Was eine LCD-Lib mindestens können muss, hängt nur von der Anwendung ab. 
Braucht (!= möchte) man eine Grafikausgabe, nimmt man eben eine Lib die 
das bietet, sinnvollerweise auch gleich einen Controller, der die 
nötigen Ressourcen hat. Für viele Anwendungen, wo man bisher 
Characterdisplays verbaut hat, wird man meistens ohne Grafik auskommen.

Vierecke, Kreise und Sterne sind nett für Demos, aber bei realen Geräten 
z.B. einer Steuerung stören irgendwelche kaum erkennbaren Bildchen doch 
mehr als sie nutzen. Bei Displays mit höherer Auflösung sieht das 
natürlich wieder anders aus.
Wobei es Anwendungen gibt, wo Symbole nützlich sind. Beispiel: 
Transistortester. Aber auch dort braucht man keine Sternchen oder Kreise 
zeichnen, es genügt ein fester Satz von Symbolen. Schriften können auf 
Grafikdisplays wesentlich besser lesbarer sein als auf 
Charakterdisplays, spätestens wenn Umlaute benötigt werden. Darin sehe 
ich einen echten Mehrwert von Grafikdisplays gegenüber 
Charakterdisplays. Beim Batteriebetrieb haben OLEDs aufgrund des 
geringen Stromverbrauchs auch wieder einen Sinn, obwohl nur Schrift 
ausgegeben wird.

von Maxim B. (max182)


Lesenswert?

Ich spiele z.Z. mit einer selbstgemachten Platine. Ich bin ja kein 
Profi-Elektroniker, ich bin ein Musiker. Deshalb kann ich mir erlauben, 
zu machen, was ich möchte :)

Symbol-LCD geht ohne Frage. Graphik-LCD auch, obwohl deutlich mehr Code. 
Symbol-LCD über TWI mit ISR geht auch gut, obwohl für wirklich bequeme 
Arbeit zwei Puffer gemacht: TWI-Puffer und noch extra LCD-Puffer, für 
Daten und Befehle. Wenn nur TWI-Puffer, dann wäre innere SRAM zu stark 
genutzt, 18 Bytes pro Command oder Data. Dabei sollte Puffer mindestens 
so groß sein, um 80 Symbole und 4 Command speichern zu können (80 
Symbole und 4 Cursor-Einstellungen), sonst gibt es Verluste.
Aber noch ILI9341-Bildschirm 240x320 Pünkte dazu scheint System schon 
etwas zu übelasten: Drehgeber ist wie im Schlaf. Vielleicht sollte 
diesen Bildschirm im Hintergrund über Puffer arbeiten, d.h. erst wenn 
keine anderen Aufgaben zu erledigen sind? Hier habe ich etwa 
theoretische Interesse. Klar: wenn ich etwas weniger schalte (z.B. ein 
oder zwei Bildschirme weg), wird Drehgeber wieder in Ordnung. Aber ob 
das auch so noch geht? Schließlich ist unwichtig, ob ein paar Ziffer auf 
dem Farb-TFT in 100 ms oder in 500 ms kommen... Dabei verwende ich noch 
kein Dispatcher, nur einfache Hauptschleife...

Kontrollschleife ist bei mir so:
1. Jede Sekunde kommt ISR von DS3234. Datum, Zeit und Raumtemperatur 
werden gelesen und auf allen 4 Bildschirmen, jeder anders als die 
anderen, ausgegeben.
2. Drehgeber wird jede 1ms gefragt. Daraus wird u16-Zähler geändert und 
auf zwei verschiedenen Anzeigen mit MAX7219 ausgegeben, auch auf allen 
Bildschirmen. Darüber hinaus wird die Zahl in SPI-SRAM 23LCV1024 
geschickt, wieder gelesen und auch gezeigt.
3. Tasten werden jede 10 ms gefragt. Wenn gedruckt, wird auf allen 
Bildschirmen Name von Taste ausgegeben, und auf den Graphik-Bildschirmen 
auch verschiedene Figuren, je nach der Taste.

So foltere ich z.Z. eine AT Mega324PA.

Gedacht ist alles dafür, um verschiedene Eingabe- und Ausgabemittel auf 
bequemere Weise arbeitsbereit zu machen: damit ich verschiedene externe 
Module testen könnte. Deshalb ist auch Graphik-LCD gerade das, was ich 
z.Z. quäle (glücklicherweise hat Bildschirm kein Piepser und kann sich 
nicht beschweren :) ).

von Maxim B. (max182)


Lesenswert?

Erwin E. schrieb:
> Was eine LCD-Lib mindestens können muss, hängt nur von der Anwendung ab.

Ich finde es sinnvoll, EINMAL eine Lib zu machen (und gründlich 
überprüfen), die alles macht. Und später diese gut geprüfte Lib immer 
verwenden. Wenn man fürchtet, zu viel unnützlichen Code in einigen 
Anwendungen zu haben, so kann man per #ifdef - #ifndef verschiedene 
Teile von Lib ausschalten.

Immer für ein neues Gerät neue Lib zu schreiben (und zu überprüfen) 
finde ich nicht sinnvoll. Denn so außer vergeudeter Zeit wird auch 
notwendig, bei jedem Gerät ausreichende Debug-Möglichkeiten vorzusehen, 
die sonst auf vernünftigen Minimum reduziert sein könnten.
Daraus kommt Forderung, sowohl Text wie auch geometrischen Figuren und 
einzenle Pünkte möglich zu machen.

Lib sollte jeder möglichst selber schreiben oder mindestens selber 
überprüfen und korrigieren: nur so kann man ausreichend gut vorstellen, 
was und wie eigentlich gemacht wird.

: Bearbeitet durch User
von Erwin E. (kuehlschrankheizer)


Angehängte Dateien:

Lesenswert?

Manfred schrieb:
> Magst Du mir dazu etwas mehr verraten und die Lib zeigen?

Wollen tät ich schon, aber können tu ich nicht. Na ja, ich tu's 
trotzdem, obwohl manches noch ziemlich unfertig ist. Es fehlt leider 
auch (noch) an einer Doku. Das derzeitig Vorhandene hänge ich an. 
Disclaimer: Das ist mein Erstlingswerk in C.

Momentan funktioniert die Lib nur mit OLEDs mit SSD1306, die über I²C 
angesteuert werden.

Mit dem Fontconverter lcd-image-converter 
https://sourceforge.net/projects/lcd-image-converter/ rastere ich den 
gewünschten TTF-Font in der benötigten Größe. Proportional oder 
unproportional ist dabei egal. Es sind auch beliebige Sonderzeichen 
möglich wie Batteriesymbole oder was auch immer sonst im Font enthalten 
ist.
Das Batteriesymbol im Foto ist ein Symbol aus dem verwendeten 
Zeichensatz und wird im Code genau wie ein Buchstabe behandelt.

Als nächstes erstelle ich eine csv-Datei (Excel), in der festlegt wird, 
welche Unicodes benötigt werden und welchem ASCII-Code sie jeweils 
zugewiesen werden sollen. Das ist für Sonderzeichen und Symbole wichtig.

Bei größeren Schriften binde ich nur diejenigen Zeichen ein, die ich 
tatsächlich im jeweiligen Projekt brauche. Bei einem Thermometer würden 
z.B. nur die Ziffern sowie '°' und 'C' in großer Schrift benötigt. Also 
binde ich auch nur diese Zeichen ein, was eine Menge Platz spart.
Ein Haken dabei ist, dass für jede verwendetet Zeichengröße eine 
Sprungtabelle von ca. 450 Byte Größe benötigt wird, zusätzlich zu den 
Fontdaten.

Mit VC habe ich ein Tool geschrieben (sehr, sehr Q&D!), das aus den 
gerasterten Fonts die .h Files generiert, welche dann von der Lib 
eingebunden werden.

Es sind gleichzeitig Fonts mit 8, 16, 24, 32, 48 und 64 Größe möglich, 
nur abhängig von der Größe des verfügbaren Flashspeichers, jedoch nur 
eine Schriftart pro Fontgröße.

Grafik ist derzeit nicht möglich, es gehen lediglich vertikale Linien. 
Das liegt an der Organisation des Grafikrams des OLED. Es ist aber 
denkbar sich mit Blockgrafik zu behelfen, wenn Rahmen oder ähnliches 
gebraucht werden. Habe ich aber noch nicht getestet.
Die Funktion zur rechtsbündigen Ausgabe von Text ist noch buggy - bei 
proportionalen Fonts gibt es bei sehr breiten Zeichen 
Darstellungsfehler.

Irgendwann werde ich die Lib nebst Tools abrunden, dokumentieren und 
hier vorstellen, das wird sich aber noch etwas hinziehen. Es gibt auch 
noch einige Ideen für Erweiterungen.

Sorry, falsches Foto angehängt. Siehe nächsten Beitrag.

: Bearbeitet durch User
von Erwin E. (kuehlschrankheizer)


Angehängte Dateien:

Lesenswert?

Hier das andere Foto, sorry.

von MCUA (Gast)


Lesenswert?

> .. können auch andere Geräte bedienen, z.B. andere LCD oder Tasten
Ja. Bus-System (komplizierter).
Mit Zwischenspeicher am BusNode kann man auch weitaus höhere Frequenzen 
betreiben.

>Daten und Befehle in Puffer und los, CPU macht was anderes, z.B.
>nächste Daten für LCD.
Der AVR-SPI-TX hat kein Puffer.

>Drehgeber ist wie im Schlaf.
Tja so ist das bei falschem Timing.
Für Echtzeit kann man es nicht benutzen.
Falsche INT-Handhabung.

>So foltere ich z.Z. eine AT Mega324PA.
Nein, der foltert dich.

von Maxim B. (max182)


Lesenswert?

MCUA schrieb:
> Ja. Bus-System (komplizierter).

Nicht unbedingt Bus. Tasten kann man einfach so an diese Linien (außer 
E1 und E2) anbinden. Damit Tasten kein Kurzschluß machen, Widerstand 
seriell. Um Tastenzustand abzulesen: E1=E2=0, DDR = 0, PORT = 1 (somit 
Rpu Ein), ein bißchen Warten (Rpu * (Cpin + C_Lin)), Pin einlesen. Da 
Rpu von 20k bis 50k sein kann, dürfen serielle Widerstände 4k7 nicht 
überschreiten. Viel kleiner sind die auch nicht sinnvoll, da unnötige 
Last für Pin bei Datenaustausch.

von Manfred (Gast)


Lesenswert?

Erwin E. schrieb:
> Na ja, ich tu's trotzdem,

Erstmal danke!
Ich schaue mir das die nächsten Tage an.

von Maxim B. (max182)


Lesenswert?

MCUA schrieb:
> Tja so ist das bei falschem Timing.
> Für Echtzeit kann man es nicht benutzen.
> Falsche INT-Handhabung.

Wie wirst du das anders machen? Eine Zeile 7 Symbole Font 16x10 Größe 5 
(d.h. aus jedem Punkt wird 5x5 Pünkte gemacht) dauert 5120389 Z. oder 
bei F_CPU=16 MHz ca. 320 ms. Wird Drehgeber nicht jede ms abgefragt 
sondern jede 20 ms, bringt das wenig.

von Joachim B. (jar)


Angehängte Dateien:

Lesenswert?

am nano nutze ich gerne die Nokia5110 mit dieser sparsamen LIB
http://www.rinkydinkelectronics.com/library.php?id=44

RTC und Display auf dem Steckbrett am nano ohne weitere Kabel
Helligkeit per PWM (per Kommando) und Kontrast per Kommando

: Bearbeitet durch User
von W.S. (Gast)


Angehängte Dateien:

Lesenswert?

Erwin E. schrieb:
> Disclaimer: Das ist mein Erstlingswerk in C.

Ja, man sieht das.
Nun, du kannst natürlich tun was dir beliebt, aber ich würde es an 
deiner Stelle komplett anders machen. Erstens würde ich generell trennen 
zwischen dem Lowlevel-Treiber, der für das physische Ansteuern des 
Displays verantwortlich ist und dem GDI, also dem Treiber, der die 
ganzen grafischen Funktionen beinhaltet und den diversen Fonts, die 
ebenfalls völlig separate Dinge sein sollten.

Deine arial32.h ist viel zu umfänglich. Schreib ein GDI, das mit einem 
sinnvollen Font-Format zurechtkommt und separate Fontdateien, die dieses 
Fontformat bieten, so daß du allenfalls im GDI sowas wie
extern char Helvetica16[];
schreiben mußt. Keine aufgeblasene Headerdatei.
Hier mal zwei Links:
https://www.mikrocontroller.net/attachment/436998/Fonts_machen.zip
und
http://www.mikrocontroller.net/attachment/301321/Fonts-machen-2.zip
Damit kannst du so ziemlich alles an Fonts machen, was dir beliebt, egal 
ob nun variable oder feste Breite, tatsächliche Textzeichen oder Icons 
usw.
Für dein Display wäre dann nur noch eine Funktion
void CgPixel_at(X, Y, mode)
von dir beizusteuern und fertig. Das mode ist hier bei 
Monochrom-Displays eben schwarz, weiß oder invert und bei Farbdisplays 
wäre es die Farbe bzw. ein Index in eine Farbpalette.

Ich mache es immer so, daß ich (wie oben geschrieben) einen 
Grafikspeicher im RAM anlege, wo das GDI drauf herumzeichnet. Die 
Funktion CgPixel setzt eine boolean Variable, die damit anzeigt, daß das 
Display zu aktualisieren ist. Wenn die so alle 10 ms mal abgefragt wird, 
reicht das aus. Anbei als Beispiel ein altes GDI für nen Kinetis, damals 
mit reinem Soft-Treiber für das Display. Aber der Kinetis lief ja auch 
mit einer ordentlichen Taktfrequenz.

W.S.

von Erwin E. (kuehlschrankheizer)


Lesenswert?

W.S. schrieb:
> aber ich würde es an deiner Stelle komplett anders machen.
Scheinbar machen es alle anders. Entweder so, wie du vorschlägst, mit 
einem Buffer in Displaygröße oder indem ausschließlich mit Text einer 
vorgegebenen Größe gearbeitet wird. Meistens können die kleinen Fonts 
noch geometrisch skaliert werden, was aber unschön aussieht.
Beide Ansätze gefallen mir nicht. Wohlgemerkt, das gilt für AVR oder 
andere kleine Controller. Wenn ein schneller 32Bit Controller mit viel 
RAM benutzt wird, ist ist ein Buffer die sinnvolle Lösung.

Was ich erreichen wollte:
* Es sollen gleichzeitig Fonts verschiedener Größe benutzt werden können
* Im Flash sollen nur diejenigen Zeichen abgelegt werden, die 
tatsächlich benötigt werden
* Es sollen Zeichen mit beliebige Unicodes verwendet werden können
* Es soll kein RAM für einen Framebuffer benutzt werden
Allen diese Vorgaben habe ich in meiner Lib umgesetzt.

Grafische Funktionen brauche ich nicht. Lediglich horizontale Linien 
wären mitunter nett, aber wirklich wichtig waren sie bisher nicht. Falls 
ich wirklich mal Grafikfunktionen brauche, nehme ich eine der fertigen 
Libraries.

> Erstens würde ich generell trennen [..] Lowlevel-Treiber [..] physische 
Ansteuern des
> Displays [GDI]
D'accord, wenn verschiedene Displaycontroller sowie Grafikfunktionen mit 
der Lib benutzt werden sollen. Ob höher auflösende TFT-Displays 
überhaupt sinnvoll an einem AVR betrieben werden können? Das werde ich 
bei Gelegenheit mal testen. Was ich bisher gesehen habe, hat mich 
geschwindigkeitsmäßig nicht überzeugt.

> Deine arial32.h ist viel zu umfänglich.
Welchen Nachteil haben große Headerdateien? Du hast deine Fontdaten in 
.c Files abgelegt, wenn ich das richtig verstehe. Ich habe sie in 
Headerdateien. Macht das einen Unterschied?
Außerdem sieht es für mich aus, als würden deine Fontdaten alle Zeichen 
fortlaufend von z.B 0x20 bis 0xnn enthalten. Landen die vollständig im 
Flash? Das wollte ich gerade vermeiden. Allerdings brauche ich pro 
Schriftgröße eine Tabelle, die recht groß ist. Das amortisiert sich aber 
bei großen Fonts sehr schnell.

> Ich mache es immer so, daß ich (wie oben geschrieben) einen
> Grafikspeicher im RAM anlege, wo das GDI drauf herumzeichnet.
Das ist der gängige Ansatz, aber aus meiner Sicht ist der für kleine 
Controller unnötig - falls man keine Grafikfunktionen braucht.
Spätestens bei einem 320x240 TFT kann dieser Weg nicht eingeschlagen 
werden, die kleinen Controller haben einfach nicht genug RAM für den 
nötigen Buffer. 16er oder 32er Schriften könnten aber auch bei einem TFT 
von der Geschwindigkeit her noch praktikabel sein, das möchte ich 
irgendwann mal testen.

Mit welchem Programm erzeugst du eigentlich die Fonts? Ich nehme 
lcd-immage-converter. Falls es da was besseres gibt, bin ich 
interessiert, obwohl das jetzige Tool gut funktioniert.

von Maxim B. (max182)


Lesenswert?

Hier sind doch Unterschiede in Bildschirm-Structur wichtig.
Wenn ein Bildschirm nach Byte-Linien innere Ordnung hat, dann wird immer 
mit Bytes geschrieben, gleichzeitig je 8 Punkte. Um einen Punkt zu 
ändern und andere Punkte unverändert lassen, sollte man entweder 
lesen-schreiben oder RAM-Puffer benutzen.
Falls aber Bildschirm nach Punkten organisiert ist (wie z.B. ILI9341), 
kann man sowieso jeden Punkt unabhängig von anderen ändern. Dann ist 
weder Lesen noch RAM-Puffer notwendig. Man kann einfach einen Punkt 
beschreiben ohne Rücksicht auf alles Andere.

Deshalb kann ein RAM-Puffer für Bildschirm auf KS0108B sinnvoll sein, 
dann braucht man aber für 128x64 Bildschirm lediglich 1 kB RAM.
Für ILI9341 und Ähnlichen braucht man im Prinzip keinen RAM-Puffer.

Erwin E. schrieb:
> Welchen Nachteil haben große Headerdateien? Du hast deine Fontdaten in
> .c Files abgelegt, wenn ich das richtig verstehe. Ich habe sie in
> Headerdateien. Macht das einen Unterschied?

Unterschied kommt, wenn man gleichzeitig mehrere Bildschirme nutzt. Dann 
kann man für alle eine Schriftdatei benutzen, aber nur wenn sie in *.c 
steht. Wenn in *.h, dann hat man für jeden Bildschirm eigene Kopie von 
der gleichen Schrift.

: Bearbeitet durch User
von Stefan F. (Gast)


Lesenswert?

Was Unicode angeht, ist dir bewusst dass es Zeichen gibt, die aus 
mehreren Unicodes zusammen gesetzt sind?
Und wo willst du Fonts für beliebige Codes ablegen? Die werden doch 
mehrere MB groß!

von Erwin E. (kuehlschrankheizer)


Lesenswert?

Maxim B. schrieb:
> Wenn ein Bildschirm nach Byte-Linien innere Ordnung hat, dann wird immer
> mit Bytes geschrieben, gleichzeitig je 8 Punkte. Um einen Punkt zu
> ändern und andere Punkte unverändert lassen, sollte man entweder
> lesen-schreiben oder RAM-Puffer benutzen.
Aus diesem Grund haben meine Fonts alle eine Höhe in Vielfachen von 
acht. Damit brauche ich weder einen Buffer noch bin ich auf 
read/modify/write angewiesen. In der Breite eines Zeichens habe ich 
keine Einschränkung, was auch proportionale Fonts erlaubt.

> Falls aber Bildschirm nach Punkten organisiert ist (wie z.B. ILI9341),
> kann man sowieso jeden Punkt unabhängig von anderen ändern. Dann ist
> weder Lesen noch RAM-Puffer notwendig. Man kann einfach einen Punkt
> beschreiben ohne Rücksicht auf alles Andere.
Ob solche großen TFTs mit einem AVR sinnvoll genutzt werden können weiß 
ich nicht, das möchte ich bei Bedarf aber noch testen. Mein Gefühl sagt 
mir aber, dass das zu langsam wird.

> Deshalb kann ein RAM-Puffer für Bildschirm auf KS0108B sinnvoll sein,
> dann braucht man aber für 128x64 Bildschirm lediglich 1 kB RAM.
Kann man machen, ja. Aber, q.e.d., es geht auch sehr gut ohne Buffer.

> Unterschied kommt, wenn man gleichzeitig mehrere Bildschirme nutzt. Dann
> kann man für alle eine Schriftdatei benutzen, aber nur wenn sie in *.c
> steht. Wenn in *.h, dann hat man für jeden Bildschirm eigene Kopie von
> der gleichen Schrift.

Meinst du wirklich? Ich habe das noch nicht gemacht, sehe aber nicht, 
warum ich nicht auch mehrere Displays ansteuern könnte. Ob .c oder .h, 
auf welchem Display die Ausgabe landet, bestimmt nur die I²C-Adresse. 
Meine ich zumindest, da bin sogar ziemlich sicher.

von Erwin E. (kuehlschrankheizer)


Lesenswert?

Stefan ⛄ F. schrieb:
> Was Unicode angeht, ist dir bewusst dass es Zeichen gibt, die aus
> mehreren Unicodes zusammen gesetzt sind?
Ja, das ist mir aufgefallen. ;)
Wenn du dir das Beispielfoto vom 14.10.2020 16:51 anschaust, das 
Batteriesymbol das du dort siehst, hat den Unicode 0xeba3. Im Code wird 
das auf ASCII 0x9d gemappt. Insgesamt brauche ich 20 Symbole für die 
Batterie, die werden auf aufeinanderfolgende ASCII Codes gemappt.

> Und wo willst du Fonts für beliebige Codes ablegen? Die werden doch
> mehrere MB groß!
Wer braucht denn alle Unicodezeichen gleichzeitig? Ich binde 
diejenigen Zeichen ein, die ich tatsächlich verwende. Das muss ich mir 
natürlich bei der Entwicklung überlegen, dann lege die benötigeten 
Unicodes und ihren ASCII-Code in einer Excel-Tabelle fest und lasse mir 
die Headerdatei mit den Fontdaten erzeugen. So mache ich es auch mit den 
'normalen' Zeichen. Wenn ich nur Ziffern benötige, warum sollte ich 
Bcuhsateben einbinden?

von Maxim B. (max182)


Angehängte Dateien:

Lesenswert?

Erwin E. schrieb:
> Aus diesem Grund haben meine Fonts alle eine Höhe in Vielfachen von
> acht. Damit brauche ich weder einen Buffer noch bin ich auf
> read/modify/write angewiesen.

Dann kannst du auf dem 128x64 entweder 8 Zeilen je 21 Symbol haben, oder 
4 Zeilen je 10 Symbole, oder 2 Zeilen je 5 Symbole. Keine 
Zwischenvarianten, keine Graphik zusammen mit Symbolen (keine Linien, 
Rechtecke, Kreise - nichts).
Braucht jemand so einen Bildschirm wirklich?

Hier ein Testbeispiel, was man mit 128x64 machen kann, wenn man 
Lesen+Schreiben-Mode verwendet (darüber ist auch 20x4 LCD zu sehen).

Erwin E. schrieb:
> Ob solche großen TFTs mit einem AVR sinnvoll genutzt werden können weiß
> ich nicht, das möchte ich bei Bedarf aber noch testen. Mein Gefühl sagt
> mir aber, dass das zu langsam wird.

Ja, etwas langsam. Aber kleinere Symbole noch ganz OK. Wirklich langsam 
sind gefüllte Kreise und Symbole mit so ca. ab 30 Punkte hoch, auch 
ganzen Bildschirm mit einer Farbe füllen. Deshalb ist manchmal sinnvoll 
nicht ganzen Bildschirm zu löschen sondern über zum Löschen bestimmten 
Text einen gefüllten Rechteck mit bg_color zu zeichnen.
Dafür aber ist solche Bildschirm viel mehr informativ. Man kann 
gleichzeitig mehrere Fenster haben, z.B. für Modus und auch für Daten, 
die gezeigt sein müssen.

: Bearbeitet durch User
von Thomas F. (igel)


Lesenswert?

Erwin E. schrieb:
>> Falls aber Bildschirm nach Punkten organisiert ist (wie z.B. ILI9341),
>> kann man sowieso jeden Punkt unabhängig von anderen ändern. Dann ist
>> weder Lesen noch RAM-Puffer notwendig. Man kann einfach einen Punkt
>> beschreiben ohne Rücksicht auf alles Andere.
> Ob solche großen TFTs mit einem AVR sinnvoll genutzt werden können weiß
> ich nicht, das möchte ich bei Bedarf aber noch testen. Mein Gefühl sagt
> mir aber, dass das zu langsam wird.

Einen Film kann man nicht ansehen. Aber zum Anzeigen von Text und 
Ziffern reicht es locker:

Ich benutze an meiner Fräse ein 240x320 Farbdisplay mit 16-Bit Farbmode.

Beitrag "Re: 10stelliges 7-Segment DRO für WABECO Messschieber"

Angesteuert mit 16-Bit Bus von einem Atmega64.
Die Zahlen werden alle 100ms aktualisiert und springen so schnell dass 
keinerlei Verzögerung zu erkennen ist.

von MCUA (Gast)


Lesenswert?

>Angesteuert mit 16-Bit Bus von einem Atmega64.
Obwohl AVR nur 8-Bit-Datenbus hat ???

von Erwin E. (kuehlschrankheizer)


Lesenswert?

Thomas F. schrieb:
> Angesteuert mit 16-Bit Bus von einem Atmega64.
> Die Zahlen werden alle 100ms aktualisiert und springen so schnell dass
> keinerlei Verzögerung zu erkennen ist.

Interessant! Hast du mal getestet, ob SPI sehr viel langsamer ist?
Ich nehme an, die aktualisierst nur die jeweilige Textzeile und 
beschreibst nicht das vollständige Display? Hast du eine fertige Library 
für die Ansteuerung genommen oder selbst eine gebaut?

von W.S. (Gast)


Lesenswert?

Erwin E. schrieb:
> Welchen Nachteil haben große Headerdateien? Du hast deine Fontdaten in
> .c Files abgelegt, wenn ich das richtig verstehe. Ich habe sie in
> Headerdateien. Macht das einen Unterschied?

Ja, einen erheblichen Unterschied. Bei dir erstickt man ja geradezu in 
einer Flut von namen wie "static const tImage arial32_0x20 PROGMEM = 
...", die alle in deiner Headerdatei stehen?

Und du stellst dir vor, daß man dein Konstrukt über deine Tabelle 
"static const tImage* const charset32[] PROGMEM  =..", die aus Pointern 
besteht, verwendet.

Mit dem Auseinandernehmen deines Fonts sparst du keinerlei Platz im 
Flash ein und mir scheint, daß du auch massenweise Platz vergeigst, 
indem du für jedes Zeichen (auch für große) zeilenweise auf ganze Bytes 
auffüllst.

Obendrein besteht ein Großteil deines Codes aus "PROGMEM", was für eine 
völlige Un-Portierbarkeit sorgt. Meine Fonts könnte man hingegen selbst 
rein binär auf so ziemlich alle Plattformen portieren. Siehe unten.

> Außerdem sieht es für mich aus, als würden deine Fontdaten alle Zeichen
> fortlaufend von z.B 0x20 bis 0xnn enthalten. Landen die vollständig im
> Flash? Das wollte ich gerade vermeiden. Allerdings brauche ich pro
> Schriftgröße eine Tabelle, die recht groß ist. Das amortisiert sich aber
> bei großen Fonts sehr schnell.

Das Prinzip sollte ich dir hier mal erläutern:
1. Bei mir besteht ein Font aus einer variablen Struktur, die als 
Byte-Block gespeichert werden kann und die zum Zugriff NUR einen 
einzigen Zeiger auf ihren Anfang benötigt und auch nur einen einzigen 
Bezeichner in der gesamten Firmware einträgt.

2. Diese Struktur ist so ausgelegt, daß sie sowohl auf bigendian als 
auch auf littleendian Maschinen zu benutzen ist.

3. Jeder Font besteht aus 3 Teilen:
 - einem Fontheader
 - einer variablen Anzahl von Zeichen-Einträgen
 - den eigentlichen Glyphen

4. Der Fontheader beschreibt die Gesamthöhe, die Höhe der 
Großbuchstaben, die Höhen über und unter der gedachten Schreiblinie und 
den Bereich der enthaltenen Zeichen (also ChMin und ChMax). In dieser 
Struktur sind lediglich 8 Bit Werte für die Zeichen möglich, also 
keine Zeichencodierungen von 16 Bit und aufwärts (Unicode). Wer also 
dringend chinesische Zeichen oder Farsi benötigt, braucht ein anderes 
Fontsystem.
Innerhalb der üblichen ANSI-Zeichen von 0 bis FF ist jedoch alles 
möglich. Wenn es Lücken zwischen ChMin und ChMax gibt, wird für diese 
auf ChMin umgelenkt.

5. Die Zeichen-Einträge beschreiben das Displacement des zuständigen 
Glyphen vom Fontanfang  sowie die Größe des Glyphen in X und Y Richtung.

6. Die Glyphen sind Bitstreams. Das Fenster für das Zeichen ist ja 
bereits per dX,dY in dem Zeichen-Eintrag festgelegt und dessen Inhalt 
wird von links oben bis rechts unten gefüllt, zeilenweise, aber nicht 
byteweise. Eben ein Bitstream, kein padding am Zeilenende, deswegen 
relativ platzsparend. Padding auf ein ganzes Byte nur am Ende nach dem 
letzten Pixel des Zeichens.

7. Mit diesem Font Format sind sowohl Proportionalfonts als auch solche 
mit fester Zeichenbreite möglich. Letztere sind ja nur eine Untermenge 
der ersteren. Ein Font braucht nicht alle zeichen zu enthalten, man kann 
ihn auch so gestalten, daß er nur die Zeichen enthält, die man 
tatsächlich benutzt. Das ist wichtig für das Darstellen von großen 
Ziffern, wo man eben nur '0'..'9','-','+','.' benötigt.

8. Die zugehörige GDI-Routine zum Zeichnen eines Char's an beliebiger 
Stelle hab ich ja schon gepostet. Sie funktioniert wie ein Schreibstift 
und nicht wie ein Stempel. Das heißt, nichtgesetzte Pixel werden auch 
nicht gezeichnet. Ist wie an der Schultafel: Wo man schreiben will, muß 
man vorher auswischen.

So, das sollte als Erklärung reichen.


Erwin E. schrieb:
> * Es sollen Zeichen mit beliebige Unicodes verwendet werden können

Wie bitte? Ein Font für beliebige Unicodes würde schlichtweg aus allen 
Nähten platzen!

Erwin E. schrieb:
> Mit welchem Programm erzeugst du eigentlich die Fonts? Ich nehme
> lcd-immage-converter. Falls es da was besseres gibt, bin ich
> interessiert, obwohl das jetzige Tool gut funktioniert.

Lade dir die zwei Archive herunter, die ich weiter oben angegeben habe. 
Dort ist FM.EXE drin, was mein Eigenbau-Fontcompiler ist. Der setzt von 
einer textuellen Darstellung (die man zum Editieren braucht) in eine 
C-Quelle um. Daneben steckt dort auch Fontex.exe drin, ebenfalls ein 
Eigenbau von mir, was aber nur zum ungefähren Importieren von 
Windows-Fonts gedacht war. Ist hakelig, hatte mir aber ausgereicht für 
das, was ich damit machen wollte.

W.S.

von Maxim B. (max182)


Lesenswert?

Erwin E. schrieb:
> Meinst du wirklich? Ich habe das noch nicht gemacht, sehe aber nicht,
> warum ich nicht auch mehrere Displays ansteuern könnte. Ob .c oder .h,
> auf welchem Display die Ausgabe landet, bestimmt nur die I²C-Adresse.

Du denkst wohl, wenn du mehrere Bildschirme von gleichem Typ benutzt? 
Aber das kann man selten brauchen. Öfter braucht man gleichzeitig 
Bildschirme verschiedener Art. Trotzdem kann man für mehrere Bildschirme 
gleiche Zeichentabellen benutzen, obwohl für jeden Bildschirm eigene 
Befehle notwendig sind und entsprechend eigene *.c + *.h - Dateien.

Unterschied ist darin, daß du in einem Fall immer wieder die Daten im 
Speicher hast. In anderem Fall hast du immer wieder einen Zeiger auf 
eine und dieselbe Datei.

: Bearbeitet durch User
von Thomas F. (igel)


Lesenswert?

Erwin E. schrieb:
> Thomas F. schrieb:
>> Angesteuert mit 16-Bit Bus von einem Atmega64.
>> Die Zahlen werden alle 100ms aktualisiert und springen so schnell dass
>> keinerlei Verzögerung zu erkennen ist.
>
> Interessant! Hast du mal getestet, ob SPI sehr viel langsamer ist?

Ja, ist deutlich langsamer: Für ein anderes Projekt habe ich die 2,8' 
TFTs mit SPI eingesetzt. Hier geht der Bildaufbau deutlich langsamer. 
Ein flüssiger Bildaufbau war aber in dieser Anwendung nicht nötig.

> Ich nehme an, du aktualisierst nur die jeweilige Textzeile und
> beschreibst nicht das vollständige Display?

Ja. Für jedes Zeichen wird ein Schreibfenster passender Größe im RAM des 
TFT definiert und dieses dann geschrieben.

> Hast du eine fertige Library für die Ansteuerung genommen oder selbst eine 
gebaut?

Ist alles in Assembler selbst geschrieben.

von Joachim B. (jar)


Lesenswert?

noch größerer Unsinn scheint mir zu sein Trenner 0x00 in jedes Zeichen 
zu packen!

LCD5110_Basic: DefaultFonts.c
0x00, 0x7C, 0x12, 0x11, 0x12, 0x7C,   // A
der Font ist verschwenderischer, aber dafür die LIB sparsamer!
ideal für nano328p

platzsparender: Adafruit glcdfont.c
0x7C, 0x12, 0x11, 0x12, 0x7C,   // A
der Font ist sparsamer, aber dafür die LIB verschwenderischer!
beim ESP32 egal, RAM und flash genug vorhanden

von Stefan F. (Gast)


Lesenswert?

Zu genau der gleichen Erkenntnis bin ich auch gekommen, als ich meine 
OLED Klasse implementierte. Das gesparte Byte (pro Zeichen) zahlt man an 
anderer Stelle mit Performance und Code-Bedarf wieder drauf.

"Unsinn" würde ich genau deswegen aber eben nicht sagen. Außerdem möchte 
man vielleicht später mal Zeichen hinzufügen, die keinen Trenner haben, 
zum Beispiel um im Turbo-Vision Stil Rahmen aus Text-Zeichen zu 
erstellen.

von Erwin E. (kuehlschrankheizer)


Lesenswert?

W.S. schrieb:

> Ja, einen erheblichen Unterschied. Bei dir erstickt man ja geradezu in
> einer Flut von namen wie "static const tImage arial32_0x20 PROGMEM =
> ...", die alle in deiner Headerdatei stehen?
Nicht nur in einer... Jede Schriftgröße hat eine eigene Header Datei. 
Diese Dateien werden aber automatisch generiert und müssen deshalb nicht 
(von mir) angesehen werden. Dem Compiler ist es wurscht, 1000 mal 
"static const tImage arial32_0x20 PROGMEM =" lesen zu müssen.

> Und du stellst dir vor, daß man dein Konstrukt über deine Tabelle
> "static const tImage* const charset32[] PROGMEM  =..", die aus Pointern
> besteht, verwendet.
Eher nicht. Dafür gibts oled_write_char(..) und weitere 
Ausgabefunktionen.

> Mit dem Auseinandernehmen deines Fonts sparst du keinerlei Platz im
> Flash ein und mir scheint, daß du auch massenweise Platz vergeigst,
> indem du für jedes Zeichen (auch für große) zeilenweise auf ganze Bytes
> auffüllst.
Nein, das täuscht. Die Zeichendaten werden nicht aufgefüllt. Allerdings 
sind sie um 90° gedreht, weil ich sie so ohne Umrechnung direkt ans 
Display schicken kann. Da ich keinen Buffer verwende ist das schneller. 
Prinzipiell haben alle Zeichensätze eine Höhe von einem Vielfachen von 
acht. Die Breite ist beliebig. Das ist nur der Architektur des SSD1306 
geschuldet.

Die Größe der Fontdaten sind bei deiner und bei meiner Methode 
vergleichbar. Kein Wunder, denn auch ich speichere lediglich gerasterte 
Fontdaten. So wie du auch. Zum Vergleich den Platzbedarf des Zeichens 
'0':
Helvetica Größe 14 = 13 Byte bei dir gegenüber Noto Größe 16 = 16 Byte 
bei mir.
Lucida Größe 25: 47 Byte bei dir gegenüber Noto Größe 24 mit 39 Byte bei 
mir.
Die Organisation unserer Fonts scheint mir durchaus vergleichbar. Du 
hast ebenfalls eine Sprungtabelle in der Fontdatei über welche die 
Zeichen adressiert werden. Diese Tabelle belegt 2 Byte pro ASCII-Zeichen 
und ist der größte Platzfresser. Bei kleinen Schriftgrößen mit wenigen 
Glyphen benötigt die Tabelle mit knapp 500Byte mehr Platz wie die 
Fontdaten. Bei großen Fonts fällt die Tabelle weniger ins Gewicht. Eine 
64 Pixel hohe Glyphe benötigt z.B. 8 * 30 Bytes, da spielt die Tabelle 
mit 500 Bytes keine Rolle mehr.

Du lässt einzelne Zeichen aus um Platz zu sparen, ich mache das auch. 
Ein Unterschied ist, dass ich beliebige (ja, wirklich) Unicode-Zeichen 
in den Font einbauen kann, aber natürlich nicht mehr als 256 insgesamt. 
Die  Symbole aus dem Unicodebereich > 0xff werden innerhalb der 
Sprungtabelle auf beliebige Positionen gemappt. Für chinesisch taugt die 
Methode also auch nicht, weil es insgesamt nur max 256 unterschiedliche 
Glyphen geben kann. Welche das sind, kann ich ohne Einschränkung beim 
Erzeugen der Fontdatei über eine simple .csv Textdatei festlegen.

Alle Zeichensätze haben als Höhe ein Vielfaches von 8 und beginnen immer 
auf einer Page von Bit Höhe. Einen 24er Font kann ich also auf Zeile 
2..7 ausgeben, einen 8er Font auch auf Zeile 0. Das erinnert an 
Charakter Displays. Allerdings kann ich innerhalb einer Zeile die 
Schriftgröße beliebig wechseln.

Die Textausgabe ist sehr schnell, weil die Zeichen und Strings direkt 
vom Flash ins Display geschrieben werden. Das geht deutlich schneller, 
als einen vollständigen 1k großen Buffer mit dem vollständigen 
Displayinhalt auf einmal zu schreiben.
Wird nämlich ein Buffer benutzt, ist das für den Controller doppelte 
Arbeit: Zuerst müssen die Zeichen in den Buffer geschrieben werden. 
Anschließend wird der Buffer zyklisch zum Display übertragen.
Letztes kann ich mir sparen.

> Obendrein besteht ein Großteil deines Codes aus "PROGMEM", was für eine
> völlige Un-Portierbarkeit sorgt.

Sorry, aber das ist bei einer AVR-Library wohl so. Ohne PROGMEM kann ich 
den Flashspeicher nicht ansprechen. Natürlich ist die Lib als solche 
deshalb nicht (direkt) portierbar.
Das Prinzip der Fonterzeugung kann jedoch durchaus auf beliebige 
Architekturen übertragen werden. Auch andere Displaycontroller kann ich 
mit mäßigem Aufwand ansteuern. Das bereits erwähnte ILI9143 interessiert 
mich, das werde ich bei Gelegenheit mal angehen. Dazu muss ich den 
Fontcompiler an die Architektur des ILI anpassen und die Ausgaberoutine 
in der Lib. Der Rest kann bleiben.


> 1. Bei mir besteht ein Font aus einer variablen Struktur, die als
> Byte-Block gespeichert werden kann und die zum Zugriff NUR einen
> einzigen Zeiger auf ihren Anfang benötigt und auch nur einen einzigen
> Bezeichner in der gesamten Firmware einträgt.
Bei mir gibt es in der Sprungtabelle eines Fonts (nur einmal vorhanden) 
für jeden Zeichencode einen Zeiger, über den die Zeichendaten adressiert 
werden. Jeder Zeiger ist 2 Byte groß. Die Zeichen des Fonts und die 
Springtabelle liegen direkt hintereinander im Flash. Das sollte das 
selbe Ergebnis bringen wie deine Methode.

> 2. Diese Struktur ist so ausgelegt, daß sie sowohl auf bigendian als
> auch auf littleendian Maschinen zu benutzen ist.
Bei mir ist die Struktur auf die Organisation des Grafik-RAM meines 
LCD-Controllers abgestimmt. Damit die Daten ohne Umrechnug direkt aufs 
Display geschrieben werden können.

> 3. Jeder Font besteht aus 3 Teilen:
>  - einem Fontheader
>  - einer variablen Anzahl von Zeichen-Einträgen
>  - den eigentlichen Glyphen
Mache ich auch so.

> 4. Der Fontheader beschreibt die Gesamthöhe, die Höhe [..]
> In dieser
> Struktur sind lediglich 8 Bit Werte für die Zeichen möglich, [..]
Genau wie bei mir.

> keine Zeichencodierungen von 16 Bit und aufwärts (Unicode).
Das ist ein Unterschied, beliebige Unicodezeichen mappe ich auf 8Bit 
Werte. Natürlic nicht mehr als insgesamt 255. Für Chinesisch wird das 
nicht reichen.

> Wenn es Lücken zwischen ChMin und ChMax gibt, wird für diese
> auf ChMin umgelenkt.
Mache ich genauso.

> 5. Die Zeichen-Einträge beschreiben das Displacement des zuständigen
> Glyphen vom Fontanfang  sowie die Größe des Glyphen in X und Y Richtung.
Bei mir steht ein 16Bit Zeiger auf die Adresse des Glyphen in der 
Tabelle.
Das könnte minimal schneller sein, beim Zugriff auf ein Zeichen. Bin mir 
da aber nicht ganz sicher.

> 6. Die Glyphen sind Bitstreams.
> bereits per dX,dY in dem Zeichen-Eintrag festgelegt und dessen Inhalt
> wird von links oben bis rechts unten gefüllt, zeilenweise, aber nicht
> byteweise.
Das mache ich genauso, nur eben ohne Puffer. Der SSD1306 braucht die 
Daten eben spaltenweise, weshalb ich sie entsprechend im Font abgelegt 
habe.

> 7. Mit diesem Font Format sind sowohl Proportionalfonts als auch solche
> mit fester Zeichenbreite möglich.

Exakt das gleiche Prinzip wie bei mir.

> 8. Die zugehörige GDI-Routine zum Zeichnen eines Char's an beliebiger
> Stelle hab ich ja schon gepostet. Sie funktioniert wie ein Schreibstift
> und nicht wie ein Stempel. Das heißt, nichtgesetzte Pixel werden auch
> nicht gezeichnet. Ist wie an der Schultafel: Wo man schreiben will, muß
> man vorher auswischen.
Das geht beim SSD1306 nicht, wenn kein Puffer oder r/m/w-Verfahren 
verwendet wird. Diese Einschränkung war der Auslöser, dass ich diese 
Library so gemacht habe.
Das ist auch der Grund, warum ich keine geometrischen Figuren ausgeben 
kann. Senkrechte Linien beliebiger Breite sind möglich. Kreise, 
Rechtecke dagegen nicht. Weil kein Puffer vorhanden ist und ich über I²C 
das Display-RAM nur schreiben, aber nicht lesen kann.

> Wie bitte? Ein Font für beliebige Unicodes würde schlichtweg aus allen
> Nähten platzen!
Wie geschrieben, beliebige Codes sind möglich - aber nicht alle 
gleichzeitig.

> Erwin E. schrieb:
>> Mit welchem Programm erzeugst du eigentlich die Fonts? Ich nehme
>> lcd-immage-converter. Falls es da was besseres gibt, bin ich
>> interessiert, obwohl das jetzige Tool gut funktioniert.
>
> Lade dir die zwei Archive herunter, die ich weiter oben angegeben habe.
Habe ich bereits gemacht. Danke fürs Zeigen!

Was bei dir die txt-Dateien sind, sind bei mir .c Files, welche der 
lcd-image-converter (oben verlinkt) erzeugt und von meinem primitiven 
Fontcompiler in die eigentliche .h umsetzt wird.

Danke für deinen Beitrag. Eine Library zu benutzen und zu Verstehen sind 
wirklich zwei paar Stiefel. Diese Antwort hat mich gezwungen, meine 
Library nochmals zu durchdenken und selbst wieder zu begreifen, was ich 
vor einem halben Jahr wie und warum gemacht habe.

von Erwin E. (kuehlschrankheizer)


Lesenswert?

Joachim B. schrieb:
> noch größerer Unsinn scheint mir zu sein Trenner 0x00 in jedes Zeichen
> zu packen!

Das wäre wirklich Unsinn. Allerdings gibts da keinen 'Trenner' 0x00. 
Wozu auch, für jedes Zeichen gibt es einen 16Bit Zeiger in den 
Flashspeicher.

von Joachim B. (jar)


Lesenswert?

Erwin E. schrieb:
> Wozu auch, für jedes Zeichen gibt es einen 16Bit Zeiger in den
> Flashspeicher.

du scheinst es nicht verstanden zu haben!
Das 0x00 Byte belegt flash und für jedes Zeichen etliche Bytes die immer 
redundant sind!

von Erwin E. (kuehlschrankheizer)


Lesenswert?

Joachim B. schrieb:
> du scheinst es nicht verstanden zu haben!
> Das 0x00 Byte belegt flash und für jedes Zeichen etliche Bytes die immer
> redundant sind!

Was du als 'Trenner' zu erkennen glaubst, sind vermutlich die weißen 
Ränder eines Zeichens. Die sind aber nötig, damit die Zeichen nicht 
direkt aneinanderstoßen. Allerdings ändert das nichts daran, dass bei 
einem proportionalen Font ein 'I' weniger Platz braucht als ein 'W'. 
Jedoch ist links und rechts vom 'W' ein weißer Streifen als Abstand 
genau (aber nicht unbedingt gleich breit) wie beim 'I'.

Natürlich könnte ich für jedes Zeichen die Breite des linken und rechten 
Rands als Zahlenwert in die Fontdatei schreiben und erst bei der Ausgabe 
entsprechend viele '0x00' schreiben. Das bedingt aber zusätzlichen 
Rechenaufwand, den ich sparen möchte. Dann lieber gleich 
RLE-Kompression, die spart wirklich Speicher, aber eben auch auf Kosten 
der Rechenzeit beim Beschreiben des Displays.

von W.S. (Gast)


Angehängte Dateien:

Lesenswert?

Joachim B. schrieb:
> noch größerer Unsinn scheint mir zu sein Trenner 0x00 in jedes Zeichen
> zu packen!

Sieh das mal ein bissel relativiert. Ich betreibe Grafik-Displays in 
allen möglichen Versionen - aber NICHT an irgend einem kleinen 8 Bit µC, 
sondern nur mit 32 Bit µC.

Da ist es mit dem Platz im Flash weitaus entspannter. Das wiederum macht 
es leicht, durch das Gestalten der Glyphen die Schrift so hinzukriegen, 
daß man bei Bedarf auch Kerning und Unterschneidungen etc. hinkriegen 
kann, also trotz recht simpler Fontgestaltung doch noch einiges an 
typografischen Dingen realisieren kann - wenn man das will und sich die 
ja nicht unerhebliche Mühe macht.

Das ist der Grund, weshalb auch bei meinen Fonts Zeichenzwischenräume 
eingearbeitet sind - anstatt sie zentral in der Grafikroutine 
unterzubringen. Wenn allerdings das ganze auf einem beengten 8 Bit 
System laufen soll, dann wäre es ganz sicher viel sinnvoller, Leer-Räume 
sowohl vertikal als auch horizontal aus dem Font zu entfernen und diese 
pauschal von der Ausgaberoutine erledigen zu lassen.

Ebenso wäre es dort auch ausreichend, auf die Offset-Tafel bzw. 
Adreßtafel zu verzichten und jedem Glyphen an seinem Anfang ein 
Längenbyte voranzustellen, so daß man mit nur jeweils 1 Byte zum 
Erreichen des Glyphen auskommen kann. Man muß sich dabei lediglich durch 
das Glyphenfeld hindurchhangeln.

Nun hat Erwin sich jede nur erdenkliche Mühe gegeben, darzustellen, daß 
er es besser kann - ok, ich will ihn da nicht bremsen, allerdings ist 
sein Konzept umständlicher in jeder Hinsicht, stellt aus Nutzersicht ein 
riesiges Gewirr von Tabellen dar, ist nicht portabel und kommt auch 
nicht mit beliebigen Textkoordinaten klar. Dafür ist es ganz speziell an 
die AVR und an eine bestimmte Sorte von Display gebunden und eben daran 
angepaßt. Ob das nun jedem so gefällt und woanders nachnutzbar ist, ist 
eine andere Frage.

Ich habe da eine völlig andere Herangegensweise: Ich will bei allen 
Dingen eine möglichst sinnvolle Abstraktion, so daß ich damit nicht auf 
einen Chip oder einen Hersteller festgenagelt bin. Also trenne ich auch 
bei grafischen Displays zwischen der niederen Seite der physischen 
Display-Ansteuerung und der eher logischen Seite des Zeichnens von 
grafischen Elementen auf einem Canvas und trenne davon obendrein auch 
Grafik-Elementen wie Fonts, Icons und Bildern ab.

Eben deshalb ist bei mir ein Font eben ein einziges "Ding", also ein 
einziger Datenblock und nicht ein Sammelsurium von Tafel verschiedenster 
Art wie bei Erwin. Ein Gleiches gilt für Grafiken. Auch hier sind die 
diversen Grafiken jeweils ein einziges Ding. Wie das aussieht, siehe 
angehängte Datei. Ich hatte sowas m.W. schon mal gepostet, hier also nur 
der Ansicht halber. Im ZIP sind sowohl die eigentliche Grafik als auch 
die Umsetzung in C in mehreren verschieden stark farbreduzierten 
Versionen. Ist immer dasselbe Bild, aber deutlich unterschiedlich im 
Byteumfang.

Um auf die Fonts zurückzukommen: Die Fontausgabe auf so kleinen 
monochromen 128x64 Displays ist bei mir nur ein Sonderfall, normal ist 
eher die Ausgabe auf bunten TFT, so ab QVGA bis WVGA. Die zugehörigen 
Zeichenausgaberoutinen hab ich mir hier gespart, sie sind fast gleich 
zum bereits Geposteten, lediglich "mode" ist dort durch einen Zeiger auf 
den zugehörigen Device-Kontext ersetzt. Damit haben die Routinen auch 
die Charakteristika des Canvas, der wiederum zu einem TFT oder zu einem 
Drucker gehören kann.

Das alles würde hier zu weit führen, wir reden hier ja über einfache 
128x64 Displays.

W.S.

von Tom Ranik (Gast)


Lesenswert?

MCUA schrieb:
> SPI-Probleme bei (bisherigen, nicht die allerneusten) AVRs:
>
> 1.) SPI -TX hat keinen einzigen Byte-Buffer
> ...(es kann also nichtmal mit einem Jitter von +- der Länge eines
> ....ausgeschriebenen (SPI)Bytes in das SPI-Modul geschrieben werden)
> ...(evtl. kann man (wenn im Master-Mode) taktgenau 'warten' (diese Takte
> ....gehen aber verloren) und so weitere Bytes an TX rausschicken)
> ...(selbst ein winziger STM8 ist hier besser, und es gibt faktisch keine
> ....neuere CPU, die hier nicht wenigstens einen Buffer hat)

MCUA schrieb:
>>Daten und Befehle in Puffer und los, CPU macht was anderes, z.B.
>>nächste Daten für LCD.
> Der AVR-SPI-TX hat kein Puffer.

Dazu nimmt man auch nicht das SPI Peripheral, sondern den USART im 
Master-SPI Mode...

von Johannes S. (Gast)


Lesenswert?

Erwin E. schrieb:
> Ohne PROGMEM kann ich den Flashspeicher nicht ansprechen.

Das ist auch kein Problem, da sieht nur W.S. welche.
Alle anderen schreiben sowas wie
1
#ifndef AVR
2
#define PROGMEM
3
#endif

Und schon ist es weg gebeamt.
Bzw beim ESP wird es auch genutzt um Daten ins Flash zu legen wimre.

von spess53 (Gast)


Lesenswert?

Hi

>Dazu nimmt man auch nicht das SPI Peripheral, sondern den USART im
>Master-SPI Mode...

Naja, dann fallen erst mal einige Arduinos raus.

MfG Spess

von MCUA (Gast)


Lesenswert?

>Dazu nimmt man auch nicht das SPI Peripheral, sondern den USART im
>Master-SPI Mode...
ich weis, dass der das hat (auch keine Hardw-FIFOs), trotzdem sind die 
weiter genannten Mängel an der CPU vorhanden.

von Maxim B. (max182)


Lesenswert?

Man kann auch ohne PROGMEM.
1
const __flash char myarray[] =
2
{0,1,2,3,4,5};
Natürlich sollte man dafür GSS nicht aus dem Jahre 2010 nehmen. Bei mir 
arbeitet das mit 5.4.0
Das gibt deutlich mehr Freiheit: man braucht keine besonderen Funktionen 
mehr, es reicht, Argumente in einer Funktion als const __flash zu 
erklären.
Hier sind drei Funktionen zum Vergleich, die String auf LCD bringen: für 
String in RAM, in FLASH mit PROGMEM und in FLASH mit const __flash
1
void lcd_string( char *data ){
2
    while( *data != '\0' )
3
        lcd_data( *data++ );
4
} 
5
6
void lcd_string_P( PGM_P data ){
7
  char tmp;
8
    tmp=pgm_read_byte(data);
9
    while( tmp != '\0' ) {       
10
        lcd_data( tmp );
11
        data++;
12
        tmp = pgm_read_byte(data);
13
    }
14
} 
15
16
void lcd_string_F(  const __flash char *data ){
17
      while( *data != '\0' )
18
        lcd_data( *data++ );
19
}
Hier sieht man, wie bequemer es mit const __flash geht.

: Bearbeitet durch User
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.