Welche "sparsame" Display Bibliothek verwenden?

Hallo in die Runde,
einmal ist immer das erste Mal, das hier ist meines - sorry!
In meinem Bastelzimmer liegen hier so ca. 10 Breadboards mit UNOs, NANOs und Ähnlichem herum mit denen bisher unterschiedliche Sensoren getestet wurden (meist mit den Standardsketches). Auch Displays hab ich schon zum laufen gebracht, immerhin.

So langsam muß ich aber alles irgendwie auf eine UNO-Platine bringen, die dann in einem Hutschienengehäuse in einen Schaltschrank passen muss. Aufgaben bekommt der UNO genug und deshalb ist es schon jetzt Zeit, sich über den Speicherplatz Gedanken zu machen. Es soll auch ein OLED-Display mit 128x64 und I2C Verwendung finden (ich muß auch Pins sparen), allerdings wird hier die u8g2 empfohlen, die enorm leistungsfähig und daher offenbar speicherhungrig ist.
Die kann ja auch viele lustige Grafiken anzeigen, die ich allerdings nicht brauche, ebensowenig kunstvolle Fonts in allen möglichen Abmessungen.

Gibt es nicht auch eine "abgemagerte" Bibliothek für ganz gemeine ASCII Zeichen?
Ich habe die Hoffnung, dass hier im Kreise bewanderter und erfahrener Anwender sicher das Problem schon mal aufgetaucht ist und kurz eine Empfehlung gegeben werden kann.
Schon jetzt vielen Dank an die Community!
Mit besten Grüßen,
Ralf

Naja, ich kenne nicht jede Libs dazu.

Aber ich nutze diese hier.

// SSD1306Ascii  - Copyright (c) 2011..2023 Bill Greiman

#include "SSD1306Ascii.h"
#include "SSD1306AsciiWire.h"
#define oled_adresse 0x3C

SSD1306AsciiWire oled;

void setup() {

    Serial.begin(9600); // Initialize serial communications with the PC
    while (!Serial);    // Do nothing if no serial port is opened (added for Arduinos based on ATMEGA32U4)
    
// Oled-Display 
    Wire.begin();
    Wire.setClock(400000L);
    oled.begin(&Adafruit128x64, oled_adresse);
    oled.setFont(TimesNewRoman16); // Auswahl der Schriftart
    oled.clear(); //Löschen der aktuellen Displayanzeige
    oled.println("Pogramm gestartet");

}

für DIESE Displays.

https://www.amazon.de/gp/product/B09BF7SQHS?th=1

Ich schreibe das dabei, weil bei den Teilen wichtig ist (wie meist) welcher Steuerchip da sein Job macht. Bei meinen halt ein SSD-1306. Siehe Schaltplan im Amazon-link.

Anderer Steuerchip = meist andere Libs.

Die Auflösung ist i.d.R. 2.rangig. Die Libs oben kann auch andere Auflösungen. Man muss es ihr nur sagen :wink:

Gruß

Pucki

Wenn du bessere Angaben willst, musst du dein Display so genau wie möglich angeben.
Am besten mit Link wo man das bekommen kann.

Datenblatt lesen hilft auch.

Und dann noch beten das es ein "Normales-Display" ist, also eins was für den freien Markt erhältlich ist. Ich wollte mir nämlich gestern ein Display bei Pollin für ca. 50 Cent kaufen. Hab das aber gelassen weil der Aufwand das ans laufen zu bekommen (wenn überhaupt) die Ersparnis bei weiten übersteigt.

Gruß

Pucki

Zur u8g2 Lib gibt es anzumerken, dass der Speicherverbrauch von zwei Dingen entscheidend abhängt:

  1. Mit welcher Buffersize man das u8g2 Objekt initialisiert
    u8g2setupcpp · olikraus/u8g2 Wiki · GitHub

U8G2_SSD1306_128X64_NONAME_1_4W_SW_SPI(rotation, clock, data, cs, dc [, reset]) [page buffer, size = 128 bytes]
U8G2_SSD1306_128X64_NONAME_2_4W_SW_SPI(rotation, clock, data, cs, dc [, reset]) [page buffer, size = 256 bytes]
U8G2_SSD1306_128X64_NONAME_F_4W_SW_SPI(rotation, clock, data, cs, dc [, reset]) [full framebuffer, size = 1024 bytes]

Zu beachten ist hierbei, dass die Programmierung der Ausgabe bei Modi 1 und 2 etwas anders erfolgt als beim Modus F (do while) u8g2reference · olikraus/u8g2 Wiki · GitHub

  1. Welchen Font man auswählt. Nahezu jeden Font gibt es in unterschiedlichen Ausprägungen an verfügbaren Zeichen und somit auch unterschiedlichem Speicherverbrauch.
    fntlist8 · olikraus/u8g2 Wiki · GitHub

Achtet man also auf Buffermodus und verwendete Fontvariante, ist auch mit der u8g2 Lib eine „speicherplatzschonende“ Programmierung möglich.

Holla,
das sieht doch schon mal sehr Vertrauen erweckend aus, wenn es schon gleich "Ascii" im Namen trägt. Ich habe hier eine ganze Reihe verschiedener Displays vorrätig, meist von AZ-Delivery, dabei ist auch ein 0,96" mit SSD1306, also ist der Sonntag auch schon verplant :wink:
Vielen Dank für den Tipp, ich werde den Speicherzuwachs im Auge behalten!
Beste Grüße

Ralf

  1. Mit welcher Buffersize man das u8g2 Objekt initialisiert
    u8g2setupcpp · olikraus/u8g2 Wiki · GitHub

Auch das ein wichtiger Hinweis, da muß ich mal tiefer einsteigen, wobei ich sagen muß, dass mir die 'einfachen' oled.clear- und oled.print-Anweisungen sehr entgegenkommen, statt zunächst den Buffer zu befüllen und dann selbigen abzuschicken - ist aber nur mal ein erster Eindruck ohne praktische Erfahrung.
Melde mich wieder,
beste Grüße
Ralf

Du kannst die "einfachen" oled.print und oled.clear Anweisungen in allen Modi verwenden.

Der Unterschied liegt hier:


// Full Display Frame Buffer (F)

oled.clearBuffer();
oled.print("BlaBlaBla);
oled.sendBuffer();


// Page Buffer (Mode 1 oder 2)

oled.firstPage();
do {
  oled.print("BlaBlaBla);
} while ( oled.nextPage() );

In den Seitenpuffermodi müssen die Ausgabeanweisungen in der do - while Schleife eingebunden sein, nachdem oled.firstPage() aufgerufen wurde.

Bei letzterem Fall ist die Ausgabe etwas langsamer als im "Fullframe" Modus, was aber in vielen Fällen keine merkliche Rolle spielt.

Der verwendete Font ist auch entscheidend. Mal ein Beispiel:
u8g2_font_logisoso18_tf -> 3626 Bytes
u8g2_font_logisoso18_tr -> 1880 Bytes
u8g2_font_logisoso18_tn -> 330 Bytes (Wenn man nur Ziffern * / + - . braucht)

Wenn man nun noch den Unterschied Fullframe Buffer (1024 Bytes) und Modus 1 (128 Bytes)
betrachtet, kann man bei vernünftiger Auswahl von Buffer und Font einige Kilobyte! sparen.

Kommt man mit 8x8 Zeichen aus, kann man auch auf den u8x8 "Modus" umschalten:

Je nach bestehender Anwendung macht es dann wenig Sinn, sich nach einer anderen Bibliothek umzuschauen und Bestehendes komplett umzukrempeln, wenn man die beschriebenen zwei Stellschrauben nutzt.

Wenn das nicht ausreicht... ja dann muss man halt doch was anderes suchen und umsteigen.

Ergänzung: Die Wahl der Buffermethode macht sich vor allem und entscheidend im RAM bemerkbar!

Beispiel (Nano Clone) :
Ein Programm im Modus 1:
RAM: [===== ] 46.2% (used 946 bytes from 2048 bytes)
Flash: [===== ] 45.1% (used 14542 bytes from 32256 bytes)

Gleiches Programm im Modus F
RAM: [========= ] 89.9% (used 1842 bytes from 2048 bytes)
Flash: [===== ] 45.1% (used 14544 bytes from 32256 bytes)

Der Vergleich ist zwar nicht so ganz sauber, weil vor dem Compilieren nur der Buffemodus geändert wurde, aber nicht die Programmierung der Ausgabe. Aber im Prinzip passt es.

Programm:

  • solltest du NANOs haben und diese mit dem "Old Bootloader" beladen, dann würde ich auf die NANOs den UNO Bootloader aufbringen und künftig als UNO beladen. Erstens ersparst du dir das Umschalten zwischen UNO/NANO und außerdem kann der Sketch um 1500K größer sein.
Maximum is 32256 bytes vs
Maximum is 30720 bytes
  • wenn es kein OLED sein muss, würde ich ein Character LCD nehmen (1602, 2004, ... ganz egal). Da diese einen eingebauten Zeichensatz haben, ist deren Speicherverwendung massiv geringer.
  • wenn du pinmäßig statt I2C auch SPI verwenden kannst - würde ich ein SPI Display verwenden, und I2C weglassen.
  • Oder wenn du bereits SPI Hardware im Einsatz hast und I2C nur fürs Display gebraucht wird - nimm ein SPI Display.

Wenig Speicher, nicht viel Grafik dann u8x8 auch vom Oli, ist unter Beispiele versteckt.
Der meister Speicherfresser sind Die Fonts == Schriftarten je mehr Punkte, Größer die Zeichen desto mehr Speicher brachen die.

Test von 2017
Text auf OLED speicherschonend darstellen

Aufgabe: Ein bestehendes Projekt mit Nano möchte ich um die Anzeige von Text erweitern. Dazu erstelle ich auf einem UNO einen Testsketch, der einen Text möglichst speicherschonend darstellen soll.

Hardware: UNO über I2C mit 0,96" OLED, programmiert mit IDE 1.6.5

1. Versuch: Adafruit_SSD1306 mit Sketch abgeleitet von ssd1306_128x64_i2c.ino

#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#define OLED_RESET -1
Adafruit_SSD1306 oled(OLED_RESET);

void setup() {
  oled.begin(SSD1306_SWITCHCAPVCC, 0x3C);  // initialize with the I2C addr 0x3C = 0x78/2 (for the 128x64)
  oled.clearDisplay();
  oled.setTextSize(1);
  oled.setTextColor(WHITE);
  oled.setCursor(0, 0);
  oled.println("21.8.2017 11:11");
  oled.display();
}
void loop() {}

Der Sketch verwendet 10.130 Bytes (31%) des Programmspeicherplatzes. Das Maximum sind 32.256 Bytes.
Globale Variablen verwenden 1.395 Bytes (68%) des dynamischen Speichers, 653 Bytes für lokale Variablen verbleiben. Das Maximum sind 2.048 Bytes.

Neben verschiedenen Warnungen ist der Speicherverbrauch nicht akzeptabel, einen reinen Textmodus habe ich aber nicht gefunden.

2. Versuch: Oliver Kraus

Test_Forum.ino.386-002
#include <Arduino.h>
#include "U8g2lib.h"
#include <SPI.h>
#include <Wire.h>

U8G2_SSD1306_128X64_NONAME_1_HW_I2C oled(U8G2_R0);
 
void setup(void) {
  oled.begin();
}

void loop(void) {
  oled.firstPage();
  do {
    oled.setFont(u8g2_font_6x12_tr);
    oled.drawStr(0,12,"21.8.2017 11:11");
  } while ( oled.nextPage() );
}

Der Sketch verwendet 8.694 Bytes (26%) des Programmspeicherplatzes. Das Maximum sind 32.256 Bytes.
Globale Variablen verwenden 606 Bytes (29%) des dynamischen Speichers, 1.442 Bytes für lokale Variablen verbleiben. Das Maximum sind 2.048 Bytes.

3. Versuch:
Test_Forum.ino.386-003
#include <Arduino.h>
#include "U8glib.h"
#include <SPI.h>
#include <Wire.h>

// setup u8g object, please remove comment from one of the following constructor calls
U8GLIB_SSD1306_128X64 u8g(U8G_I2C_OPT_NONE|U8G_I2C_OPT_DEV_0);  // I2C / TWI
//U8GLIB_SSD1306_128X64 u8g(U8G_I2C_OPT_DEV_0 | U8G_I2C_OPT_NO_ACK | U8G_I2C_OPT_FAST); // Fast I2C / TWI
//U8GLIB_SSD1306_128X64 u8g(U8G_I2C_OPT_NO_ACK);  // Display which does not send AC

void draw(void) {
  // graphic commands to redraw the complete screen should be placed here
  u8g.setColorIndex(1);         // pixel on
  //u8g.setFont(u8g_font_unifont);
  u8g.setFont(u8g_font_6x10);
  u8g.drawStr( 0, 10, "21.8.2017 11:11");
}

void setup(void) {
}

void loop(void) {
  // picture loop
  u8g.firstPage();
  do {
    draw();
  } while ( u8g.nextPage() );

  // rebuild the picture after some delay
  delay(50);
}

Der Sketch verwendet 7.350 Bytes (22%) des Programmspeicherplatzes. Das Maximum sind 32.256 Bytes.
Globale Variablen verwenden 455 Bytes (22%) des dynamischen Speichers, 1.593 Bytes für lokale Variablen verbleiben. Das Maximum sind 2.048 Bytes.

4. Versuch:
Test_Forum.ino.386-004
#include "U8x8lib.h"
#include <SPI.h>
#include <Wire.h>

/* Constructor */
U8X8_SSD1306_128X64_NONAME_HW_I2C oled(-1);

/* u8x8.begin() is required and will sent the setup/init sequence to the display */
void setup(void)
{
  oled.begin();
  oled.setFont(u8x8_font_artossans8_r);
  oled.drawString(0,16,"21.8.2017 11:11");
}

void loop(void){}

Der Sketch verwendet 5.912 Bytes (18%) des Programmspeicherplatzes. Das Maximum sind 32.256 Bytes.
Globale Variablen verwenden 398 Bytes (19%) des dynamischen Speichers, 1.650 Bytes für lokale Variablen verbleiben. Das Maximum sind 2.048 Bytes.


5. Versuch:
Test_OLED_128X64.ino.006 mit MicroLCD.h

In file included from Test_Forum.ino:2:0:
F:\Arduino\libraries\MicroLCD/MicroLCD.h:39:43: warning: '__progmem__' attribute ignored [-Wattributes]
     virtual void draw(const PROGMEM byte* buffer, byte width, byte height) {}
                                           ^
F:\Arduino\libraries\MicroLCD/MicroLCD.h:38:18: warning: unused parameter 'on' [-Wunused-parameter]
     virtual void backlight(bool on) {}
                  ^
F:\Arduino\libraries\MicroLCD/MicroLCD.h:39:18: warning: unused parameter 'buffer' [-Wunused-parameter]
     virtual void draw(const PROGMEM byte* buffer, byte width, byte height) {}
                  ^
F:\Arduino\libraries\MicroLCD/MicroLCD.h:39:18: warning: unused parameter 'width' [-Wunused-parameter]
F:\Arduino\libraries\MicroLCD/MicroLCD.h:39:18: warning: unused parameter 'height' [-Wunused-parameter]
F:\Arduino\libraries\MicroLCD/MicroLCD.h:43:18: warning: unused parameter 'n' [-Wunused-parameter]
     virtual void writeDigit(byte n) {}
                  ^
F:\Arduino\libraries\MicroLCD/MicroLCD.h:53:10: warning: unused parameter 'line' [-Wunused-parameter]
     void clearLine(byte line) {}
          ^
F:\Arduino\libraries\MicroLCD/MicroLCD.h:56:10: warning: unused parameter 'column' [-Wunused-parameter]
     void setCursor(byte column, byte line) {}
          ^
F:\Arduino\libraries\MicroLCD/MicroLCD.h:56:10: warning: unused parameter 'line' [-Wunused-parameter]
F:\Arduino\libraries\MicroLCD/MicroLCD.h:57:12: warning: unused parameter 'c' [-Wunused-parameter]
     size_t write(uint8_t c) { return 0; }
            ^
In file included from Test_Forum.ino:2:0:
F:\Arduino\libraries\MicroLCD/MicroLCD.h:67:35: warning: '__progmem__' attribute ignored [-Wattributes]
     void draw(const PROGMEM byte* buffer, byte width, byte height);
                                   ^
F:\Arduino\libraries\MicroLCD/MicroLCD.h:84:35: warning: '__progmem__' attribute ignored [-Wattributes]
     void draw(const PROGMEM byte* buffer, byte width, byte height);
                                   ^
In file included from Test_Forum.ino:2:0:
F:\Arduino\libraries\MicroLCD/MicroLCD.h:115:35: warning: '__progmem__' attribute ignored [-Wattributes]
     void draw(const PROGMEM byte* buffer, byte width, byte height);
                                   ^

Der Sketch verwendet 8.712 Bytes (27%) des Programmspeicherplatzes. Das Maximum sind 32.256 Bytes.
Globale Variablen verwenden 278 Bytes (13%) des dynamischen Speichers, 1.770 Bytes für lokale Variablen verbleiben. Das Maximum sind 2.048 Bytes.

#define MEMORY_SAVING in MicroLCD.h
Der Sketch verwendet 5.818 Bytes (18%) des Programmspeicherplatzes. Das Maximum sind 32.256 Bytes.
Globale Variablen verwenden 278 Bytes (13%) des dynamischen Speichers, 1.770 Bytes für lokale Variablen verbleiben. Das Maximum sind 2.048 Bytes.

Ich hoffe, es hilft Dir :slightly_smiling_face:

1 Like

Sag ich doch :wink:
die SSD1306Ascii kommt auf 22% Genaue Byte zahl weis nicht mehr, habe noch ein mall in die Lib reingeschaut die kann nur Zeichen darstellen wen gut gelesen

Kannst Du das bitte nochmal erklären? Ich verstehe diesen Satz nicht.

Der Speicherbedarf hängt von verschiedenen "Stellschrauben" ab, was die Auswahl der Optionen nicht einfacher macht, aber ich finde, es lohnt sich.

Neben dem, was schon in #4 geschrieben wurde, ist auch der Zeichenumfang ganz entscheidend, Speicherbedarf absteigend:

  • UTF8
  • ASCII bis 255
  • ASCII bis 127
  • Zahlen mit ein paar Zeichen

Wer die Wahl hat, hat die Qual :wink:

Das sehe ich genau so.
Z.B. könnte man auch ressourcenschonend programmieren. :wink:
Je früher man damit anfängt, umso besser.

Völlig korrekt, liegt auch in meiner Absicht, aber eventuell nicht in meinen Fähigkeiten...
Was ich vorher nicht ausgebe, muß ich hinterher nicht einsparen - wär ja auch mal ein Ansatz.
Jedenfalls hab ich für die nächsten Tage einiges zu ergründen, vielen Dank für die zahlreichen Hinweise, diese Community hat was... :slight_smile:
Schönen Sonntag noch,
Ralf

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.