TFT Flakter -> Sketch zu groß!

Hey zusammen!

Ich hab mal wieder ein Problem und komm diesbezüglich zu euch!
Also zum Projekt, ich mach mir ein Modul für mein Motorrad mit TFT Display, GPS und einem MPU5060.
Die einzelnen “Codes” funktionieren alle soweit nun bin ich dabei alles in einen Sketch zu schreiben.
Das hat bis her auch ganz gut Funktioniert nur hab ich das Problem das bei der Wertausgabe (Uhr) die Zahl entweder Flacker oder garnicht überschrieben wird. Nun hab ich ein bisschen gelesen und bin auf printNumber (utft library) bzw drawNumber(bei meiner library) gestoßen was auch super funktioniert. Wenn ich aber jedoch printNumber/drawNumber öfters in meinem Sketch verwende wird er zu groß für den nano.

Hab jetzt noch was im Netz gefunden:

Hier noch meine TFT library

Kann es aber leider nicht so einbauen das es bei mir Funktioniert…
Hat jemand ne andere Idee und wenn ja kann ich so auch die km/h ohne flacker anzeigen lassen?

Hier noch der Sketch!

//---------------------------------------TFT-Display
#include <Adafruit_GFX_AS.h>   
#include <Adafruit_ST7735_AS.h> 
#include <SPI.h>

#define TFT_CS     10
#define TFT_RST    9  
#define TFT_DC     8
#define TFT_SCLK   13  
#define TFT_MOSI   11   

Adafruit_ST7735_AS tft = Adafruit_ST7735_AS (TFT_CS,  TFT_DC, TFT_RST);

volatile int state=1;                   
volatile unsigned long lastTime=0;
void prettyPrint(long value, int width, bool rightadjust = true);      

//-----------------------------------------------GPS
#include <TinyGPS++.h>
#include <SoftwareSerial.h>

TinyGPSPlus gps;
SoftwareSerial ss(5, 4);

//--------------------------------------------Button
byte a = 0;

const byte buttonPin1 = 3;
const byte buttonPin2 = 6;

byte button1 = 0;
byte button2 = 0;

//----------------------------------------Void-Setup
void setup() {

  pinMode(buttonPin1, INPUT);
  pinMode(buttonPin2, INPUT);
  digitalWrite(buttonPin1, HIGH);
  digitalWrite(buttonPin2, HIGH);

  Serial.begin(115200);
  ss.begin(9600);

  tft.initR(INITR_BLACKTAB);
  tft.fillScreen(ST7735_BLACK);
  tft.setRotation(3);
  tft.setTextWrap(false);
  tft.setCursor(20, 40);
  tft.setTextColor(ST7735_WHITE);
  tft.setTextSize(3);
  tft.println("Test");
  tft.setCursor(55, 65);
  tft.println("BOARD");
  tft.setCursor(2, 118);
  tft.setTextSize(1);
  tft.println("Software V1.0");
  delay(3000);
  
  attachInterrupt(1, keyPressed, FALLING);  
}

//----------------------------------------KeyPressed
void keyPressed(){                   
  unsigned long now = millis();
  if (now - lastTime > 300){           
    state++;
    if (state > 6){state=1;}
  }
  lastTime=now;
}

//-----------------------------------------Void-Loop
void loop() {
  
  button1 = digitalRead(buttonPin1);
  button2 = digitalRead(buttonPin2);
      
    switch(state) {
     case 1:     frame_1();
                 break;
     case 2:     frame_2();
                 break;
     case 3:     frame_3();
                 break;
     case 4:     frame_4();
                 break;
     case 5:     frame_5();
                 break;
     case 6:     frame_6();
                 break;                 
     default:
          state = 1;
          break;
    }
    
  while (ss.available() > 0)
  gps.encode(ss.read()); 
}

//--------------------------------------------Frames
void frame_1()
{ 
  if (a <= 0)
  {
    tft.fillScreen(ST7735_BLACK);
    a = 1;
  }

  tft.setTextColor(ST7735_WHITE);
  tft.setCursor(50, 50);
  tft.printNumber(gps.time.hour()); //!!!!!!!!
  tft.print(":");
   tft.printNumber(gps.time.minute()); //!!!!!!!!
  tft.setCursor(2, 118);
  tft.setTextSize(1);
  tft.print("Clock");
  tft.setCursor(120, 118);
  tft.print("Sat.:");
  tft.printNumber(gps.satellites.value()); //!!!!!!!!
  delay(1000);
}

void frame_2()
{ 
  if (a <= 1)
  {
    tft.fillScreen(ST7735_BLACK);
    a = 2;
  }
  
  tft.setTextColor(ST7735_WHITE);
  tft.setCursor(2, 118);
  tft.setTextSize(1);
  tft.println("Speed");
}

void frame_3()
{ 
  if (a <= 2)
  {
    tft.fillScreen(ST7735_BLACK);
    a = 3;
  }  
  
  tft.setTextColor(ST7735_WHITE);
  tft.setCursor(2, 118);
  tft.setTextSize(1);
  tft.println("0-100");
}

void frame_4()
{
  if (a <= 3)
  {
    tft.fillScreen(ST7735_BLACK);
    a = 4;
  }
     
  tft.setTextColor(ST7735_WHITE);
  tft.setCursor(2, 118);
  tft.setTextSize(1);
  tft.println("100-200");
}

void frame_5()
{
  if (a <= 4)
  {
    tft.fillScreen(ST7735_BLACK);
    a = 5;
  }
     
  tft.setTextColor(ST7735_WHITE);
  tft.setCursor(2, 118);
  tft.setTextSize(1);
  tft.println("100-0");
}

void frame_6()
{
  if (a == 5)
  {
    tft.fillScreen(ST7735_BLACK);
    a = 0;
  }
     
  tft.setTextColor(ST7735_WHITE);
  tft.setCursor(2, 118);
  tft.setTextSize(1);
  tft.println("Angle");
}

mfg Fabi

Wenn's flackert wirst Du zu schnell auf das Display schreiben.
Hab den Sketch aber nicht verinnerlicht (ist mir zu lang auf die Schnelle :grin:), bin aber ziemlich sicher dass es das ist.

Hey danke schon mal für deine Antwort, aber soweit war ich jetzt auch schon nur muss das alles auch ziemlich fix funktionieren, ich hab eine Funktion drin die die Zeit von 0-100 misst und die Ausgabe ist neunmal in Millisekunden. Deswegen meine ich muss es doch einen anderen Weg geben als die ganze Zahl zu überschreiben…

Mfg fabi

Ähh, wie bitte????

skaterfabi11:
Hey danke schon mal für deine Antwort, aber soweit war ich jetzt auch schon nur muss das alles auch ziemlich fix funktionieren, ich hab eine Funktion drin die die Zeit von 0-100 misst und die Ausgabe ist neunmal in Millisekunden. Deswegen meine ich muss es doch einen anderen Weg geben als die ganze Zahl zu überschreiben…

Mfg fabi

Das ist schwer zu verstehen und du solltest es besser erklären.

Allerdings wenn du einen Displaywert schnell hintereinander überschreibst, ist es kein Wunder das es flackert.

Also nochmal vom vorne :smiley:

Ich will ja z.b. die Funktion, Zeitmessung 0-100 einbauen (im Sketch noch nicht drin) und weil ich die zeit in Millisekunden anzeigen lassen will aktualisiert sich der Wert unweigerlich im Millisekunden Takt. Meine Frage war jetzt ob es irgendwie möglich ist nicht die komplette Zahl zu überschreiben sondern vielleicht nur die benötigte stelle das quasi nicht der ganze wert zu flackern beginnt. Oder ist es möglich den Wert zu buffern und trotzdem eine saubere Anzeige zu bekommen?

Du weißt aber schon, dass das Auge ab 25 Hz eh nix mehr unterscheiden kann? Und das wären dann so locker 40 ms.

Ja das hab ich auch gedacht jedoch funktioniert das nicht wenn ich den Wert so schnell aktualisiere keine Ahnung wieso?! Display zu lansam?

Nano zu langsam. Miss mal, wie lange dein Loop braucht.

Das Display mag die Daten schnell entgegen nehmen, aber die Ausgabe dauert "relativ " lange, durch die Trägheit der LC. Kann man das vereinfacht so sagen?

Jup kann man kapieren :slight_smile:

Kann es leider gerade nicht messen. Aber gibt es eine lösen (wie oben bereits gefragt) das man nur die einzelnen Ziffern der gesamten Zahl überschreibt?

Bsp:

0-100 in 13,67.6 Sekunden.
Jetzt wird ja bei jeder Millisekunde der komplette Wert überschrieben aber es würde ja jetzt theoretisch reichen wenn er die Sekunden nur jede Sekunde überschreibt die 10 nur alle 10 Millisekunde... so das quasi nicht meine komplette angegebene Zeit flackert....

Hoffe das war jetzt ein wenig verständlicher :blush:

Ich würde das anders machen.

im millisekundentakt ein Display zu beschreiben ist völliger Blödsinn.
Selbst wenn du nur alle 100ms einen Wert schreibst, kann das Auge das kaum noch erkennen.

Ich würde eine eigene Funktion schreiben, die in festem Rhytmus das Display aktualisiert, und in den anderen Funkionen nur die Variablen berechnen, die dann ausgegeben werden.

void display(int newval){
  static unsigned long lastUpdate = 0;
  if (millis()-100 < lastUpdate) return;
  lastUpdate = millis();

  static lastval=0;
  if (newval == lastval) return;
  lastval = newval;
// newval auf Display schreiben.
}

Hier nur mal ein Beispiel für einen int Wert.

Du kannst doch mit:

  tft.setCursor(nnn, nnn);
  tft.print("1");

eine einzelne Ziffer anspringen und diese ändern.

Wenn du vorher den Wert der zu ändernden Ziffer mit dem aktuellen Inhalt vergleichst, änderst du nur die Stellen, die auch den Wert geändert haben.
Dann flackert nicht die gesamte Zeile. Ich denke, so kann es funktionieren.

skaterfabi11:
Aber gibt es eine lösen (wie oben bereits gefragt) das man nur die einzelnen Ziffern der gesamten Zahl

Du musst dir nur eine Formatierungs-Funktion schreiben;

void setup()
{
  Serial.begin(9600);

  printNumber(0);
  printNumber(5);
  printNumber(43);
  printNumber(125);
}

void loop() 
{
}

void printNumber(byte num)
{
  char buffer[] = "000";
  int index = sizeof(buffer) - 2;

  while (num > 0 && index >= 0)
  {
    buffer[index--] = (num % 10) + '0';
    num /= 10;
  }

  Serial.println(buffer);
}

Für den TFT kannst du noch die Koordinaten als Parameter übergeben

Aber das alle 1ms zu machen geht trotzdem nicht!! Siehe guntherb

Mhm okay schonmal vielen dank für eure Vorschläge.

@Serenifly ich hab schon bei einem anderen Forumbeitrag diesen Code von dir gefunden:

void prettyPrint(long value, int width, bool rightadjust = false);

void setup()
{
  Serial.begin(9600);
}

void loop()
{
  prettyPrint(10, 3);
  prettyPrint(100, 3);
  prettyPrint(1000, 3);
  prettyPrint(10, 4);
  prettyPrint(100, 4);
  prettyPrint(1000, 4);
  prettyPrint(10, 5);
  prettyPrint(100, 5);
  prettyPrint(1000, 5);
  prettyPrint(10, 6, true);
  prettyPrint(100, 6, true);
  prettyPrint(1000, 6, true);
  prettyPrint(10, 4, true);
  prettyPrint(100, 4, true);
  prettyPrint(1000, 4, true);

  Serial.println();
  delay(2000);
}

void prettyPrint(long value, int width, bool rightadjust)
{
  long val = (value < 0) ? value * -1 : value;
  if (value < 0) width--;

  if (!rightadjust) Serial.print(value);

  unsigned long num = 10;
  for (int i = 0; i < width - 1; i++)
  {
    if (val < num) Serial.print(' ');
    num = num * 10;
  }

  if (rightadjust) Serial.print(value);

  Serial.println();   //diese Zeile bei LCDs entfernen!
}

könntest du mir bitte erklären wie er Funktioniert bzw wie ich ihn bei mir einbingen kann(bereits versucht aber gescheitert :astonished: )? Werde aus dem Code nicht gerade schlau.

Mfg fabi

Wenn du nur 3-stellige Zahlen hast ist der Code aus #12 einfacher

Der andere Code funktioniert mit Klassen die die Arduino print() Methode unterstützen. Also Zeichen schreiben und danach die Position automatisch inkrementieren. Laut HotSystems würde das bei Adafruit gehen. Aber bei UTFT geht es nicht!

Du müsstest nur Serial durch tft austauschen und das println() ganz am Ende entfernen. Außerdem brauchst du nur den Prototyp in der ersten Zeile und die prettyPrint() Funktion selbst. Das in loop() ist Test-Code um zu zeigen wie man die Funktion verwendet.
Aber da ist Zeug drin dass du nicht braucht. #12 formatiert einfach eine 3-stellige Ziffer und ist ganz kurz, wobei man das auch auf mehr erweitern könnte.

Probier erst mal was ich hier gepostet habe und kombiniere dass mit einer zeitlichen Verzögerung per millis(). Alle 1ms zu schreiben kannst du sowieso nicht lesen.

Wobei mit Adafruit auch das gehen sollte:

void printNumber(int num)
{   
   lcd.print(num);

   if (num < 1000) lcd.print(' ');
   if (num < 100) lcd.print(' ');
   if (num < 10) lcd.print(' ');
}

Das ist linksbündig. Wenn du willst kann man das auch rechtsbündig machen. Dazu musst du nur die Reihenfolge von print(’ ') und print(num) rumdrehen. Nullen statt Leerzeichen gehen natürlich auch.

Das ist noch einfacher und besser als das von oben. Sowas geht halt nicht mit UTFT. Deshalb bist du vielleicht daran gescheitert.

So ich wieder =D

Danke Serenifly habs jetzt kapiert und konnte es au super einbinden =)
leider funktioniert es trozdem nicht so wie ich das gerne hätte, da der Wert nicht neu geschrieben wir sondern nur dauf geschrieben wir das bedeutet das nach kürzester Zeit die Zahl bei jeder stelle ein "ausgemaltes" Kästchen angezeigt wird. Liegt das nur an der library? Wenn ich den "Wert" wieder lösche fägt es wieder an zu flackern... werd das ganze nochmal mit utft probieren...

mfg fabi

Wenn das der Fall ist liegt es an der Library. Mit der Adafruit habe ich noch nichts gemacht, aber normal sollte neuer Text an gleichen Stelle auch wirklich alle Pixel überschreiben. Wundert mich sehr dass das nicht so ist.

Bei UTFT kannst du aber so nicht print() machen. Da brauchst du dann die Variante aus #12 die erst mal einen Puffer beschreibt und dann wird der gesamte Puffer auf einmal gedruckt. Die Breite ist da aber nicht variabel einstellbar. Ich hatte es mit 3 Stellen gemacht weil du Zahlen von 0-100 erwähnt hast.

Geht auch mit einer Uhrzeit so ähnlich:

void setup()
{
  Serial.begin(9600);

  printTime(23, 45, 35);
}

void loop()
{
}

void printTime(byte hour, byte minute, byte second)
{
  char buffer[] = "00:00:00";

  buffer[0] += (hour / 10);
  buffer[1] += (hour % 10);
  buffer[3] += (minute / 10);
  buffer[4] += (minute % 10);
  buffer[6] += (second / 10);
  buffer[7] += (second % 10);

  Serial.print(buffer);
}

Da gibt es auch bequemere Funktionen die sowas automatisch machen, aber die sind nichts wenn du keinen Speicher mehr frei hast, da die viel fressen.

Wo du übrigens mit UTFT ein wenig Speicher sparen kannst ist wenn du memorysaver.h öffnest und die nicht benötigten Treiber abschaltest. Also nur die Zeile auskommentieren die zu deinem Treiber gehört

Also mit der Utft geht das ganze nicht. Alleine wenn ich sie schon einbinde ist der Sketch zu groß.
Ich such mal was neues bzw muss die und anderen libraries verkleiner!

Danke an alle für eure bemühungen!

Ist ein Arduino Mega eine Option?

Ansonsten sollte sich mal jemand mit Adafruit Erfahrung melden. Wundert mich doch sehr dass man Text da nicht einfach direkt überschreiben kann.

Nope ist leider keine Option da er von der Baugröße einfach zu groß ist.
Vielleicht sollte ich es doch mit nur einem Leistungsfähigeren Chip über Bascom probieren.

mfg Fabi