TFT "flackert"

hallo,

Habn problem bzw versuche grade eine DCF77 Uhr auf einem GLCD mit anzeige zu realisieren.

Nun habe ich das Problem das die angzeigten bereiche flackern bzw zu oft oder zu schnell neu schreiben und es dadurch scheiße aussieht. genauso die werte vom Cap sensor (wasserstand capacitiv)

der code:

#include <UTFT.h>
#include <CapacitiveSensor.h>
#include <DCF77.h>
#include <Time.h>
#include <UTouch.h>

#define DCF_PIN 23
#define DCF_INTERRUPT 23

time_t time;

extern uint8_t SmallFont[];

int count = 0 ;
const int maxpin = 8;
const int minpin = 9;
int maxpinstate = 0;
int minpinstate = 0;
long minlvl = 0;
long maxlvl = 0;
long offset = 0;
long prozent1 = 0;
long prozent2 = 0;
int firststart = 1;
uint8_t  fileid;
uint16_t filetype;

DCF77 DCF = DCF77(DCF_PIN, DCF_INTERRUPT);
CapacitiveSensor   liquidLevel = CapacitiveSensor(12, 13);
UTFT myGLCD(CTE50, 25, 26, 27, 28);
UTouch  myTouch( 6, 5, 4, 3, 2);



void setup()
{
  Serial.begin(9600);
  DCF.Start();
  setSyncInterval(30);
  setSyncProvider(DCF.getTime);
  Serial.println("Start!");
  pinMode(maxpin, INPUT);
  pinMode(minpin, INPUT);
  myGLCD.InitLCD();
  myGLCD.setFont(SmallFont);
  myGLCD.clrScr();


  Serial.println("Waiting for DCF77 time ... ");
  Serial.println("It will take at least 2 minutes until a first update can be processed.");
}

void loop()
{
  time_t DCFtime = DCF.getTime(); // Check if new DCF77 time is available
  count++ ;

  maxpinstate = digitalRead(maxpin);
  minpinstate = digitalRead(minpin);
  //long total =  liquidLevel.capacitiveSensor(50);
  long total = 0;

  myGLCD.print("    ", 280 , 10);
  myGLCD.printNumI(total, 280 , 10);

  if (firststart == 1) {


    Serial.println("Warte auf MIN Wert...");
    myGLCD.print("Warte auf MIN Wert...", 30, 20);
    Serial.println("Warte auf MAX Wert...");
    myGLCD.print("Warte auf MAX Wert...", 30, 50);


    // if (minpinstate == HIGH) {
    if (count == 50) {
      Serial.println("MIN WERT GESETZT auf:");
      myGLCD.print("MIN WERT GESETZT auf:", 30, 35);
      minlvl = total;
      Serial.print(minlvl);
      myGLCD.printNumI(minlvl, 200, 35);
      delay(500);
    }

    // if (maxpinstate == HIGH) {
    if (count == 100) {
      Serial.println("MAX WERT GESETZT auf:");
      myGLCD.print("MAX WERT GESETZT auf:", 30, 65);
      maxlvl = total;
      Serial.print(maxlvl);
      myGLCD.printNumI(maxlvl, 200, 65);
      delay(500);
      myGLCD.clrScr();
      firststart = 0;
    }

  }

  if (firststart == 0) {


    prozent1 = maxlvl / 100;
    prozent2 = total / prozent1;

    myGLCD.print("           ", 40, 10);
    myGLCD.print("           ", 40, 30);
    myGLCD.print("           ", 40, 50);
    myGLCD.print("           ", 40, 70);
    myGLCD.print("           ", 40, 90);
    myGLCD.print("           ", 40, 110);

    myGLCD.print("Max:", 10, 10);
    myGLCD.print("Min:", 10, 30);
    myGLCD.print("LVL:", 10, 50);
    myGLCD.print("Hour:", 10, 70);
    myGLCD.print("Min:", 10, 90);
    myGLCD.print("Sek:", 10, 110);

    myGLCD.printNumI(maxlvl, 40, 10);
    myGLCD.printNumI(minlvl, 40, 30);
    myGLCD.printNumI(prozent2, 40, 50);
    myGLCD.printNumI(hour(), 45, 70);
    myGLCD.printNumI(minute(), 45, 90);
    myGLCD.printNumI(second(), 45, 110);

        Serial.println("max:");
        Serial.println(maxlvl);
        Serial.println("min:");
        Serial.println(minlvl);
        Serial.println("prozent1:");
        Serial.println(prozent1);
        Serial.println("prozent2:");
        Serial.println(prozent2);
  }


  // delay (400);
}

void printDigits(int digits) {
  // utility function for digital clock display: prints preceding colon and leading 0
  Serial.print(":");
  if (digits < 10)
    Serial.print('0');
  Serial.print(digits);
}

unsigned long getDCFTime()
{
  time_t DCFtime = DCF.getTime();
  // Indicator that a time check is done
  if (DCFtime != 0) {
    Serial.print("X");
  }
  return DCFtime;
}

Du solltest dich dringend um den Speicherbedarf kümmern - > F-Makro

Was soll count bewirken? Dass du alle 50x, wenn die loop durchlaufen wird, das Display neubeschrieben wird?

Trenne die grafische Ausgabe von deinem eigentlich Programm. Soll heißen, nur an das Display senden, wenn sich ein Zeichen geändert hat, und dann auch nur die geänderten Zeichen und nicht den ganzen Inhalt.

Das LCD erst mit Leerzeichen zu beschreiben und dann mit dem eigentlichen Text ist sehr schlecht. Schreibe direkt drauf und überschreibe nur die Differenz zum vorherigen Text mit Leerzeichen wenn nötig.

Zahlen kann man außerdem einfach auf eine konstante Breite formatieren. Entweder per Hand oder per sprintf(). Verschiedene Varianten davon:

http://forum.arduino.cc/index.php?topic=345879.msg2384221#msg2384221
http://forum.arduino.cc/index.php?topic=303009.msg2108779#msg2108779

Kann man mit Nullen oder Leerzeichen machen. Man kann das Füllzeichen auch als zusätzlichen Parameter übergeben. Dann kann man wählen.

Wobei sich bei TFTs da generell s(n)printf() anbietet, da die Libraries den Text meistens als ganzes erwarten. Dann erstellt man einen Puffer, formatiert seine Zahlen und übergibt dann den Puffer an die LCD Library. Aber auch die oben gezeigten Funktionen lassen sich so umbauen dass man einen Puffer damit per Hand beschreibt. Man braucht halt noch itoa() und ähnliches für die Integer->Array Konvertierung.

Was soll count bewirken? Dass du alle 50x, wenn die loop durchlaufen wird, das Display neubeschrieben wird?

das count ist nur zu bastelzwecken da - entfällt wieder..

Du solltest dich dringend um den Speicherbedarf kümmern - > F-Makro

Der Sketch verwendet 44.168 Bytes (8%) des Programmspeicherplatzes. Das Maximum sind 524.288 Bytes.

das mit den leerzeichen versuche ich mal, danke

Um Integer auf eine konstante Breite zu formatieren unter Verwendung eines Puffers:

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

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

  prettyPrint(10, 3);
  prettyPrint(100, 3);
  prettyPrint(1000, 3);
  prettyPrint(10, 4);
  prettyPrint(100, 4);
  prettyPrint(1000, 4);
  prettyPrint(10, 5, true, '0' );
  prettyPrint(100, 5, true, '0');
  prettyPrint(1000, 5, true, '0');
  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, 6, true);
  prettyPrint(-100, 6, true);
  prettyPrint(-1000, 6, true);
}

void loop()
{
}

void prettyPrint(long value, int width, bool rightadjust, char fill)
{
  char buffer[20];
  byte index = 0;
  if (value < 0) width--;

  if (!rightadjust)
  { 
    ltoa(value, buffer, 10);
    index = strlen(buffer);
  }

  long val = (value < 0) ? value * -1 : value;
  unsigned long num = 10;
  for (int i = 0; i < width - 1; i++)
  {
    if (val < num) buffer[index++] = fill;
    num = num * 10;
  }

  if (rightadjust) 
    ltoa(value, &buffer[index], 10);
  else
    buffer[index] = '\0';

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

Am Ende dann Serial auf LCD ändern und das println() weglassen. Ich hoffe es haben sich keine Fehler eingeschlichen

'0' als Füllzeichen macht natürlich nur rechtsbündig Sinn. Außerdem nur mit positiven Zahlen bei dieser Version.

Du kannst auch einfach snprintf() verwenden. Das ist gerade bei Uhrzeiten schön:

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

  char buffer[10];
  byte hour = 12;
  byte minute = 5;
  byte second = 9;
  
  snprintf(buffer, sizeof(buffer), "%5d", hour);
  Serial.println(buffer);
  snprintf(buffer, sizeof(buffer), "%-5d", hour);
  Serial.println(buffer);
  snprintf(buffer, sizeof(buffer), "%05d", hour);
  Serial.println(buffer);
  snprintf(buffer, sizeof(buffer), "%02d:%02d:%02d", hour, minute, second);
  Serial.println(buffer);
}

void loop()
{
}

Du kannst prettyPrint() auch leicht so umschreiben, dass es standardmäßig rechtsbündig ist wie printf(). Geschmackssache

Danke,

habs so gemacht

sprintf(uhrzeit,"%02d:%02d:%02d", hour(), minute(), second());

ok so und wo habe ich hier den fehler?

myGLCD.print(prettyPrint(prozent2, 3), 40, 50);

habe in der prettyPrint funktion am ende

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

durch

return buffer;

ersetz

würde die funktion gerne so nutzen

das ist der fehler

terra.ino: In function 'void loop()':
terra:124: error: invalid use of void expression
terra.ino: In function 'void prettyPrint(long int, int, bool, char)':
terra:190: error: return-statement with a value, in function returning 'void' [-fpermissive]
invalid use of void expression

Dazu musst du noch mehr ändern.

Hier den Rückgabe-Wert

char* prettyPrint(long value, int width, bool rightadjust = false, char fill = ' ');
char* prettyPrint(long value, int width, bool rightadjust, char fill)

Das ist es was klar angemeckert wird:

return-statement with a value, in function returning 'void

Und ganz wichtig, der Puffer muss static sein:

static char buffer[20];

Da man keine Zeiger auf lokale Variablen zurückgeben kann

Oder du übergibst den Puffer als zusätzlichen Parameter wie auch bei sprintf().

Alternative: übergebe noch die Koordinaten als Parameter und mache die ganze Ausgabe in der Funktion

okay,

prettyPrint(prozent2, 3, 40, 50);

void prettyPrint(long value, int width, int posx, int posy, bool rightadjust, char fill)
{
  char buffer[20];
  byte index = 0;
  if (value < 0) width--;

  if (!rightadjust)
  { 
    ltoa(value, buffer, 10);
    index = strlen(buffer);
  }

  long val = (value < 0) ? value * -1 : value;
  unsigned long num = 10;
  for (int i = 0; i < width - 1; i++)
  {
    if (val < num) buffer[index++] = fill;
    num = num * 10;
  }

  if (rightadjust) 
    ltoa(value, &buffer[index], 10);
  else
    buffer[index] = '\0';

  myGLCD.print(buffer, posx, posy);
}

aber jetzt bekomme ich kein rückgabewert auf dem tft mehr was übersehe ich nun?

Mhh, komisch. Wenn es auf Serial geht, sollte es eigentlich auch auf dem LCD gehen. Ich nehme an du hast beide Funktions-Signaturen geändert, sonst würde dir der Linker auf die Finger klopfen.

Wobei ich sehe, dass du UTFT verwendest. Da müsste man das gar nicht per Hand implementieren :-*
Schau dir mal die Erläuterung zu printNumI() an:
http://www.rinkydinkelectronics.com/resource/UTFT/UTFT.pdf
Da gibt es zwei optionale Parameter für die Länge und das Füllzeichen

Also kannst du auch gleich das verwenden. Wobei da sowieo es aussieht nur rechtsbündig geht. Daran hatte ich gar nicht gedacht. Das oben hatte ich mal für 16x2/20x4 character LCDs geschrieben, wo man das nicht hat

Ansonsten, wenn du schon für die Uhrzeit sprintf() verwendest, kannst du das auch für einzelne Zahlen nehmen.

Nachtrag:
Bei mir geht es auch mit UTFT. Hatte erst setFont() und setColor() vergessen. Danach ging es :slight_smile:

jo hast recht hab das übersehen geht mit

myGLCD.printNumI(prozent2, 40, 50, 3);

Wunderbar =)

danke vielmals