Adafruit 320x240 mit Teensy 4.0 "Flickering"

Hallo Zusammen

dies ist meine erster Beitrag.

Ich spiele seit Jahren mit den Teensys herum und mit Displays.
Aktuell habe ich ein Adafruit 320x240 Display mit dem Teensy 4.0 verbaut.

Mein Ziel ist es, 2 Werte anzuzeigen (PWM-Signal und eine Spannung).
Gleichzeitig soll das PWM-Signal als "Tacho" dargestellt werden.
Und die Spannung als "Fortschritsbalken".

Im Grunde funktioniert alles aber das Flickering ist da.

Welcher Herangehensweise ist die Richtige:
Canvas über den Fortschrittsbalken legen
Fillscreen ganz entfernen – das erzeugt ja das Flackern

FlickerFree geht für die reinen Zahlen aber nicht für die Balken oder die Nadel.

Leider werde ich aus dem Canvas nicht richtig schlau.

Auch dachte ich, dass die SPI Geschwindigkeit erhöht werden kann, bekomme dies nicht hin.

Danke Euch über Anregungen.

LG Fabian

Hast du dir die TFT_eSPI schon mal angesehen ?
Da gibt es auch div. Beispiele mit Zeigerinstrumenten.
Und die ist deutlich schneller im Vergleich zur Adafruit Lib.
Auch ein Flickern kenne ich damit nicht.

Hi, danke für die Nachricht. Nein habe ich nicht, komisch dass ich diese auch bereits noch nicht gefunden habe. Werde ich anschauen und mich wieder melden. Danke schon einmal.

Hi @1fabu-80 ,

was Du zusätzlich testen könntest:

  • Tacho-Nadel

    • Koordinaten des letzten Zeichnens merken
    • Nur bei Änderung(!)
      • alte Nadel in Hintergrundfarbe zeichnen
      • neue Nadel zeichnen
  • Balken

    • Länge des letzten Balkens merken
    • Nur bei Änderung(!)
      • Wert > alter Wert, dann Balken verlängern
      • Wert < alter Wert, dann Überstand mit Hintergrundfarbe löschen

Viel Erfolg!
ec2021

Hi @ec2021 Danke auch Dir.
Blöde Frage, beide Berechnungen habe ich je in eine void () reingepackt und im loop dann aufgerufen. Würdest Du die Änderungen auch hier reinpacken oder im loop?
Ich dachte für die Struktur so schlank wie möglich.
Ich würde Änderung in der jeweiligen void () abhandeln und dann den Parameter im loop schreiben - oder hänge ich hier in einer Sackgasse? Müsste ich so auch den Hinweis geben, dass der Wert gleich bleibt? Also Wert plus dessen Status übertragen?

Damit meinst du sicher die Funktion. Void ist ein Datentyp.

Und ja, du kannst zu den Berechnungen auch deine Änderungen mit in die jeweilige Funktion reinsetzen.

Vermutlich der richtige Ansatz. Das sollte den "Sprites" der TFT_eSPI entsprechen, dann ist das zutreffend.

Ich nutze eher ESP32 und TFT_eSPI, da fehlt mir leider die Erfahrung bezüglich Canvas. Mein Teensy 3.2 ist Klasse, aber die neuen sind leider recht teuer zum Basteln.

TFT_eSPI unterstützt Teensys nicht explizit:

For other (generic) processors only SPI interface displays are supported and the slower Arduino SPI library functions are used by the library. Higher clock speed processors such as used for the Teensy 3.x and 4.x boards will still provide a very good performance with the generic Arduino SPI functions.

Einen Versuch ist es aber wert :slightly_smiling_face:

1 Like

Hallo Zusammen
so mit dem Canvas geht generell aber, ich muss den Canvas immer "Quadratisch" halten. Bedeutet z.B. Höhe x Breite = 100 x 100. So geht es zu mindestens für den Text. Wenn ich den Canvas ändern möchte, z.B. Höhe x Breite = 50 x 150 (für breiten Text), dann zerreisst es den Text.
Gibt es einen Denkfehler? In sämtlichen Beispielen wird oft ein "nicht-quadratischer" Canvas verwendet.
LG Fabian

Ja. Nur ohne Code kann man den nicht erraten.

Fairer Punkt, werden den Code Morgen mal hochladen. Danke und einen schönen Abend Allen :slight_smile:

Hat etwas gedauert, aber ich habe ein Beispiel erstellt:

/*
  Forum: https://forum.arduino.cc/t/adafruit-320x240-mit-teensy-4-0-flickering/1350338
  Wokwi: https://wokwi.com/projects/421983019578677249

  ec2021

  Draw Bars/Pointers with minimum erasure effort

*/


#include "SPI.h"
#include "Adafruit_GFX.h"
#include "Adafruit_ILI9341.h"

#define TFT_DC 9
#define TFT_CS 10
Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC);
constexpr float pi = 3.1415926;
constexpr float Radius = 100.0;

unsigned long lastTime = 0;

void setup() {
  Serial.begin(115200);
  Serial.println("Graphics Example");
  tft.begin();
  clearScreen();
}


void loop(void) {
  Bar();
  if (millis() - lastTime > 100) {
    lastTime = millis();
    Pointer();
  }
}

void clearScreen() {
  tft.fillScreen(ILI9341_BLACK);
}

void Pointer() {
  static int Angle = 180;
  static int AngleDx = 10;
  int x = int(cos(Angle * pi / 180) * Radius);
  int y = int(sin(Angle * pi / 180) * Radius);
  drawPointer(x, y, ILI9341_YELLOW);
  Angle += AngleDx;
  if ((Angle < 0) || (Angle > 180)) {
    AngleDx = -AngleDx;
  }
}

// *****************************************
// Removes previous line and draws new line
// *****************************************
void drawPointer(int nX, int nY, uint16_t color) {
  constexpr int cX = 120;
  constexpr int cY = 160;
  static int oX = 1000;
  static int oY = 1000;
  if (oX < 1000) {
    tft.drawLine(cX, cY, cX + oX, cY + oY, ILI9341_BLACK);
  }
  tft.drawLine(cX, cY, cX + nX, cY + nY, color);
  oX = nX;
  oY = nY;
}

// *****************************************
// Draws bar with minimum flicker effect
// *****************************************
void drawBar(int value, int16_t color) {
  constexpr int startX = 100;
  constexpr int startY = 20;
  constexpr int width  = 20;
  static int oValue = 0;
  int y0, y1;
  int delta = value - oValue;
  if (delta == 0) {
    return;
  }
  if (delta > 0) {
    // Longer
    y0 = startY + oValue;
    y1 = value - oValue;
    tft.fillRect(startX, y0, width, y1, color);
  } else {
    // Shorter
    y0 = startY + value;
    y1 = oValue;
    tft.fillRect(startX, y0, width, y1, ILI9341_BLACK);
  }
  oValue = value;
}

void Bar() {
  static unsigned long lastT = 0;
  static int i = 1;
  static int d = 1;
  if (millis() - lastT > 100) {
    lastT = millis();
    drawBar(i * 10, ILI9341_RED);
    i += d;
    if (i > 10 || i < 2) {
      d = -d;
    }
  }
}

Zum Testen siehe hier

https://wokwi.com/projects/421983019578677249

Die wesentlichen Zeichenroutinen sind

void drawBar(int value, int16_t color)

und

void drawPointer(int nX, int nY, uint16_t color)

Sie zeigen die grundsätzliche Verfahren:

  • Alten Zeiger schwarz "überschreiben" und neuen zeichnen
  • Beim Balken nur das Delta zwischen vorheriger und neuer Länge zeichnen bzw. löschen

Die Routinen müssen ggf. an die verwendete Library angepasst werden. Die EIngabeparameter werden nicht darauf geprüft, ob sie innerhalb gültiger Grenzen sind; das ist u.U. noch nachzupflegen. Außerdem werden einige Konstanten in den o.a. Funktionen deklariert; auch das kann man in einer echten Anwendung global im Sketch umsetzen.

Die weiteren Funktionen des Sketches benutzen die Routinen für die Beispieldarstellungen.

Viel Erfolg!
ec2021

Hi @ec2021
vielen Dank für Deinen Beitrag. Werde ich so anschauen. Ich habe kommende Woche Zeit und dann hoffentlich auch mehr Motivation mich am Abend damit zu beschäftigen.
Vielleich für Euch, was ich machen will, ich baue seit 2012 selber Jetsurfboards. Elektrisch angetriebene Boards, Prinzip wie ein Jetski.
Mittlerweile die 5.te Generation. Immer für mich als "unendliche Geschichte".

Nun will ich eine eigene Fernbedienung (kabelgebunden) programmieren.
Bis dato hatte ich eine Funkfernbedienung verwendet, finde aber die Stabilität manchmal fraglich.

Ich möchte eigentlich nur die Spannung der Hauptbatterie darstellen (sehr langsam ändernd) und eben den PWM-Wert.
Dieser ist für mich wichtig um währen dem Setup gewisse Rampen und Kurven fahren zu können.
Eigentlich reichen die Werte mir aber ich finde ein Zeiger deutlich angenehmer als nur Werte :wink:
Sorry, dass ich das geschrieben habe, finde sollte man aber auch erwähnen was man überhaupt machen will.

LG Fabian

Ich finde es spannend, was die Leute so treiben und außerdem kann dadurch die Hilfe nochmal eine andere Richtung bekommen. Daher sollte der Zusammenhang schon beschrieben werden.

Was @ec2021 gemacht hat, finde ich gut.

Mit Canvas von Adafruit habe ich keine Erfahrung, aber bei TFT_eSPI kann man einen Zeiger in ein Sprite malen und dann um einen Punkt drehen. Die Hintergrundfarbe kann man als durchsichtig festlegen. Mehrere Sprites kann man ineinander kopieren und das Ergebnis auf das Display übertragen. Dadurch flackert die Anzeige nicht.

Eventuell geht sowas auch mit Canvas :wink:

Habe das Ganze mal in eine Klasse überführt:

Klasse (fehlerhaft, siehe unten unter [Edit])
#pragma once
#include "SPI.h"
#include "Adafruit_GFX.h"
#include "Adafruit_ILI9341.h"

#define TFT_DC 9
#define TFT_CS 10
Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC);
constexpr float pi = 3.1415926;

class PointerClass {
  private:
    int centerX = 0;
    int centerY = 0;
    int radius = 10;
    int oldX = 0;
    int oldY = 0;
    float oldAngle = 0;
    boolean doErase = false;
  public:
    void setXYR(int cX, int cY, int rad);
    void draw(float newAngle, uint16_t color);
};

class BarClass {
  private:
    int startX = 0;
    int startY = 0;
    int width  = 10;
    int oldLength = 0;
    byte direction = 0;
  public:
    void setXYWD(int x, int y, int w, byte dir);
    void draw(int length, uint16_t color);
};

void PointerClass::setXYR(int cX, int cY, int rad) {
  centerX = cX;
  centerY = cY;
  radius = rad;
}

void PointerClass::draw(float newAngle, uint16_t color) {
  if (doErase) {
    tft.drawLine(centerX, centerY, centerX + oldX, centerY + oldY, ILI9341_BLACK);
  }
  int newX = int(cos(newAngle * pi / 180) * radius);
  int newY = int(sin(newAngle * pi / 180) * radius);
  tft.drawLine(centerX, centerY, centerX + newX, centerY + newY, color);
  oldX = newX;
  oldY = newY;
  doErase = true;
}


void BarClass::setXYWD(int x, int y, int w, byte dir) {
  startX = x;
  startY = y;
  width  = w;
  direction = dir;
}

void BarClass::draw(int length, uint16_t color) {
  int delta = length - oldLength;
  if (delta == 0) {
    return;
  }
  if (delta > 0) {
    // Longer
    switch (direction) {
      case 0:
        tft.fillRect(startX, startY + oldLength, width, length - oldLength, color);
        break;
      case 1:
        tft.fillRect(startX + oldLength, startY, length - oldLength, width, color);
        break;
      case 2:
        tft.fillRect(startX, startY - oldLength, width, length - oldLength, color);
        break;
      case 3:
        tft.fillRect(startX - oldLength, startY, length - oldLength, width, color);
        break;
    }
  } else {
    // Shorter
    switch (direction) {
      case 0:
        tft.fillRect(startX, startY + length, width, oldLength, ILI9341_BLACK);
        break;
      case 1:
        tft.fillRect(startX + length, startY, oldLength,  width, ILI9341_BLACK);
        break;
      case 2:
        tft.fillRect(startX, startY - length, width, oldLength - length, ILI9341_BLACK);
        break;
      case 3:
        tft.fillRect(startX - length, startY, oldLength - length,  width, ILI9341_BLACK);
        break;
    }
  }
  oldLength = length;
}

Beispielanwendung

/*
  Forum: https://forum.arduino.cc/t/adafruit-320x240-mit-teensy-4-0-flickering/1350338
  Wokwi: https://wokwi.com/projects/422046098566960129

  ec2021

  Draw Bars/Pointers with minimum erasure effort

*/

#include "GraphicClass.h"

constexpr float Radius = 100.0;
unsigned long lastTime = 0;
int Angle = 180;
int AngleDx = 10;
int value = 1;
int delta = 1;

PointerClass pointerA, pointerB, pointerC, pointerD;
BarClass barA, barB, barC, barD;

void setup() {
  Serial.begin(115200);
  Serial.println("Graphics Example");
  tft.begin();
  pointerA.setXYR(120, 160, 80);
  pointerB.setXYR(120, 160, 60);
  pointerC.setXYR(120, 160, 50);
  pointerD.setXYR(120, 160, 40);
  barA.setXYWD(200,  20, 40, 0);
  barB.setXYWD( 40, 260, 30, 1);
  barC.setXYWD( 20, 120, 20, 2);
  barD.setXYWD(160, 300, 10, 3);
  clearScreen();
}


void loop(void) {
  if (millis() - lastTime > 100) {
    lastTime = millis();
    handlePointers();
    handleBars();
  }
}

void clearScreen() {
  tft.fillScreen(ILI9341_BLACK);
}

void handlePointers() {
  pointerA.draw(Angle, ILI9341_YELLOW);
  pointerB.draw(90 - Angle, ILI9341_GREEN);
  pointerC.draw(Angle + 45, ILI9341_YELLOW);
  pointerD.draw(180 - Angle, ILI9341_GREEN);
  Angle += AngleDx;
  if ((Angle < 0) || (Angle > 180)) {
    AngleDx = -AngleDx;
  }
}

void handleBars() {
  barA.draw(value * 10, ILI9341_MAGENTA);
  barB.draw(value * 10, ILI9341_RED);
  barC.draw(value * 10, ILI9341_BLUE);
  barD.draw(value * 10, ILI9341_GREEN);
  value += delta;
  if (value > 10 || value < 2) {
    delta = -delta;
  }
}

Position, Breite und Richtung der Balken werden so gesetzt

barA.setXYWD(200, 20, 40, 0);

Länge und Farbe des Balkens werden so beeinflusst:

barA.draw(value * 10, ILI9341_MAGENTA);

Mittelpunkt (Drehpunkt) und Länge des Zeigers

pointerA.setXYR(120, 160, 80);

Zeichnen mit Richtung (Winkel in Grad 0..360) und Farbe:

pointerA.draw(Angle, ILI9341_YELLOW);

Die Umsetzung ist nicht ganz "sauber" umgesetzt, aber wer Lust hat, kann gerne die Klasse in .h und .cpp Dateien aufteilen ... :wink:

Einschränkungen:

  • Basiert auf den Adafruit Libraries
  • Vor Wechsel der Farbe im "laufenden Betrieb" sollte man einmal den Balken mit der Länge 0 zeichnen, da ansonsten beim "Verlängern" ein zweifarbiger Balken dargestellt wird. Könnte man in der Klasse abfangen, indem man prüft, ob ein Farbwechsel stattgefunden hat.

Viel Spass damit!
ec2021

[Edit]: Ich habe leider noch einen Fehler in der ursprünglich geposteten Klasse gefunden, daher hier eine korrigierte Version:

Klasse (korrigiert)
#pragma once
#include "SPI.h"
#include "Adafruit_GFX.h"
#include "Adafruit_ILI9341.h"

#define TFT_DC 9
#define TFT_CS 10
Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC);
constexpr float pi = 3.1415926;

class PointerClass {
  private:
    int centerX = 0;
    int centerY = 0;
    int radius = 10;
    int oldX = 0;
    int oldY = 0;
    float oldAngle = 0;
    boolean doErase = false;
  public:
    void setXYR(int cX, int cY, int rad);
    void draw(float newAngle, uint16_t color);
};

class BarClass {
  private:
    int startX = 0;
    int startY = 0;
    int width  = 10;
    int oldLength = 0;
    byte direction = 0;
  public:
    void setXYWD(int x, int y, int w, byte dir);
    void draw(int length, uint16_t color);
};

void PointerClass::setXYR(int cX, int cY, int rad) {
  centerX = cX;
  centerY = cY;
  radius = rad;
}

void PointerClass::draw(float newAngle, uint16_t color) {
  if (doErase) {
    tft.drawLine(centerX, centerY, centerX + oldX, centerY + oldY, ILI9341_BLACK);
  }
  int newX = int(cos(newAngle * pi / 180) * radius);
  int newY = int(sin(newAngle * pi / 180) * radius);
  tft.drawLine(centerX, centerY, centerX + newX, centerY + newY, color);
  oldX = newX;
  oldY = newY;
  doErase = true;
}


void BarClass::setXYWD(int x, int y, int w, byte dir) {
  startX = x;
  startY = y;
  width  = w;
  direction = dir;
}

void BarClass::draw(int length, uint16_t color) {
  int delta = length - oldLength;
  if (delta == 0) {
    return;
  }
  if (delta > 0) {
    // Longer
    switch (direction) {
      case 0:
        tft.fillRect(startX, startY + oldLength, width, length - oldLength, color);
        break;
      case 1:
        tft.fillRect(startX + oldLength, startY, length - oldLength, width, color);
        break;
      case 2:
        tft.fillRect(startX, startY - oldLength, width, length - oldLength, color);
        break;
      case 3:
        tft.fillRect(startX - oldLength, startY, length - oldLength, width, color);
        break;
    }
  } else {
    // Shorter
    switch (direction) {
      case 0:
        tft.fillRect(startX, startY + length, width, oldLength - length, ILI9341_BLACK);
        break;
      case 1:
        tft.fillRect(startX + length, startY, oldLength - length,  width, ILI9341_BLACK);
        break;
      case 2:
        tft.fillRect(startX, startY - length, width, oldLength - length, ILI9341_BLACK);
        break;
      case 3:
        tft.fillRect(startX - length, startY, oldLength - length,  width, ILI9341_BLACK);
        break;
    }
  }
  oldLength = length;
}


/*
   (- length) was missing in BarClass::draw -> // Shorter -> case 0 and case 1

      case 0:
        tft.fillRect(startX, startY + length, width, oldLength, ILI9341_BLACK);
        break;
      case 1:
        tft.fillRect(startX + length, startY, oldLength,  width, ILI9341_BLACK);


*/

Die Fehlerbehebung ist im Code dokumentiert.

Du hast mehere Methoden, wie z.B.

mit der gleichen Signatur, die das Gleiche machen.
Das deutet darauf hin, dass es sinnvoll wäre, eine gemeinsame Oberklasse, z.B. DrawObject, zu bilden, von denen die spezialisierten Klassen erben. Die Unterschiede z.B. bei draw könnte man über virtuelle Methoden abbilden.
Damit könnten alle Objekte in einem Array vom Typ DrawObject gespeichert werden.

Gruß Tommy

Danke @Tommy56 ,

Du hast natürlich recht. Ich wollte allerdings erstmal nicht noch mehr Zeit in die Klasse investieren... Mir ging es im wesentlichen darum, das Prinzip des möglichst "flackerarmen" Löschens
zu demonstrieren.

Vielleicht findet sich auch jemand, der interessiert ist, eine von den Adafruit-Libraries unabhängige Umsetzung zu schreiben.

Danke und herzliche Grüße
ec2021

@ec2021: Das sollte auch nicht als Kritik verstanden werden, sondern als Anregung.
Ich habe keine solchen Displays, kann also nichts entwickeln, was sich testen lässt.
Eine Umsetzung unabhängig von der Grafik-Lib halte ich für mindest schwierig bis kaum realisierbar. Die müsste dann selbst alles vom drawPixel an machen und irgendwie die drawPixel-Methode der jeweiligen Grafik-Lib injiziert bekommen.
Nur mal so ins Unreine gedacht.

Gruß Tommy

1 Like

Keine Sorge, ich hatte Deinen Post auch genauso verstanden. Ich wollte mit meiner Antwort nur meine offensichtliche Nachlässigkeit entschuldigen ... :wink:

Habe mal die Klassen so umgeschrieben, dass PointerClass sowie BarClass per Template an den im Hauptsketch verwendeten Grafiktreiber angepasst werden.

Das funktioniert mit anderen Treibern allerdings auch nur dann, wenn diese "funktionskompatibel" bzgl. Bezeichnungen und Parameter sind.

Klasse und Beispielanwendung

Klasse:

#pragma once
//#include "Arduino.h"

template <typename T>
class PointerClass {
  private:
    const float pi {3.1415926};
    T* _driver;
    int _centerX = 0;
    int _centerY = 0;
    int _radius = 10;
    int _oldX = 0;
    int _oldY = 0;
    uint16_t _backColor = 0x000000;
    float _oldAngle = 0;
    boolean _doErase = false;
  public:
    PointerClass(T &driver) : _driver(&driver) {};
    void setXYR(int cX, int cY, int rad);
    void setBackColor(uint16_t col);
    void draw(float newAngle, uint16_t color);
};

template <typename T>void PointerClass<T>::setXYR(int cX, int cY, int rad) {
  _centerX = cX;
  _centerY = cY;
  _radius = rad;
}

template <typename T>void PointerClass<T>::setBackColor(uint16_t col) {
  _backColor = col;
}

template <typename T>void PointerClass<T>::draw(float newAngle, uint16_t color) {
  if (_doErase) {
    _driver->drawLine(_centerX, _centerY, _centerX + _oldX, _centerY + _oldY, _backColor);
  }
  int newX = int(cos(newAngle * pi / 180) * _radius);
  int newY = int(sin(newAngle * pi / 180) * _radius);
  _driver->drawLine(_centerX, _centerY, _centerX + newX, _centerY + newY, color);
  _oldX = newX;
  _oldY = newY;
  _doErase = true;
}


template <typename T>
class BarClass {
  private:
    T* _driver;
    int _startX = 0;
    int _startY = 0;
    int _width  = 10;
    int _oldLength = 0;
    byte _direction = 0;
    uint16_t _backColor = 0x000000;
  public:
    BarClass(T &driver) : _driver(&driver) {};
    void setXYWD(int x, int y, int w, byte dir);
    void setBackColor(uint16_t col);
    void draw(int length, uint16_t color);
};


template <typename T>void BarClass<T>::setXYWD(int x, int y, int w, byte dir) {
  _startX = x;
  _startY = y;
  _width  = w;
  _direction = dir;
}

template <typename T>void BarClass<T>::setBackColor(uint16_t col) {
  _backColor = col;
}

template <typename T>void BarClass<T>::draw(int length, uint16_t color) {
  int delta = length - _oldLength;
  if (delta == 0) {
    return;
  }
  if (delta > 0) {
    // Longer
    switch (_direction) {
      case 0:
        _driver->fillRect(_startX, _startY + _oldLength, _width, length - _oldLength, color);
        break;
      case 1:
        _driver->fillRect(_startX + _oldLength, _startY, length - _oldLength, _width, color);
        break;
      case 2:
        _driver->fillRect(_startX, _startY - _oldLength, _width, length - _oldLength, color);
        break;
      case 3:
        _driver->fillRect(_startX - _oldLength, _startY, length - _oldLength, _width, color);
        break;
    }
  } else {
    // Shorter
    switch (_direction) {
      case 0:
        _driver->fillRect(_startX, _startY + length, _width, _oldLength - length, _backColor);
        break;
      case 1:
        _driver->fillRect(_startX + length, _startY, _oldLength - length,  _width, _backColor);
        break;
      case 2:
        _driver->fillRect(_startX, _startY - length, _width, _oldLength - length, _backColor);
        break;
      case 3:
        _driver->fillRect(_startX - length, _startY, _oldLength - length,  _width, _backColor);
        break;
    }
  }
  _oldLength = length;
}

Beispiel:

/*
  Forum: https://forum.arduino.cc/t/adafruit-320x240-mit-teensy-4-0-flickering/1350338
  Wokwi: https://wokwi.com/projects/422059759297301505

  ec2021

  Draw Bars/Pointers with minimum erasure effort

  Classes with Template

*/
#include "SPI.h"
#include "Adafruit_GFX.h"
#include "Adafruit_ILI9341.h"
#include "TemplateGraphicClass.h"
#define TFT_DC 9
#define TFT_CS 10
Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC);

constexpr float Radius = 100.0;
unsigned long lastTime = 0;
int Angle = 180;
int AngleDx = 10;
int value = 1;
int delta = 1;

PointerClass<Adafruit_ILI9341> pointerA(tft), pointerB(tft), pointerC(tft), pointerD(tft);
BarClass<Adafruit_ILI9341> barA(tft), barB(tft), barC(tft), barD(tft);

void setup() {
  Serial.begin(115200);
  Serial.println("Graphics Example");
  tft.begin();
  pointerA.setXYR(120, 160, 80);
  pointerB.setXYR(120, 160, 60);
  pointerC.setXYR(120, 160, 50);
  pointerD.setXYR(120, 160, 40);
  pointerA.setBackColor(ILI9341_BLACK);
  barA.setXYWD(200,  20, 40, 0);
  barA.setBackColor(ILI9341_GREEN);
  barB.setXYWD( 40, 260, 30, 1);
  barC.setXYWD( 20, 120, 20, 2);
  barD.setXYWD(160, 300, 10, 3);
  clearScreen();
}


void loop(void) {
  if (millis() - lastTime > 100) {
    lastTime = millis();
    handlePointers();
    handleBars();
  }
}

void clearScreen() {
  tft.fillScreen(ILI9341_BLACK);
}

void handlePointers() {
  pointerA.draw(Angle, ILI9341_YELLOW);
  pointerB.draw(90 - Angle, ILI9341_GREEN);
  pointerC.draw(Angle + 45, ILI9341_YELLOW);
  pointerD.draw(180 - Angle, ILI9341_GREEN);
  Angle += AngleDx;
  if ((Angle < 0) || (Angle > 180)) {
    AngleDx = -AngleDx;
  }
}

void handleBars() {
  barA.draw(value * 10, ILI9341_MAGENTA);
  barB.draw(value * 10, ILI9341_RED);
  barC.draw(value * 10, ILI9341_BLUE);
  barD.draw(value * 10, ILI9341_GREEN);
  value += delta;
  if (value > 10 || value < 2) {
    delta = -delta;
  }
}

Außerdem gibt es eine Funktion, der einzelnen Instanz eine von Schwarz abweichende Hintergrundfarbe zu vergeben ...

Zum Ausprobieren: https://wokwi.com/projects/422059759297301505

1 Like

Sonst muss man einen Wrapper drum herum bauen, der die Bezeichnung und die Parameter anpasst :wink:

Gruß Tommy

1 Like