Das runde Display GC9A01 am ESP8266

Das neue Runde Display mit dem Chip GC9A01 bietet sich geradezu an eine Uhr zu bauen. Aber es gibt auch noch mehr Bedarf an runden Anzeigen die sich lohnen zu programmieren.

Erstmal eine Uhr die sich über das Internet stellt. Dadurch werden keine Tasten für die Zeiteinstellung benötigt.

Verkabelung ESP8266 mit dem Display GC9A01

Die Verbindung des Displays mit dem ESP8266 ist, wenn man die richtigen PINs gefunden hat, eigentlich sehr einfach.

PIN Tabelle ESP8266 und Display GC9A01

Im Arduinocode sind dann die verwendeten PINs zu definieren.

Die wichtigsten TFT Display Befehle lauten:

  • tft.drawLine (x startposition, y startposition, x endposition, y endposition, Farbe) zeichnet eine Linie
  • tft.fillCircle (x, y, radius, Farbe) zeichnet ein ausgefüllten Kreis
  • tft.setText(„Beispieltext“) schreibt den Text, aber man muss die Position vorher angeben
  • tft.setCursor(x, y) Setzte den Cursor hierhin und schreibe ab hier den Text
  • tft.setTextColor(Vordergrundfarbe, Hintergrundfarbe) setzt die Textfarbe
  • tft.drawPixel(x, y, Farbe) zeichnet ein Pixel
  • tft.fillScreen(Farbe) füllt das Display mit einer Farbe

Wenn man genau in der Mitte ein Pixel setzen will, so würde der Befehl
tft.drawPixel(120, 120, RED) lauten. Auch Text funktioniert so.

Display GC9A01 240×240 Pixel

Bei einem schrägen Strich kommen zu den beiden Startpunkten noch die Endpunkte hinzu.
tft.drawLine (60, 60, 120, 120 , GREEN). Dies wäre dann ein Strich vom roten Punkt bis zum Mittelpunkt.

Die folgende Software der Uhr ist von Floris Wouterlood.

// internet_clock_GC9A010_ESP8266
// platform: ESP8266 Wemos d1 mini
// display: GC9A010 driven circular display 240*240 pixels
//
// clock by Bodmer - Clock example in TFT_eSPI library
//
// adapted and modified
// Floris Wouterlood
// November 1, 2022
// public domain

Wichtiger Hinweis:
Dies ist nicht der komplette Code zum kopieren !!! Da fehlt noch was. Sucht auf Github.

Einbinden der Bibliotheken und Deklarierung der Werte. Die PIN’s sind festzulegen. Bei mir funktioniert diese PIN’s aber ich habe auch schon andere gesehen.

#include "SPI.h"
#include "Adafruit_GFX.h"
#include "Adafruit_GC9A01A.h"
#include <NTPClient.h>
#include <ESP8266WiFi.h>
#include <WiFiUdp.h>

const char* ssid = "Name WLAN";         
// network wifi credentials  - fill in your wifi network name
const char* password = "WLAN Schlüssel";  
// network wifi credentials  - fill in your wifi key

const long utcOffsetInSeconds = 7200;  
// 3600 = western europe winter time - 7200 = western europe summer time

#define TFT_DC D2 // PIN's z.B. AZDelevery ESP8266MOD 12F
#define TFT_CS D8
#define TFT_SCL D5
#define TFT_SDA 7
#define TFT_RES RES
#define DEG2RAD 0.0174532925

Im Setup startet man das Display, verbindet sich mit seinem WLAN und ruft mit „CreateDial()“ das zeichnen der Uhr mit Kreise, Striche und Linien auf. Das ist ja das interessante. Natürlich müssen auch noch die Stunden, Minuten und Sekunden hh:mm:ss geholt und in die Variablen gespeichert werden.

void setup(void) {
  tft.begin(); // Startet das Display
  tft.setRotation(2); // deht das Display
  tft.fillScreen(BLACK); // Füllt es mit Schwarz
  delay(200);
  tft.fillScreen(RED); // Füllt es mit Rot usw.
  delay(200);
  tft.fillScreen(GREEN);
  delay(200);
  tft.fillScreen(BLUE);
  delay(200);
  tft.fillScreen(BLACK);
  delay(200);
  tft.fillScreen(GREY); // ist nur Interessant

  createDial();  // Zeichnet die Uhr

  // WLAN Verbindung...
  Serial.begin(9600);
  Serial.println();
  Serial.println();
  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.print("connection with ");
  Serial.println(ssid);
  Serial.println("-------------------------------");

  timeClient.begin();
  timeClient.update();
  Serial.print("internet server time: ");
  Serial.println(timeClient.getFormattedTime());

  hh = timeClient.getHours();
  mm = timeClient.getMinutes();
  ss = timeClient.getSeconds();
  }

In der Loop() wird die Zeit berechnet und den X und Y-Werten für das Display zugewiesen, damit die Linien mit (tft.drawLine) gezeichnet werden können.

void loop() {
   if (targetTime < millis())
      {
      targetTime += 1000;
      ss++;                               // advance second
      if (ss==60)
         {
         ss=0;
         mm++;                            // advance minute
         if(mm>59)
            {
            mm=0;
            hh++;                         // advance hour
            if (hh>23) 
               {
               hh=0;
               timeClient.update ();      // update at midnight
               }
            }
         }
          
      // pre-compute hand degrees, x & y coords for a fast screen update
      sdeg = ss*6;                         // 0-59 -> 0-354
      mdeg = mm*6+sdeg*0.01666667;         // 0-59 -> 0-360 - includes seconds
      hdeg = hh*30+mdeg*0.0833333;         // 0-11 -> 0-360 - includes minutes and seconds
      hx = cos ((hdeg-90)*DEG2RAD);    
      hy = sin ((hdeg-90)*DEG2RAD);
      mx = cos ((mdeg-90)*DEG2RAD);    
      my = sin ((mdeg-90)*DEG2RAD);
      sx = cos ((sdeg-90)*DEG2RAD);    
      sy = sin ((sdeg-90)*DEG2RAD);

      if (ss==0 || initial) 
         {
         initial = 0;
         tft.drawLine (ohx, ohy, 120, 121, BLUE);  // erase hour and minute hand positions every minute
         ohx = hx*62+121;    
         ohy = hy*62+121;
         tft.drawLine (omx, omy, 120, 121, BLUE);  // alte Position Minuten Zeiger muss wieder die Hintergrundfarbe erhalten
         omx = mx*84+120;    
         omy = my*84+121;
         }
 
      tft.drawLine (osx, osy, 120, 121, BLUE);    // redraw new hand positions, hour and minute hands not erased here to avoid flicker
      osx = sx*90+121;    
      osy = sy*90+121;
      tft.drawLine (osx, osy, 120, 121, RED);
      tft.drawLine (ohx, ohy, 120, 121, WHITE);
      tft.drawLine (omx, omy, 120, 121, WHITE);
      tft.drawLine (osx, osy, 120, 121, RED);
      tft.fillCircle(120, 121, 3, RED);
      }
}

Der Hintergrund (bei mir ist er Blau) muss wieder gezeichnet werden, wenn der Zeiger (Linie) „weiter“ gegangen ist. Sonst bleiben dort der weiße Strich als rest übrig.
In der letzten Zeile wird der rote Punkt in der Mitte der Uhr gezeichnet.

In der „createDial()“ wird das Uhrenblatt gezeichnet. Als erstes wird der Äußere Ring in Bordeaux Rot und dann ein blauer Ring, der bis zur Mitte reicht, gezeichnet. Dann folgt das Zeichnen der Linien (Grün) alle 5 Minuten. Das erfolgt in einer Schleife es sind ja bekanntlich 12 Stück. Dann werden die 60 Punkte für die Minuten gezeichnet und innerhalb der Schleife auch die 4 weißen Punkte der Stunden (tft.fillCircle) bei 0, 90, 180 und 270 Grad gezeichnet.

void createDial() {

  tft.setTextColor(GC9A01A_WHITE);

  tft.setTextColor(WHITE, GREY);
  tft.fillCircle(120, 120, 118, BORDEAUX);  // Äußerer Ring in Bordeaux Rot
  tft.fillCircle(120, 120, 110, BLUE); // innerer Ring

  for (int i = 0; i < 360; i += 30)  // draw 12 line segments at the outer ring
  {
    sx = cos((i - 90) * DEG2RAD);
    sy = sin((i - 90) * DEG2RAD);
    x0 = sx * 114 + 120;
    yy0 = sy * 114 + 120;
    x1 = sx * 100 + 120;
    yy1 = sy * 100 + 120;
    tft.drawLine(x0, yy0, x1, yy1, GREEN); // grüne Linien
  }

  for (int i = 0; i < 360; i += 6)  // draw 60 dots - minute markers
  {
    sx = cos((i - 90) * DEG2RAD);
    sy = sin((i - 90) * DEG2RAD);
    x0 = sx * 102 + 120;
    yy0 = sy * 102 + 120;
    tft.drawPixel(x0, yy0, WHITE);  // weiße Punkt

    if (i == 0 || i == 180) tft.fillCircle(x0, yy0, 2, WHITE);  // draw main quadrant dots
    if (i == 90 || i == 270) tft.fillCircle(x0, yy0, 2, WHITE);
  }

  tft.fillCircle(120, 121, 3, WHITE);  // pivot
  targetTime = millis() + 1000;
}

Es gibt noch mehr Möglichkeiten diesen Code zu erweitern. Ich habe z.B. die Uhrzeit als Text eingebunden. Das ist sehr einfach da man ja die Werte hh.mm.ss bereits hat. Wenn nur eine Ziffer angezeigt wird, dann soll auch noch eine Null davor geschrieben werden. Dies kann man in einer if Schleife machen. Natürlich dreimal, denn es gibt ja auch 1 Uhr und 5 Minuten sowie 7 Sekunden.

if (hh < 10) tft.print(„0“);

void loop() {
  

  tft.setTextColor(WHITE, BLUE); // Text weiß auf blauen Hintergrund
  tft.setTextSize(3); // Textgröße
  tft.setCursor(50, 80); // Position x und y
  if (hh < 10) tft.print("0"); // wenn nur eine Ziffer dann eine Null davor
  tft.println(hh);  // Stunden

  tft.setCursor(85, 80); // Position Doppelpunkt
  tft.println(":");  // Doppelpunkt

  tft.setCursor(100, 80);
  if (mm < 10) tft.print("0");
  tft.println(mm);  // Minuten

  tft.setCursor(135, 80);
  tft.println(":");

  tft.setCursor(150, 80);
  if (ss < 10) tft.print("0");
  tft.println(ss);  // Sekunden

Der Platz unten möchte auch gefüllt werden….

Nachtrag: Leider geht dann die Uhr nicht mehr genau. Es ist ein Zeitproblem in der Schleife. Das Zeichen des Displayeintrags, in meinem Fall das DL1RLB, brauch auch etwas Rechenzeit und die fehlt dann im Takt bei der Berechnung. So ist die Uhr in einer Stunde einige Sekunden nachgegangen und das hat sich addiert. Also muss dieser Code aus der Loop() entfernt werden und im Setup eingefügt werden.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert