Wie kann ich hier millis einsetzen?

ESP8266 NodeMcu mit int.OLED

Ich habe eine kleine Animation für mein OLED wenn Daten per UDP empfangen wurden.
Statt delay möchte ich lieber millis einsetzen.
Problem: Die Animation (im Unterprogramm ganz unten) wird nur einmal bei Datenempfang (if (packetSize).....) durchlaufen. Einen aufgerechneten Milliwert werde ich also so nicht erreichen!?

Könnt ihr mir einen Tip geben wie ich das trotzdem umsetzen kann? Einen Marker setzen und im Haupt-Loop laufen lassen? Wird aber dann sehr unübersichtlich...

#include <ESP8266WiFi.h>
#include <SSD1306Wire.h>          // für OLED` 128x64
#include <WiFiUdp.h>

//#define LED D7

WiFiUDP Udp;
unsigned int localUdpPort = 4210;     // local port to listen on
char befehl[8];                      // buffer for incoming packets in binär
boolean Relais1 = 0;
boolean Relais2 = 0;
boolean Relais3 = 0;
boolean Relais4 = 0;
boolean Relais5 = 0;
boolean Relais6 = 0;
char myIpString[24];          //um IP Adresse in String umzuwandeln und anzuzeigen

char *ssid = "++++++++++++";
char *password = "##########";

// Initialize the OLED display using Wire library
SSD1306Wire  display(0x3c, D1, D2);  //D2=SDK  D1=SCK  As per labeling on NodeMCU


//unsigned int localUdpPort = 4210;
char incomingPacket[256];
char replyPacket[] = "Hi there! Got the message :-)";

int Heizleistung = 0;



void setup() {
  Serial.begin(9600);
  display.init();
  display.flipScreenVertically();
  display.setTextAlignment(TEXT_ALIGN_LEFT);
  display.setFont(ArialMT_Plain_16);
  //display.setFont(ArialMT_Plain_10);
  display.clear();
  display.drawString(0, 0, "Start");
  display.display();
  delay(1000);
  
  WiFiStart();                                //Unterprogramm verbindet ESP mit Router
  Udp.begin(localUdpPort);
  delay(3000);
}




void loop() {
    int packetSize = Udp.parsePacket();
    if (packetSize)
    {
      //Serial.printf("Received %d bytes from %s, port %d\n", packetSize, Udp.remoteIP().toString().c_str(), Udp.remotePort());
      int len = Udp.read(incomingPacket, 255);
      if (len > 0)
      {
        incomingPacket[len] = '\0';
      }
      //Serial.printf("UDP packet Inhalt: %s\n", incomingPacket);
      //Symbol für neue Daten empfangen kurz anzeigen
      DatenEmpfSymbol();                                      // Unterprogramm um Dateneingang als Animationspunkt auf OLED anzuzeigen
      Relais1 = bitRead(atoi(incomingPacket),0);
      Relais2 = bitRead(atoi(incomingPacket),1);
      Relais3 = bitRead(atoi(incomingPacket),2);
      Relais4 = bitRead(atoi(incomingPacket),3);
      Relais5 = bitRead(atoi(incomingPacket),4);
      Relais6 = bitRead(atoi(incomingPacket),5);
      Heizleistung=0;                                         
      if (Relais1==1){Heizleistung=Heizleistung+50;}
      if (Relais2==1){Heizleistung=Heizleistung+100;}
      if (Relais3==1){Heizleistung=Heizleistung+200;}
      if (Relais4==1){Heizleistung=Heizleistung+200;}
      if (Relais5==1){Heizleistung=Heizleistung+200;}
      if (Relais6==1){Heizleistung=Heizleistung+200;}
      Anzeige();                                              //Unterprogramm vfür OLED Datenanzeige
    }
}







void WiFiStart()                              // Unterprogramm um WiFi am Router anzumelden
{
  // Connect to WiFi network
  display.clear();
  display.setFont(ArialMT_Plain_10);
  display.drawString(0, 0, "Call to " + String(ssid));
  display.display();
  
  WiFi.begin(ssid, password);
  int i=0;
  while (WiFi.status() != WL_CONNECTED) {
    display.drawString(i, 9, ".");
    display.display();
    delay(500);
    i=i+3;
  }
  // Print the IP address
  IPAddress myIp = WiFi.localIP();
  sprintf(myIpString, "%d.%d.%d.%d", myIp[0], myIp[1], myIp[2], myIp[3]);   //IP muss in String umgewandelt werden
  display.clear();
  display.setFont(ArialMT_Plain_16);
  display.drawString(0, 0, myIpString);
  display.display();
  delay(2000);                                    // Unterprogramm aufrufen um Sprengerzeiten neu einzustellen
}





void Anzeige()                              // Unterprogramm um Daten auf OLED anzuzeigen
{
  display.clear();
  if (Relais1==1){display.fillCircle(3, 6, 3);}             //int16_t x, int16_t y, int16_t radius
  else {display.drawCircle(3, 6, 3);}
  if (Relais2==1){display.fillCircle(3, 16, 3);}
  else {display.drawCircle(3, 16, 3);}
  if (Relais3==1){display.fillCircle(3, 26, 3);}
  else {display.drawCircle(3, 26, 3);}
  if (Relais4==1){display.fillCircle(3, 38, 3);}
  else {display.drawCircle(3, 38, 3);}
  if (Relais5==1){display.fillCircle(3, 48, 3);}
  else {display.drawCircle(3, 48, 3);}
  if (Relais6==1){display.fillCircle(3, 58, 3);}
  else {display.drawCircle(3, 58, 3);}
  display.drawString(9, 0, "50W");
  display.drawString(9, 10, "100W");
  display.drawString(9, 20, "200W");
  display.drawString(9, 32, "200W");
  display.drawString(9, 42, "200W");
  display.drawString(9, 52, "200W");
  display.drawString(50, 33, "empf= " + String(incomingPacket));
  display.drawString(50, 43, "binaer= " + String(bitRead(atoi(incomingPacket),5)) + String(bitRead(atoi(incomingPacket),4)) + String(bitRead(atoi(incomingPacket),3)) + String(bitRead(atoi(incomingPacket),2)) + String(bitRead(atoi(incomingPacket),1)) + String(bitRead(atoi(incomingPacket),0)));
  display.drawString(50, 53, "HzLeist.=" + String(Heizleistung) + "W");
  display.display();
  delay(300);
}





void DatenEmpfSymbol()                              // Unterprogramm um Dateneingang als Animationspunkt auf OLED anzuzeigen
{
  display.drawCircle(122, 4, 1);
  display.display();
  delay(100);
  display.drawCircle(122, 4, 2);
  display.display();
  delay(100);
  display.setColor(BLACK);
  display.drawCircle(122, 4, 1);
  display.display();
  delay(100);
  display.setColor(WHITE);
  display.drawCircle(122, 4, 4);
  display.display();
  delay(100);
  display.setColor(BLACK);
  display.drawCircle(122, 4, 2);
  display.display();
  delay(100);
  display.drawCircle(122, 4, 4);
  display.display();
  display.setFont(ArialMT_Plain_10);
  display.setColor(WHITE);
}

Da ja nicht delay() durch millis() ersetzt wird, sondern das gesamte Konzept deiner loop-Schleife geändert wird, musst du schon etwas mehr bedenken.

Meine Fragen:
Während der Animation in DatenEmpfSymbol(); soll noch was genau parallel ablaufen ?
Wenn da etwas geschieht, welche Auswirkung soll das auf die Animation haben ?

Die Funktion Anzeige(); soll weiterhin nur dran kommen, wenn die Animation fertig ist und display.setColor(WHITE); aktiv ist, richtig?

display.setFont ist eigentlich in DatenEmpfSymbol überflüssig, richtig ?

Auf einem ESP (mit RTOS) ist das keine gute Idee.

Unter RTOS sollen Tasks laufen, mach Dich mal darüber schlau.

ESP8266 - hat kein RTOS.

Wenn eine Message kommt, dann einen boolWert setzen.
Die Funktion DatenEmpfSymbol()umschreiben mit switch/Case und am Ende den bool löschen.
Ist der gelöscht gehts wieder in die Anzeige.

Warum nutzt für die Relais 0 und 1 und nicht true/false bzw. HIGH/LOW? Das macht es übersichtlicher.

Ich plane vor: Es soll eine Uhr im Hintergrund laufen und ein sleep über Nacht schalten.

Die Funktion Anzeige kann parallel mitlaufen.

Theoretisch ja, praktisch aber kam es ohne zu seltsamer Anzeige der Zeichen.

Wie meinst du das?
Der boolWert schaltet ein Unterprogramm frei welches aus dem Haupt-loop aufgerufen wird?:thinking:

Denkanstoss:

#include <ESP8266WiFi.h>
#include <SSD1306Wire.h>          // für OLED` 128x64
#include <WiFiUdp.h>

//#define LED D7

WiFiUDP Udp;
unsigned int localUdpPort = 4210;     // local port to listen on
char befehl[8];                      // buffer for incoming packets in binär
boolean Relais1 = 0;
boolean Relais2 = 0;
boolean Relais3 = 0;
boolean Relais4 = 0;
boolean Relais5 = 0;
boolean Relais6 = 0;
char myIpString[24];          //um IP Adresse in String umzuwandeln und anzuzeigen

char *ssid = "++++++++++++";
char *password = "##########";

// Initialize the OLED display using Wire library
SSD1306Wire  display(0x3c, D1, D2);  //D2=SDK  D1=SCK  As per labeling on NodeMCU


//unsigned int localUdpPort = 4210;
char incomingPacket[256];
char replyPacket[] = "Hi there! Got the message :-)";
bool newMessage = false;


int Heizleistung = 0;

void setup()
{
  Serial.begin(9600);
  display.init();
  display.flipScreenVertically();
  display.setTextAlignment(TEXT_ALIGN_LEFT);
  display.setFont(ArialMT_Plain_16);
  //display.setFont(ArialMT_Plain_10);
  display.clear();
  display.drawString(0, 0, "Start");
  display.display();
  delay(1000);
  WiFiStart();                                //Unterprogramm verbindet ESP mit Router
  Udp.begin(localUdpPort);
  delay(3000);
}


void loop()
{
  int packetSize = Udp.parsePacket();
  if (packetSize)
  {
    //Serial.printf("Received %d bytes from %s, port %d\n", packetSize, Udp.remoteIP().toString().c_str(), Udp.remotePort());
    int len = Udp.read(incomingPacket, 255);
    if (len > 0)
    {
      incomingPacket[len] = '\0';
      newMessage = true;
    }
    //Serial.printf("UDP packet Inhalt: %s\n", incomingPacket);
    //Symbol für neue Daten empfangen kurz anzeigen
    DatenEmpfSymbol();                                      // Unterprogramm um Dateneingang als Animationspunkt auf OLED anzuzeigen
    Relais1 = bitRead(atoi(incomingPacket), 0);
    Relais2 = bitRead(atoi(incomingPacket), 1);
    Relais3 = bitRead(atoi(incomingPacket), 2);
    Relais4 = bitRead(atoi(incomingPacket), 3);
    Relais5 = bitRead(atoi(incomingPacket), 4);
    Relais6 = bitRead(atoi(incomingPacket), 5);
    Heizleistung = 0;
    if (Relais1 == 1) {Heizleistung = Heizleistung + 50;}
    if (Relais2 == 1) {Heizleistung = Heizleistung + 100;}
    if (Relais3 == 1) {Heizleistung = Heizleistung + 200;}
    if (Relais4 == 1) {Heizleistung = Heizleistung + 200;}
    if (Relais5 == 1) {Heizleistung = Heizleistung + 200;}
    if (Relais6 == 1) {Heizleistung = Heizleistung + 200;}
    if (!newMessage) Anzeige();                            //Unterprogramm vfür OLED Datenanzeige
  }
}

void WiFiStart()                              // Unterprogramm um WiFi am Router anzumelden
{
  // Connect to WiFi network
  display.clear();
  display.setFont(ArialMT_Plain_10);
  display.drawString(0, 0, "Call to " + String(ssid));
  display.display();
  WiFi.begin(ssid, password);
  int i = 0;
  while (WiFi.status() != WL_CONNECTED)
  {
    display.drawString(i, 9, ".");
    display.display();
    delay(500);
    i = i + 3;
  }
  // Print the IP address
  IPAddress myIp = WiFi.localIP();
  sprintf(myIpString, "%d.%d.%d.%d", myIp[0], myIp[1], myIp[2], myIp[3]);   //IP muss in String umgewandelt werden
  display.clear();
  display.setFont(ArialMT_Plain_16);
  display.drawString(0, 0, myIpString);
  display.display();
  delay(2000);                                    // Unterprogramm aufrufen um Sprengerzeiten neu einzustellen
}

void Anzeige()                              // Unterprogramm um Daten auf OLED anzuzeigen
{
  display.clear();
  if (Relais1 == 1) {display.fillCircle(3, 6, 3);}          //int16_t x, int16_t y, int16_t radius
  else {display.drawCircle(3, 6, 3);}
  if (Relais2 == 1) {display.fillCircle(3, 16, 3);}
  else {display.drawCircle(3, 16, 3);}
  if (Relais3 == 1) {display.fillCircle(3, 26, 3);}
  else {display.drawCircle(3, 26, 3);}
  if (Relais4 == 1) {display.fillCircle(3, 38, 3);}
  else {display.drawCircle(3, 38, 3);}
  if (Relais5 == 1) {display.fillCircle(3, 48, 3);}
  else {display.drawCircle(3, 48, 3);}
  if (Relais6 == 1) {display.fillCircle(3, 58, 3);}
  else {display.drawCircle(3, 58, 3);}
  display.drawString(9, 0, "50W");
  display.drawString(9, 10, "100W");
  display.drawString(9, 20, "200W");
  display.drawString(9, 32, "200W");
  display.drawString(9, 42, "200W");
  display.drawString(9, 52, "200W");
  display.drawString(50, 33, "empf= " + String(incomingPacket));
  display.drawString(50, 43, "binaer= " + String(bitRead(atoi(incomingPacket), 5)) + String(bitRead(atoi(incomingPacket), 4)) + String(bitRead(atoi(incomingPacket), 3)) + String(bitRead(atoi(incomingPacket), 2)) + String(bitRead(atoi(incomingPacket), 1)) + String(bitRead(atoi(incomingPacket), 0)));
  display.drawString(50, 53, "HzLeist.=" + String(Heizleistung) + "W");
  display.display();
  delay(300);
}


void DatenEmpfSymbol()                              // Unterprogramm um Dateneingang als Animationspunkt auf OLED anzuzeigen
{
  static byte symbol = 0;
  static unsigned long lastmillis = 0;
  if (newMessage == true)
  {
    switch (symbol)
  {
    case 0:
    display.drawCircle(122, 4, 1);
    display.display();
    lastmillis = millis();                      // Merken wann ausgelöst
    symbol ++;
    break;
  case 1:
    if (millis() - lastmillis >= 100)
    {
      display.drawCircle(122, 4, 2);
      display.display();
      lastmillis = millis();                   // Das kann ggfls. entfallen ...
     symbol ++;
    }
    break;
  case 2:
    if (millis() - lastmillis >= 100)          // ... wenn hier auf 200 geprüft wird ...
    {
      display.setColor(BLACK);
      display.drawCircle(122, 4, 1);
      display.display();
      lastmillis = millis();                   // ... dann hier auch weg ...
     symbol ++;
    }
    break;
  case 3:
    if (millis() - lastmillis >= 100)          // ... und hier 300 - usw.
    {
      display.setColor(WHITE);
      display.drawCircle(122, 4, 4);
      display.display();
      display.display();
      lastmillis = millis();
     symbol ++;
   }
    break;
  case 4:
    if (millis() - lastmillis >= 100)
    {
      display.setColor(BLACK);
      display.drawCircle(122, 4, 2);
      display.display();
      lastmillis = millis();
    symbol ++;
    }
    break;
  case 5:
    if (millis() - lastmillis >= 100)
    {
      display.drawCircle(122, 4, 4);
      display.display();
      display.setFont(ArialMT_Plain_10);
      display.setColor(WHITE);
      newMessage = false;
    }
  }
}
  if (!newMessage) symbol = 0;
}

Eine globale Variable newMessage.
Musst Du suchen, wo ich die eingetragen habe.
Ich hab die Anzeige ausgeblendet, wenn die gesetzt ist. Ob das richtig war...?
Die Funktion sollte machen, bitte lies meine Kommentare

1 Like

Danke!:wave:
Clever: Nur mit einer milli-Variable und switch & case hochzählen.:+1:

Klappt noch nicht ganz:
Anzeige & Animation laufen in Zeitlupe. Ich komme nicht drauf warum...

Ich momentan auch nicht.
Mal sehen, ob ich den Code verstehe....
Kann es sein, das die Reihenfolge im loop() Dir einen Streich spielt?
Wenn ich das richtig lese, brauchst Du für die Anzeige und die Animation IMMER ein packetSize != 0. Wenn Du aber im DatenEmpfSymbol() durch bist, ist packetsize evtl. noch gar nicht gefüllt, somit kommt weder die Animation noch die Anzeige.

Tausche mal loop

void loop()
{
  int packetSize = Udp.parsePacket();
  if (packetSize)
  {
    //Serial.printf("Received %d bytes from %s, port %d\n", packetSize, Udp.remoteIP().toString().c_str(), Udp.remotePort());
    int len = Udp.read(incomingPacket, 255);
    if (len > 0)
    {
      incomingPacket[len] = '\0';
      newMessage = true;
    }
    //Serial.printf("UDP packet Inhalt: %s\n", incomingPacket);
    //Symbol für neue Daten empfangen kurz anzeigen
    Relais1 = bitRead(atoi(incomingPacket), 0);
    Relais2 = bitRead(atoi(incomingPacket), 1);
    Relais3 = bitRead(atoi(incomingPacket), 2);
    Relais4 = bitRead(atoi(incomingPacket), 3);
    Relais5 = bitRead(atoi(incomingPacket), 4);
    Relais6 = bitRead(atoi(incomingPacket), 5);
    Heizleistung = 0;
    if (Relais1 == 1) {Heizleistung = Heizleistung + 50;}
    if (Relais2 == 1) {Heizleistung = Heizleistung + 100;}
    if (Relais3 == 1) {Heizleistung = Heizleistung + 200;}
    if (Relais4 == 1) {Heizleistung = Heizleistung + 200;}
    if (Relais5 == 1) {Heizleistung = Heizleistung + 200;}
    if (Relais6 == 1) {Heizleistung = Heizleistung + 200;}
  }
  DatenEmpfSymbol();                                      // Unterprogramm um Dateneingang als Animationspunkt auf OLED anzuzeigen
  if (!newMessage) Anzeige();                            //Unterprogramm vfür OLED Datenanzeige
}
1 Like

Ja, jetzt funktioniert es!:+1:
Erst mal drauf kommen...

Naja, is halt Logik.
Sag mal, warum hast Du in der Anzeige nach der dritten Zeile die Positionierung geändert?

  display.drawString(9, 0, "50W");
  display.drawString(9, 10, "100W");  <- +10
  display.drawString(9, 20, "200W");  <- +10
  display.drawString(9, 32, "200W");  <- +12 !!
  display.drawString(9, 42, "200W");  <- +10
  display.drawString(9, 52, "200W");  <- +10
// bzw:
display.fillCircle(3, 6, 3)
display.fillCircle(3, 16, 3) <- +10
display.fillCircle(3, 26, 3) <- +10
display.fillCircle(3, 38, 3) <- +12
display.fillCircle(3, 48, 3) <- +10
display.fillCircle(3, 58, 3) <- +10

Wenn das da auch ein 10er wäre, könnte der ganze Code massiv runtergekürzt werden.

... ein Array mit {0, 10,10,12,10,10} könnte hier zweimal helfen ... oder fertig aufaddiert... 0, 10, 20, 32, 42, 52

Das wollte ich vermeiden.
Mein Ansatz ist das während der Laufzeit zu errechnen:

void anzeige()                              // Unterprogramm um Daten auf OLED anzuzeigen
{
  //int16_t x, int16_t y, int16_t radius
  int16_t xCircle = 3;
  int16_t xString = 9;
  int16_t y = 6;
  int16_t r = 3;
  const int16_t line = 10;
  for (byte b = 0; b < numRelais; b++)
  {
    relais[b] ? display.fillCircle(x, y + b * line, r) : display.drawCircle(x, y + b * line, r);
    myString = String(leistung[b]) + "W";
    display.drawString(xString, b * line, myString);
  }
  display.drawString(50, 33, "empf: " + String(incomingPacket));
  myString = "binaer: ";
  for (byte b = numRelais; b > 0; b--)
  {myString = myString + String(relais[b - 1]);}
  display.drawString(50, 43, myString);
  display.drawString(50, 53, "HzLeist.: " + String(heizLeistung) + "W");
  display.display();
  delay(300);
}

Da ich das display.drawstring wegen der fehlenden Unterstützung hier derzeit auch nicht compilieren kann ist das (noch) kein const oben geworden...

war nur ein Vorschlag. Du machst das schon.

mehr weh tun ja eh derartiges Konstrukte ... um wie viel einfacher würde dieser Sketch wenn man das eine oder Array oder zusammengehörige Daten in einer Struktur zusammenfassen würde ...

Auch schon erledigt :wink:
Hier mal mein Grundgerüst, aber noch nicht durchgesehen und ggfls. sind noch Fehler in der Schreibweise...

#include <ESP8266WiFi.h>
#include <SSD1306Wire.h>          // für OLED` 128x64
#include <WiFiUdp.h>

//#define LED D7

WiFiUDP Udp;
unsigned int localUdpPort = 4210;     // local port to listen on
char befehl[8];                      // buffer for incoming packets in binär


const uint8_t relaisNum = 6;
bool relais[relaisNum] = {false};
uint16_t leistung[relaisNum] = {50, 100, 200, 200, 200, 200};
uint16_t heizLeistung = 0;
String myString;

char myIpString[24];          //um IP Adresse in String umzuwandeln und anzuzeigen

char *ssid = "++++++++++++";
char *password = "##########";

// Initialize the OLED display using Wire library
SSD1306Wire  display(0x3c, D1, D2);  //D2=SDK  D1=SCK  As per labeling on NodeMCU

//unsigned int localUdpPort = 4210;
char incomingPacket[256];
char replyPacket[] = "Hi there! Got the message :-)";
bool newMessage = false;


void WiFiStart()                              // Unterprogramm um WiFi am Router anzumelden
{
  // Connect to WiFi network
  display.clear();
  display.setFont(ArialMT_Plain_10);
  display.drawString(0, 0, "Call to " + String(ssid));
  display.display();
  WiFi.begin(ssid, password);
  int i = 0;
  while (WiFi.status() != WL_CONNECTED)
  {
    display.drawString(i, 9, ".");
    display.display();
    delay(500);
    i += 3;
  }
  // Print the IP address
  IPAddress myIp = WiFi.localIP();
  sprintf(myIpString, "%d.%d.%d.%d", myIp[0], myIp[1], myIp[2], myIp[3]);   //IP muss in String umgewandelt werden
  display.clear();
  display.setFont(ArialMT_Plain_16);
  display.drawString(0, 0, myIpString);
  display.display();
  delay(2000);                                    // Unterprogramm aufrufen um Sprengerzeiten neu einzustellen
}

displayStart()
{
  display.init();
  display.flipScreenVertically();
  display.setTextAlignment(TEXT_ALIGN_LEFT);
  display.setFont(ArialMT_Plain_16);
  //display.setFont(ArialMT_Plain_10);
  display.clear();
  display.drawString(0, 0, "Start...");
  display.display();
  delay(1000);
}

void setup()
{
  Serial.begin(9600);
  myString.reserve(25);
  displayStart();
  WiFiStart();                                //Unterprogramm verbindet ESP mit Router
  Udp.begin(localUdpPort);
  delay(3000);
}

void loop()
{
  int packetSize = Udp.parsePacket();
  if (packetSize)
  {
    //Serial.printf("Received %d bytes from %s, port %d\n", packetSize, Udp.remoteIP().toString().c_str(), Udp.remotePort());
    int len = Udp.read(incomingPacket, 255);
    if (len > 0)
    {
      incomingPacket[len] = '\0';
      newMessage = true;
    }
    //Serial.printf("UDP packet Inhalt: %s\n", incomingPacket);
    heizLeistung = 0;
    for (byte b = 0; b < numRelais; b++)
    {
      relais[b] = bitRead(atoi(incomingPacket), b);
      if (relais[b]) heizLeistung += leistung[b];
    }
  }
  if (!newMessage) printNewData();  //Unterprogramm vfür OLED Datenanzeige
}


void anzeige()                              // Unterprogramm um Daten auf OLED anzuzeigen
{
  //int16_t x, int16_t y, int16_t radius
  int16_t xCircle = 3;
  int16_t xString = 9;
  int16_t y = 6;
  int16_t r = 3;
  const int16_t line = 10;
  for (byte b = 0; b < numRelais; b++)
  {
    relais[b] ? display.fillCircle(x, y + b * line, r) : display.drawCircle(x, y + b * line, r);
    myString = String(leistung[b]) + "W";
    display.drawString(xString, b * lin, myString);
  }
  display.drawString(50, 33, "empf: " + String(incomingPacket));
  myString = "binaer: ";
  for (byte b = numRelais; b > 0; b--)
  {myString = myString + String(relais[b - 1]);}
  display.drawString(50, 43, myString);
  display.drawString(50, 53, "HzLeist.: " + String(heizLeistung) + "W");
  display.display();
  delay(300);
}

void printNewData()                              // Unterprogramm um Dateneingang als Animationspunkt auf OLED anzuzeigen
{
  static byte symbol = 0;
  static unsigned long lastmillis = 0;
  const unsigned int pause = 100;               // Zeit in ms
  const uint16_t xCircle = 122;
  const uint16_t yCircle = 4;
  if (newMessage == true)
  {
    switch (symbol)
    {
      case 0:
        display.clear();
        display.drawCircle(xCircle, yCircle, 1);
        display.display();
        lastmillis = millis();                      // Merken wann ausgelöst
        symbol ++;
        break;
      case 1:
        if (millis() - lastmillis >= pause * symbol)
        {
          display.drawCircle(xCircle, yCircle, 2);
          display.display();
          symbol ++;
        }
        break;
      case 2:
        if (millis() - lastmillis >= pause * symbol)
        {
          display.setColor(BLACK);
          display.drawCircle(xCircle, yCircle, 1);
          display.display();
          symbol ++;
        }
        break;
      case 3:
        if (millis() - lastmillis >= pause * symbol)
        {
          display.setColor(WHITE);
          display.drawCircle(xCircle, yCircle, 4);
          display.display();
          symbol ++;
        }
        break;
      case 4:
        if (millis() - lastmillis >= pause * symbol)
        {
          display.setColor(BLACK);
          display.drawCircle(xCircle, yCircle, 2);
          display.display();
          symbol ++;
        }
        break;
      case 5:
        if (millis() - lastmillis >= pause * symbol)
        {
          display.drawCircle(xCircle, yCircle, 4);
          display.display();
          display.setFont(ArialMT_Plain_10);
          display.setColor(WHITE);
        }
        break;
      case 6:
        if (millis() - lastmillis >= pause * symbol)
        {
          anzeige();
          newMessage = false;
        }
        break;
    }
  }
  if (!newMessage) symbol = 0;
}

@noiasca sag mal, das bei drawString muss doch gar kein String sein, oder übersehe ich was?
Weil dann würde das ein normales charArray werden und schick befüllt während der Laufzeit ohne reserve().

Geht nicht ganz auf um es mittig und gleichmäßig auf dem OLED zu verteilen.

Kannst Du mal nen Bild mit dem 12er und ein Bild mit nem 10er machen, damit ich ein Gefühl dafür bekomme?