TFT am Arduino

Da hier viele sehr kompetente Leute unterwegs sind, stelle ich direkt mal meine nächsten Fragen :slight_smile:

Ich habe nebenher ein kleineres Projekt laufen. Ich möchte ganz gern einen Wecker bauen, mit TFT-Display und einer hellen LED, die so eine halbe Stunde oder so vor der eigentlichen Weckzeit ganz langsam heller wird. Evtl auch mal Temperatur-Sensoren oder so. Soweit so gut.

Diesbezüglich hab ich hab ich erstmal wieder ziemlich einfach angefangen, ich hab mir ein Adafruit 1,8" TFT geschnappt, ein RTC-Modul, und das ganze mit einem Arduino Nano zusammengesteckt.

Momentan ist das ganze nur mal zum Erfahrungen sammeln und Lernen da.

Ein vorläufiger Code, der einfach nur Zeit und Datum anzeigt sieht so aus:

// Includes
#include <Adafruit_GFX.h>
#include <Adafruit_ST7735.h>
#include <SPI.h>
#include <Wire.h>
#include "RTClib.h"

// Settings
String Clock_Version = "0.1";
unsigned long intervall_timecheck = 100;
int color_clock = ST7735_BLUE;
int color_date = ST7735_BLUE;
int color_text = ST7735_RED;
int color_background = ST7735_BLACK;
int color_secs = ST7735_RED;
int size_secs = 5;
int pos_secs_x = 155;
int pos_secs_y = 5;
int font_size_def_x = 5;
int font_size_def_y = 7;
int font_size_clock = 5;
int font_size_text = 1;
int font_size_date = 1;
int pos_text_x = 0;
int pos_text_y = 30;
int pos_clock_x = 0;
int pos_clock_y = 50;
int pos_date_x = 0;
int pos_date_y = 100;

// Pins
#define TFT_CS     6
#define TFT_RST    8
#define TFT_DC     7
Adafruit_ST7735 tft = Adafruit_ST7735(TFT_CS,  TFT_DC, TFT_RST);

// Systemvariablen
int alt_day = 0;
int alt_month = 0;
int alt_year = 0;
String alt_dow;
int alt_hour = 0;
int alt_min = 0;
int alt_sec = 0;
int new_day = 0;
int new_month = 0;
int new_year = 0;
String new_dow;
int new_hour = 0;
int new_min = 0;
int new_sec = 0;
int stat_secs = 0;
unsigned long last_timecheck = 0;
RTC_DS1307 RTC;


void setup(void)
  {
  Wire.begin();
  RTC.begin();

  if (! RTC.isrunning())
    {RTC.adjust(DateTime(__DATE__, __TIME__));}

  tft.initR(INITR_BLACKTAB);
  tft.fillScreen(color_background);
  tft.setRotation(1);
  tft.setTextWrap(false);

  tft.setCursor(pos_text_x, pos_text_y);
  tft.setTextColor(color_text);
  tft.setTextSize(font_size_text);
  tft.print("TFT-Clock V");
  tft.print(Clock_Version);

  int pos_dotdot_x = pos_clock_x + (font_size_clock * 2) + (font_size_clock * font_size_def_x * 2);
  tft.setCursor(pos_dotdot_x, pos_clock_y);
  tft.setTextColor(color_clock);
  tft.setTextSize(font_size_clock);
  tft.print(":");
  }

void loop(void)
  {
  if(millis() > last_timecheck + intervall_timecheck)
    {
    displayTime();
    last_timecheck = millis();
    }
  }

void displayTime()
  {
  DateTime datetime=RTC.now();
  new_day = datetime.day(),DEC;
  new_month = datetime.month(),DEC;
  new_year = datetime.year(),DEC;
  new_dow = get_day_of_week(datetime.dayOfWeek());
  new_hour = datetime.hour(),DEC;
  new_min = datetime.minute(),DEC;
  new_sec = datetime.second(),DEC;
  
  if(new_hour != alt_hour)
    {
    tft.setTextSize(font_size_clock);
    tft.setCursor(pos_clock_x, pos_clock_y);
    tft.setTextColor(color_background);
    if(alt_hour<10)tft.print(0);
    tft.print(alt_hour);
    tft.setCursor(pos_clock_x, pos_clock_y);
    tft.setTextColor(color_clock);
    if(new_hour<10)tft.print(0);
    tft.print(new_hour);
    alt_hour = new_hour;
    }

  if(new_min != alt_min)
    {
    int pos_min_x = pos_clock_x + (font_size_clock * font_size_def_x * 3) + (font_size_clock * 3);
    tft.setTextSize(font_size_clock);
    tft.setCursor(pos_min_x, pos_clock_y);
    tft.setTextColor(color_background);
    if(alt_min<10)tft.print(0);
    tft.print(alt_min);
    tft.setCursor(pos_min_x, pos_clock_y);
    tft.setTextColor(color_clock);
    if(new_min<10)tft.print(0);
    tft.print(new_min);
    alt_min = new_min;
    }
    
  if(new_sec != alt_sec)
    {
    if (stat_secs == 0)
      {
      tft.fillCircle(pos_secs_x, pos_secs_y, size_secs, color_secs);
      stat_secs = 1;
      }
    else
      {
      tft.fillCircle(pos_secs_x, pos_secs_y, size_secs, color_background);
      stat_secs = 0;
      }
    alt_sec = new_sec;
    }
    
  if(new_day != alt_day)
    {
    tft.setTextSize(1);
    tft.setCursor(pos_date_x, pos_date_y);
    tft.setTextColor(ST7735_BLACK);
    tft.print(alt_dow);
    tft.print(", ");
    if(alt_day<10)tft.print(0);
    tft.print(alt_day);
    tft.print(".");
    if(alt_month<10)tft.print(0);
    tft.print(alt_month);
    tft.print(".");
    tft.print(alt_year);
 
    tft.setTextSize(1);
    tft.setCursor(pos_date_x, pos_date_y);
    tft.setTextColor(ST7735_BLUE);
    tft.print(new_dow);
    tft.print(", ");
    if(new_day<10)tft.print(0);
    tft.print(new_day);
    tft.print(".");
    if(new_month<10)tft.print(0);
    tft.print(new_month);
    tft.print(".");
    tft.print(new_year);
    
    alt_day = new_day;
    alt_month = new_month;
    alt_year = new_year;
    alt_dow = new_dow;
    }
  }

String get_day_of_week(uint8_t dow)
  { 
  String dows="  ";
  switch(dow)
    {
    case 0: dows="So"; break;
    case 1: dows="Mo"; break;
    case 2: dows="Di"; break;
    case 3: dows="Mi"; break;
    case 4: dows="Do"; break;
    case 5: dows="Fr"; break;
    case 6: dows="Sa"; break;
    }
  return dows;
  }

Jaja ich weiß, diese Mischung aus deutschen und englischen Namen für die Variablen, grausam :wink:

Aber die Sache funktioniert sehr schön und zuverlässig.

Jetzt hab ich aber 2 Punkte die mir Sorgen machen:

  1. Selbst über Hardware-SPI ist das Display sehr langsam. Ich hab jetzt so programmiert, dass immer nur die Teile, die sich tatsächlich ändern, erst mit der Hintergrundfarbe überschrieben werden und dann neu geschrieben werden. Aber selbst da flackert es noch ganz schön auch wenn sich nur die Minute ändert. Die zweite Möglichkeit wäre noch, den Teil direkt zu überschreiben und die Hintergrundfarbe mit anzugeben, aber ob das schneller geht wage ich mal zu bezweifeln.
    Wenn ich dann mal Menüs einbaue usw könnte das durchaus zu einer hässlichen Angelegenheit werden. Ich stelle mir das so vor dass ich auf "Menü" drücke um den Wecker einzustellen und dann jedesmal 2sec. dem Display zuschaue wie es die neue Seite aufbaut. Das möchte ich eigentlich nicht.
    Gibt es da eine Option? Wäre vielleicht ein Leonardo bzw Micro schneller? Oder vielleicht gleich ein Due, wobei der ja wirklich hoffnungslos überdimensioniert wäre :stuck_out_tongue:

  2. Meines Wissens geht die Hintergrundbeleuchtung nicht per Software zum Abschalten, oder gibts da inzwischen eine Möglichkeit? Die Beleuchtung hat auch keinen extra herausgeführten Pin auf der Platine.
    Ich möchte die Beleuchtung aber unbedingt abschalten können, da das Display Nachts definitiv zu hell ist... Die letzte Möglichkeit wäre vermutlich eine Leiterbahn auf der Platine aufzutrennen, aber das will ich eigentlich nicht unbedingt.

Sollte ich die Idee mit dem TFT vielleicht wieder verwerfen und einfach auf ein LCD umsteigen? Oder gibts irgendwie schnellere Alternativen?

Ich finde halt LCDs nicht wirklich schön...

Hallo Zeitsklave,

wie bereits von dir selber sind deutsche und englische Variabel/Funktionsnamen unschön und wenn möglich zu vermeiden. Bei Kommentaren hingegen geht die Meinung dahin, wenn mans nicht richtig in Englisch hinbekommt, dann einheitlich in der Muttersprache bleiben.

Das mit den Displays ist bekannt. Du hast ja zumindest soweit den Schritt schon geschafft, dass du nur die neuen Sachen überschreibst. Auch am Due sind die Displays nicht die Raketen. Zu den anderen Controllern, die arbeiten nur mit 16MHz wie der Uno auch. Der Zero ist ebenfalls nicht angebracht, ist halt noch etwas langsamer als der Due, wäre aber im Vergleich nicht überdimensioniert.

Ich habe immer bei der Schrift die Hintergrundfarbe Schwarz aktiv gehabt. Sollte schneller gehen. Da ansonsten erst alles schwarz gemacht wird, und dann erst die Schrift + schwarz überschrieben wird.

Welches Modul hast du genau im Einsatz. Ich habe mehrere Varianten hier, mit und ohne SD Karte sowie mit unterschiedlichen großen Rahmen. Die kleinsten (Itead) haben keine Möglichkeit, die Helligkeit zu regeln oder abzustellen. Bei der Variante mit der SD Karte habe ich den Pin "BL". Das sollte die Hintergrundbeleuchtung sein. Da sollte es sich um die Anode der Beleuchtung handeln. Einen kleinen PNP Transistor einsetzen und du kannst sie über den Arduino abschalten. PWM sollte ggf auch gehen, musst du mal testen.

Welche LCDs meinst du? Die GLCD sind ebenfalls nicht so schnell am Arduino. Die 16x02 oder 20x04 hingegen sind besser. Schau mal bei Google für die 16x02. Da gibt es eine Möglichkeit, die Uhrzeit größer darzustellen. Über 2 x 2 Zeichenfelder soweit ich es in Erinnerung habe.

Ich habe das bei mir mal anders gelöst, auch wenn das Projekt bis jetzt aufgrund Zeitmangels noch nicht verbaut ist. Ich habe mir eine Matrix gebaut mit den MAX7219. Über das Display (40x8) kann ich auch alle Einstellungen vornehmen, in dem ich das Menü drüber laufen lasse.

OLEDs sind auch schneller. Aber meistens etwas kleiner.

TFTs halte ich eher für sinnvoll als Eingabe Geräte wenn man eins mit Touch Screen verwendet.

Vielen Dank erstmal für den Input :slight_smile:

Naja, mit den Namen... grad bei so schnellen Testprogrammen nimmt man halt gern Code per drag&drop aus beispielen, und dann vermischen sich so bezeichnungen ganz schnell :wink:
Aber wenn das Programm wächst dann passe ich eigentlich auch da noch sehr viel an, und gerade Kommentare will ich dann schon komplett in deutsch haben, auch wenn ich des englischen mächtig bin.
Bei Variablennamen nehm ichs dann allerdings nicht so genau :grinning:
Aber das ist halt auch irgendwo eine Sache des persönlichen Geschmacks, und idR reichts ja wenn ich selber den Überblick habe.

OK, also ein anderer Arduino wäre dann wohl relativ zwecklos, lieber an der Display-Technik feilen.
Die Hintergrundfarbe werd ich dann mal probeweise umsetzen. Das spart auf jeden Fall einiges an Code, und zumindest das Flackern beim neu schreiben sollte dann deutlich besser werden.

Mein Modul ist kaum größer als das Display selbst, hat keine Tasten aber einen microSD-Schacht auf der Rückseite. Bei näherer Betrachtung ist es nicht Adafruit sondern Sainsmart, läuft aber mit der Adafruit Libary und ich denke dass es ziemlich Baugleich ist. es steht auch ST7735 drauf.
Einen BL-Pin hats nicht.
Im Anhang mal Fotos.

Hm, wenn GLCDs auch nicht schneller sind dann ist das auch keine Option. Text-LCDs gefallen mir für so einen Einsatz aber nicht wirklich...

So ein Mini-OELD hab ich auch in de Kiste liegen, habs aber bisher noch nicht getestet. Ich schätze nur das ist mir dann zu klein :wink: Ich find ja das 1,8" schon mickrig :wink:

Mit Touchscreen wäre natürlich der Hammer, aber in dem Fall wohl eher überflüssig. Besonders wenn der Arduino die Geschwindigkeit nicht gebacken bekommt ist sowas ziemlich blöd zu bedienen. Ich hasse das bei meinem Autoradio, wenn ich bei jedem Druck auf den Bildschirm erstmal warten muss. Und das Ding läuft mit Windows, aber dann ists ja eh kein Wunder :smiley:

Ich denk mal die Möglichkeit von sschultewolter wird hier wohl wirklich das beste sein, die Uhrzeit auf einer LED-Matrix anzeigen und das Menü auf ein LCD auslagern.
Bzw zum Anzeigen der Uhrzeit alleine könnt ich ja sogar mit dm langsamen TFT leben, und alles was dann irgendwie interaktiv ist dann mit einem LCD lösen, das wirklich nur an ist wenn man es tatsächlich braucht.

Ich danke euch auf jeden Fall mal für die ganze Info, und werd mir mal weiter meine Gedanken machen! :slight_smile: Vielleicht fällt uns ja auch noch was ein.

Besonders wenn der Arduino die Geschwindigkeit nicht gebacken bekommt ist sowas ziemlich blöd zu bedienen. Ich hasse das bei meinem Autoradio, wenn ich bei jedem Druck auf den Bildschirm erstmal warten muss. Und das Ding läuft mit Windows, aber dann ists ja eh kein Wunder

So langsam sind die auch wieder nicht.

Ein komplett neues Menü zu zeichnen dauert ein klein wenig. Aber +/- Knöpfe zu haben und damit einen Wert zu verändern und ähnliche Dinge geht flüssig und ohne Zeitverlust.

Dein Problem ist die große Schriftart und dass du damit viel auf einmal neu zeichnen musst. Mit kleineren Schriftarten wird das erträglich.

Ich hab in meiner Schreibtischuhr genau so ein TFT verbaut und-Uhrzeit, Datum usw. bekommt man schon "flackerfrei" hin.
Sooo lahm sind die Teile nun auch wieder nicht...allerdings kann man flüssig animierte Menüs vergessen. Selbst das bekannte Pingpong-Spiel hab ich nicht wirklich flüssig hingekriegt, aber das hatte ich damals auch nur halbherzig versucht. Wie schon gesagt wurde: niemals Zeichen mit Farbe überpinseln, das dauert. Immer einfach den Hintergrund definieren und so schreiben, das geht weit schneller.
Ausserdem ist nicht immer das Display selber das Problem, ich hatte schon Ruckler, weil das Arduinochen nebenbei zu viel anderes zu tun hatte. so dass einfach nicht ehr oft genug aktualisiert werden konnte- da ruckelt dann der Sekundenzeiger schon mal... ::slight_smile:

OK, ich hab jetzt nochmal ein bisschen rumgebastelt.
Meine Uhr hat jetzt erstmal eine Platine bekommen und einen Temperatursensor :slight_smile:

Außerdem hab ich das mit der Hintergrundfarbe eingebaut, und zumindest das Anzeigen der Uhrzeit geht vollkommen flackerfrei.

Das ist schonmal sehr gut, der nächste Schritt wird sein, ein paar Tasten anzubringen und ein Menü aufzusetzen. Da muss ich mir allerdings noch gründlich überlegen wie das aussehen soll, auch wie die Uhrzeit momentan angezeigt wird ist noch nicht der Weisheit letzter Schluss, das war ja nur schnell hingeklatscht um zu sehen wie es funktioniert :wink:

Ein animiertes Menü brauch ich eh nicht, und dann muss ich halt sehen wie ich ein einfaches halbwegs flott hinkrieg.

Ein wichtiger Punkt ist aber noch, eine Möglichkeit zu finden um die Hintergrundbeleuchtung abschalten zu können.
Da werd ich mal auf der Platine rumlöten, auch wenn mir das ein schlechtes Gewissen macht :wink:

Das Adafruit Display kann man direkt schalten:

Du hast das hier:

Da sehe ich leider keinen Schaltplan dazu

Also ich würde nie mit Tastern anfangen. So habe ich auch begonnen.
Nimm ein TFT, da sparst du dir viel Programmier- und vor allem Hardware Arbeit.

@Serenifly: richtig, und das SainSmart lässt sich nicht schalten, da kann man bloß das komplette Display in eine art ruhemodus versetzen.

Aber ich hab jetzt die Leiterbahn aufgetrennt, die für mich am meisten nach Hintergrundbeleuchtung aussah, und siehe da, es war auf anhieb richtig.
Schnell einen Transistor angelötet, eine Strippe zum Arduino gelegt, und voila: schon kann ich die Beleuchtung per PWM dimmen :grinning:

@maverick1509: du meinst einen touchscreen? Das scheint mir für meinen Zweck doch ein bisschen übertrieben :wink: außerdem bin ich mit dem kleinen Display grad so schön in fahrt, ich will jetzt kein anderes einbauen ^^

Ich muss mich nochmal zu Wort melden :smiley:
Inzwischen ist meine Uhr ein ganzes Stück weiter.

Die Hintergrundbeleuchtung wird jetzt automatisch angepasst, abhängig von der Umgebungshelligkeit.
Zur Steuerung hab ich 6 Tasten die über einen analogen Eingang abgefragt werden. Die Sache funktioniert so exakt dass ich auch Tastenkombinationen erfassen könnte, da war ich positiv überrascht. Naja brauch ich allerdings nicht ^^
Taster waren die Voraussetzung dafür, ein Menü aufzubauen.
Ich habe jetzt also ein einfaches Menü, und kann auch schon die Zeit der RTC per Taster einstellen.
Und die Temperatur wird auch angezeigt :wink:

Das Menü ist absolut minimalistisch, es wird nur ein einiger Menüpunkt in kleinster Schriftgröße angezeigt, dafür ist es absolut flackerfrei, genauso wie das einstellen der Uhr.
Ich werds allerdings noch ein bisschen erweitern... :slight_smile:

Den Rest krieg ich auch noch hin, zur Version 1.0 fehlen mir noch Einstellen der Weckzeit, eine helle LED am PWM ausgang und natürlich Tonausgabe (falls ich vom Licht nicht wach werde), aber das werd ich dann wohl noch über ein exra Modul lösen.
Aber nix was jetzt noch wirklich problematisch wäre.

Ich freue mich voll wie gut das alles funktioniert und danke euch allen nochmal für die wertvollen Tipps! Daumen hoch für dieses Forum! :slight_smile:

Hallo Zeitsklave,

stehe leider auch vor dem Problem das ich das Display nicht dimmen kann.

Könntest du vielleicht beschreiben welche Leiterbahn du durchtrennt hast?

Wenn es nicht zu viele Umstände macht, könntest du vielleicht auch ein Foto davon einstellen?

Bedanke mich jetzt schon mal für deine mühen.

Gruß Hans

Steve_-_O:
Hallo Zeitsklave,

stehe leider auch vor dem Problem das ich das Display nicht dimmen kann.

Könntest du vielleicht beschreiben welche Leiterbahn du durchtrennt hast?

Wenn es nicht zu viele Umstände macht, könntest du vielleicht auch ein Foto davon einstellen?

Bedanke mich jetzt schon mal für deine mühen.

Gruß Hans

Gern :slight_smile:
Ich hab dir auf dem Bild die Leiterbahn markiert, die hab ich einfach durchtrennt, dann an den Pin von dem 220 ohm Widerstand und an den Lötpunkt am anderen Ende der Leiterbahn einen BC368 angelötet und die Basis über einen Widerstand an einen PWM-ausgang vom Arduino - fertig!

Das ging aber schnell :o

Habe es jetzt auf die schnelle mit einem Widerstand, anstatt einem Transistor probiert.
Funktioniert perfekt.

Da steht meinem nächsten Projekt nichts mehr im Wege.

Ich sag danke. :slight_smile:

Gruß Hans