1,77" TFT Programmierung kompliziert ?

Hallo Gemeinde. Ich bin dabei mit einen Punktezähler für Softair, bzw. Nerf zu bauen.
Die Punkte sollen über einen Tast-Kontakt gezählt werden. Soweit funktioniert auch alles. Aber ist die Darstellung auf einem TFT wirklich so kompliziert oder denke ich falsch ?

Im oberen drittel soll nach einem Treffer ein Fadenkreuz erscheinen, danach verschwinden und an gleicher Stelle die getroffene Punktzahl. Im unteren drittel soll die aufaddierte Gesamtpunktzahl erscheinen. Im meinem Beispiel soll der Taster 50 Punkte zählen. Jede weiter Punktzahl soll hinzu addiert werden. Aber : Er schreibt die neue Punktzahl immer über die alte, was natürlich nicht mehr lesbar ist.

Zur Zeit ist mein Lösungsansatz folgender :
Bevor die Rechnung und die darauffolgende Ausgabe auf dem TFT erscheint, lege ich erst mal ein
schwarzes Rechteck über das alte Ergebnis.

Gibt es da eventuell elegantere Lösungen ?

Der auskommentierte Teil ist im Moment vollkommen egal, da ich den Part vom ersten Taster kopiere und die Werte ändere.

`// Pins zuordnen
# define TFT_PIN_CS 10
# define TFT_PIN_DC 9
# define TFT_PIN_RST 8

//Targets festlegen
int Target10mm = A1; 
int Status10mm = 0;
int Target20mm = A2; 
int Status20mm = 0;

int Score = 0;


// Bibliotheken einbinden
# include "SPI.h"
# include "Adafruit_GFX.h"
# include "Adafruit_ST7735.h"

Adafruit_ST7735 tft = Adafruit_ST7735(TFT_PIN_CS, TFT_PIN_DC, TFT_PIN_RST);

void setup()
{
  Serial.begin(9600);
  delay(500);
  Serial.println("Bildschirm: " + String(tft.height()) + " x " + String(tft.width()));

  tft.initR(INITR_GREENTAB);

  pinMode(Target10mm, INPUT); 
  pinMode(Target20mm, INPUT);

  // Bildschirm um 180 Grad drehen
  tft.setRotation(2);

  // schwarzer Hintergrund
  tft.fillScreen(ST7735_BLACK);

  tft.setTextSize(3);
  tft.setCursor(22, 80);
  tft.setTextColor(ST7735_WHITE);
  tft.print("Score");

  tft.setTextSize(3);
  tft.setCursor(61, 120);
  tft.setTextColor(ST7735_WHITE);
  tft.print(Score);

}

void loop()
{
     // Abfrage Target 10mm - Taster an A1
     Status10mm = digitalRead(Target10mm);
     if (Status10mm == HIGH)
     {
       tft.drawCircle(64, 40, 25, ST7735_WHITE);
       tft.drawFastVLine(64, 10, 60, ST7735_WHITE);
       tft.drawFastHLine(34, 40, 60, ST7735_WHITE);
       delay(1000);
       tft.drawCircle(64, 40, 25, ST7735_BLACK);
       tft.drawFastVLine(64, 10, 60, ST7735_BLACK);
       tft.drawFastHLine(34, 40, 60, ST7735_BLACK);
       delay(1000);     
       tft.setTextSize(4);
       tft.setCursor(43, 28);
       tft.setTextColor(ST7735_WHITE);
       tft.print("50");
       delay(1000);
       tft.setTextSize(4);
       tft.setCursor(43, 28);
       tft.setTextColor(ST7735_BLACK);
       tft.print("50");
       delay(1000);

       tft.fillRect(0, 120, 128, 40, ST7735_BLACK);

       tft.setTextSize(3);
       tft.setCursor(40, 120);
       tft.setTextColor(ST7735_WHITE);
       Score = Score + 50;
       tft.print(Score);
    
       }

//     Status20mm = digitalRead(Target20mm);
//     if (Status20mm == HIGH)
//     {
//       tft.drawCircle(64, 40, 25, ST7735_WHITE);
//       tft.drawFastVLine(64, 10, 60, ST7735_WHITE);
//       tft.drawFastHLine(34, 40, 60, ST7735_WHITE);
//       delay(1000);
//       tft.drawCircle(64, 40, 25, ST7735_BLACK);
//       tft.drawFastVLine(64, 10, 60, ST7735_BLACK);
//       tft.drawFastHLine(34, 40, 60, ST7735_BLACK);
//       delay(1000);     
//       tft.setTextSize(4);
//       tft.setCursor(43, 28);
//       tft.setTextColor(ST7735_WHITE);
//       tft.print("40");
//       delay(1000);
//       tft.setTextSize(4);
//       tft.setCursor(43, 28);
//       tft.setTextColor(ST7735_BLACK);
//       tft.print("40");
//       delay(1000);
//     }
   
 }`

Die abgebildete Punktzahl in der Hintergrundfarbe schreiben (löschen) und erst danach die neue Punktzahl in der Schriftfarbe neu schreiben.

1 Like

Versuche mit,

tft.setTextColor(ST7735_WHITE, ST7735_BLACK);  //Vordergrund, Hintergrund

das ist normales vorgehen nicht nur bei Adafruit, nur ob mit der ST7735 das auch funktioniert, weis nicht, habe die nicht.

Da gibt es unheimliche Flackerei, gerade bei der Langsamer ADA, wenn dann mit switch, case

Da flackert gar nichts.

Ich habe "mal schnell" den Code angepasst. Allerdings mit einer anderen Library. Die Anweisungen sind identisch, werden aber mit -> statt mit "." geschrieben. Das sollte man ja leicht ummoddeln können. Das Prinzip wird hoffentlich aus dem Code ersichtlich.

Die X-Position passt sich dem Score-Wert an. Somit wird dieser immer zentriert dargestellt.

Funktioniert mit meinem pro Mini (8Mhz) wunderbar:

#include <Arduino.h>
#include <Streaming.h>
#include <Arduino_GFX_Library.h>
#include <Button_SL.hpp>
Print &cout {Serial};

//
// PIN Definitions
//
constexpr byte PIN_SEL_BUTTON {4};
//
//  1.77" SPI Display (ST7735)
// Display          -> Arduino
// Pin1  GND
// PIN2  VCC (3,3V)
// PIN3  SCK        -> 13
// PIN4  SDA (MOSI) -> 11
// PIN5  RES (RST)  ->  8
// PIN6  RS  (DC)   ->  9
// PIN7  CS         -> 10
// PIN8  LEDA (3,3V)
//
constexpr byte PIN_TFT_CS {10};
constexpr byte PIN_TFT_DC {9};   // RS
constexpr byte PIN_TFT_RST {8};

// TFT constants
// Display 160 x 128 Pixel (0.0 to 159.127)
constexpr byte TFT_WIDTH {128};
constexpr byte TFT_HEIGHT {160};
constexpr byte TXT_CHAR_WIDTH_S1 {6};
constexpr byte TXT_CHAR_HEIGHT_S1 {8};

constexpr unsigned int BG_COLOR {static_cast<unsigned int>(BLACK)};
constexpr unsigned int TXT_COLOR {static_cast<unsigned int>(WHITE)};

//
// Global variables/objects
//
Arduino_DataBus *bus = new Arduino_HWSPI(PIN_TFT_DC, PIN_TFT_CS);

// Arduino_GFX *gfx = new Arduino_ST7735(bus, RST_PIN, rotation, IPS, width, height, col offset, row offset,
//                                       col offset 2, row offset 2, BGR);
Arduino_GFX *tft = new Arduino_ST7735(bus, PIN_TFT_RST, 0, false, TFT_WIDTH, TFT_HEIGHT, 0, 0, 0, 0, false);

Btn::ButtonSL selBtn(PIN_SEL_BUTTON);

unsigned int score = 0;

uint8_t numDigits(unsigned int number) {
  uint8_t digits = (number == 0) ? 1 : 0;
  while (number) {
    number /= 10;
    ++digits;
  }
  return digits;
}

void drawCrossHairs(unsigned int xPos, unsigned int yPos, unsigned int radius, unsigned int color) {
  const unsigned int lineLength {(radius * 240) / 100};   // Lines have 20% overlap (radius * 2 * 120) / 100
  const unsigned int offset {lineLength / 2};
  tft->drawCircle(xPos, yPos, radius, color);
  tft->drawFastVLine(xPos, yPos - offset, lineLength, color);
  tft->drawFastHLine(xPos - offset, yPos, lineLength, color);
}

void drawScore(unsigned int score, byte yPos, byte textSize, unsigned int color) {
  tft->setTextSize(textSize);
  unsigned int xPos = (TFT_WIDTH - (TXT_CHAR_WIDTH_S1 * textSize * numDigits(score))) / 2;
  tft->setCursor(xPos, yPos);
  tft->setTextColor(color);
  tft->print(score);
}

void setup() {
  Serial.begin(19200);
  selBtn.begin();   // Assign the button to the bounce object
  selBtn.releaseOn();
  if (!tft->begin(4000000)) { cout << F("gfx->begin() failed!\n"); }
  tft->fillScreen(BG_COLOR);
  tft->setRotation(2);

  tft->setTextSize(3);
  tft->setCursor(22, 80);
  tft->setTextColor(WHITE);
  tft->print("score");

  drawScore(score, 120, 3, WHITE);
}

void loop() {
  static unsigned int oldScore {0};
  // Abfrage Target 10mm - Taster an A1
  // Status10mm = digitalRead(Target10mm);
  if (selBtn.tick() == Btn::ButtonState::shortPressed) {
    drawCrossHairs(64, 40, 25, TXT_COLOR);
    delay(1000);
    drawCrossHairs(64, 40, 25, BG_COLOR);
    delay(1000);
    drawScore(50, 28, 4, TXT_COLOR);
    delay(1000);
    drawScore(50, 28, 4, BG_COLOR);
    delay(1000);
    drawScore(oldScore, 120, 3, BG_COLOR);
    score = score + 50;
    drawScore(score, 120, 3, TXT_COLOR);
    oldScore = score;
  }
}

Edit: Konstanten etwas sortiert. Funktion zum Zeichnen des Fadenkreuzes etwas flexibler gestaltet.

Wen Du das schreibst ist das so !
Persönlich mag Adafruit GFX nicht ist mir zu langsam, vor allem wen man Kompleten Display neu zeichnet hier bin bei 12ms. loop durchlauf mit Tuch Auswertung und neu zeichnen, ist ein 480 x320 SPI TFT, mit ESP32.

Uuuiii..... das ist ja schon High-Tech :rofl:
Ich glaube da bin ich mit meinen Kenntnissen noch ziemlich weit von entfernt.
Das was ich aber schon erkannt habe, daß die Textfelder (Score) und das Fadenkreuz im Setup "gezeichnet" werden und bei einem Treffer unter dem jeweiligen Taster einfach nur aufgerufen werden. So muß es nicht unter jeder IF-Anweisung eines Tasters neu stehen.....

Danke für Deine Hilfe.

Du kannst Die Funktionen eigentlich 1zu1 übernehmen. Musst nur aus dem -> einen "." machen. Dann läuft das auch mit der Adafruit Bibiliothek, die du verwendest.

Vielen Dank Leute..... Habe wieder etwas dazu gelernt (z.B. das Fadenkreuz mit "void" zu deklarieren). Habe noch einige kleine Anpassungen vorgenommen (wie. z.B, die Trefferpunkte vorher zu bestimmen, damit diese bei Bedarf leichter angepasst werden können).
Einen zweites Target ist bereits auch eingefügt und das Skript macht was es soll.
Nur mit der Button-Abfrage

if (selBtn.tick() == Btn::ButtonState::shortPressed)

bin ich noch etwas überfordert und verstehe diese (noch) nicht, daher habe ich es erst mal bei meiner IF-Anweisung gelassen. Jetzt sieht es erst mal so aus :

// Bibliotheken einbinden
# include "SPI.h"
# include "Adafruit_GFX.h"
# include "Adafruit_ST7735.h"

// Pins zuordnen
# define TFT_PIN_CS 10
# define TFT_PIN_DC 9
# define TFT_PIN_RST 8

Adafruit_ST7735 tft = Adafruit_ST7735(TFT_PIN_CS, TFT_PIN_DC, TFT_PIN_RST);

//Targets festlegen
int Target10mm = A1; //10mm Target an PIN A1
int Status10mm = 0;
int Target20mm = A2; //20mm Target an PIN A2
int Status20mm = 0;
int Target30mm = A3; //30mm Target an PIN A3
int Status30mm = 0;
int Target40mm = A4; //40mm Target an PIN A4
int Status40mm = 0;
int Target50mm = A5; //50mm Target an PIN A5
int Status50mm = 0;

//Punkte festlegen
int T10 = 50;   //Punkte für 10mm Target
int T20 = 40;   //Punkte für 20mm Target
int T30 = 30;   //Punkte für 30mm Target
int T40 = 20;   //Punkte für 20mm Target
int T50 = 10;   //Punkte für 50mm Target

// TFT Einstellungen - Display 128 x 160 Pixel (0.0 to 159.127)
constexpr byte TFT_WIDTH {128};
constexpr byte TFT_HEIGHT {160};
constexpr byte TXT_CHAR_WIDTH_S1 {6};
constexpr byte TXT_CHAR_HEIGHT_S1 {8};
constexpr unsigned int BG_COLOR {static_cast<unsigned int>(ST7735_BLACK)};
constexpr unsigned int TXT_COLOR {static_cast<unsigned int>(ST7735_WHITE)};

// Startpunkte auf 0
unsigned int score = 0;
uint8_t numDigits(unsigned int number) {
uint8_t digits = (number == 0) ? 1 : 0;
while (number) {
number /= 10;
++digits;
}
return digits;
}

//Crosshair Zeichnen
void drawCrossHair(unsigned int xPos, unsigned int yPos, unsigned int radius, unsigned int color){
const unsigned int lineLength {(radius * 240) / 100};   // Lines have 20% overlap (radius * 2 * 120) / 100
const unsigned int offset {lineLength / 2};
tft.drawCircle(xPos, yPos, radius, color);
tft.drawFastVLine(xPos, yPos - offset, lineLength, color);
tft.drawFastHLine(xPos - offset, yPos, lineLength, color);
}

// Score Zeichen
void drawScore(unsigned int score, byte yPos, byte textSize, unsigned int color) {
tft.setTextSize(textSize);
unsigned int xPos = (TFT_WIDTH - (TXT_CHAR_WIDTH_S1 * textSize * numDigits(score))) / 2;
tft.setCursor(xPos, yPos);
tft.setTextColor(color);
tft.print(score);
}

void setup(){
  Serial.begin(19200);
  pinMode(Target10mm, INPUT); 
  pinMode(Target20mm, INPUT);
  pinMode(Target30mm, INPUT); 
  pinMode(Target40mm, INPUT); 
  pinMode(Target50mm, INPUT);

  tft.initR(INITR_GREENTAB);
  tft.fillScreen(BG_COLOR);
  tft.setRotation(2);
  tft.setTextSize(3);
  tft.setCursor(19, 80);
  tft.setTextColor(TXT_COLOR);
  tft.print("Score");

  drawScore(score, 120, 3, TXT_COLOR);
}

void loop() {
     static unsigned int oldScore {0};
     
     // Abfrage Target 10mm - Taster an A1
     Status10mm = digitalRead(Target10mm);
     if (Status10mm == HIGH){
     drawCrossHair(63, 40, 25, TXT_COLOR);
     delay(1000);
     drawCrossHair(63, 40, 25, BG_COLOR);
     delay(500);
     drawScore(T10, 28, 4, TXT_COLOR);
     delay(1000);
     drawScore(T10, 28, 4, BG_COLOR);
     delay(500);
     drawScore(oldScore, 120, 3, BG_COLOR);
     score = score + T10;
     drawScore(score, 120, 3, TXT_COLOR);
     oldScore = score;
     }

     // Abfrage Target 20mm - Taster an A2
     Status20mm = digitalRead(Target20mm);
     if (Status20mm == HIGH){
     drawCrossHair(63, 40, 25, TXT_COLOR);
     delay(1000);
     drawCrossHair(63, 40, 25, BG_COLOR);
     delay(500);
     drawScore(T20, 28, 4, TXT_COLOR);
     delay(1000);
     drawScore(T20, 28, 4, BG_COLOR);
     delay(500);
     drawScore(oldScore, 120, 3, BG_COLOR);
     score = score + T20;
     drawScore(score, 120, 3, TXT_COLOR);
     oldScore = score;
     }
 }

Ist jetzt ungetestet, kann also noch fehlerhaft sein, aber ich würde das eher so machen:

// Bibliotheken einbinden
#include "SPI.h"
// # include "Adafruit_GFX.h"
#include "Adafruit_ST7735.h"

// Pins zuordnen
#define TFT_PIN_CS  10
#define TFT_PIN_DC  9
#define TFT_PIN_RST 8

Adafruit_ST7735 tft = Adafruit_ST7735(TFT_PIN_CS, TFT_PIN_DC, TFT_PIN_RST);

// Pins für Targets festlegen -> 10mm Target (A1) bis 50mm Target (A5)
constexpr byte TARGET_PINS[] {A1, A2, A3, A4, A5};
constexpr byte NUM_TARGET_PINS {sizeof(TARGET_PINS) / sizeof(TARGET_PINS[0])};

// Punkte für 10mm Target bis 50mm Target
constexpr byte T_POINTS_VALUE[NUM_TARGET_PINS] {50, 40, 30, 20, 10};

// TFT Einstellungen - Display 128 x 160 Pixel (0.0 to 159.127)
constexpr byte TFT_WIDTH {128};
constexpr byte TFT_HEIGHT {160};
constexpr byte TXT_CHAR_WIDTH_S1 {6};
constexpr byte TXT_CHAR_HEIGHT_S1 {8};
constexpr unsigned int BG_COLOR {ST7735_BLACK};
constexpr unsigned int TXT_COLOR {ST7735_WHITE};

// Startpunkte auf 0
unsigned int score = 0;

// Abfrage der Pins - N enthält die Anzahl der Pins
template <size_t N> bool checkPins(const byte (&pins)[N], byte &index) {
  for (; index < N; ++index) {
    if (HIGH == digitalRead(pins[index])) { return true; }
  }
  return false;
}

uint8_t numDigits(unsigned int number) {
  uint8_t digits = (number == 0) ? 1 : 0;
  while (number) {
    number /= 10;
    ++digits;
  }
  return digits;
}

// Crosshair Zeichnen
void drawCrossHair(unsigned int xPos, unsigned int yPos, unsigned int radius, unsigned int color) {
  const unsigned int lineLength {(radius * 240) / 100};   // Lines have 20% overlap (radius * 2 * 120) / 100
  const unsigned int offset {lineLength / 2};
  tft.drawCircle(xPos, yPos, radius, color);
  tft.drawFastVLine(xPos, yPos - offset, lineLength, color);
  tft.drawFastHLine(xPos - offset, yPos, lineLength, color);
}

// Score Zeichen
void drawScore(unsigned int score, unsigned int yPos, byte textSize, unsigned int color) {
  tft.setTextSize(textSize);
  unsigned int xPos = (TFT_WIDTH - (TXT_CHAR_WIDTH_S1 * textSize * numDigits(score))) / 2;
  tft.setCursor(xPos, yPos);
  tft.setTextColor(color);
  tft.print(score);
}

void setup() {
  Serial.begin(19200);
  for (auto pin : TARGET_PINS) {
    pinMode(pin, INPUT);
  }

  tft.initR(INITR_GREENTAB);
  tft.fillScreen(BG_COLOR);
  tft.setRotation(2);
  tft.setTextSize(3);
  tft.setCursor(19, 80);
  tft.setTextColor(TXT_COLOR);
  tft.print("Score");

  drawScore(score, 120, 3, TXT_COLOR);
}

void loop() {
  static unsigned int oldScore {0};

  byte index {0};
  // Es wurde ein Treffer registriert. Je nach Index von 10mm (0) bis 50mm (4)
  if (true == checkPins(TARGET_PINS, index)) {
    drawCrossHair(63, 40, 25, TXT_COLOR);
    delay(1000);
    drawCrossHair(63, 40, 25, BG_COLOR);
    delay(500);
    drawScore(T_POINTS_VALUE[index], 28, 4, TXT_COLOR);
    delay(1000);
    drawScore(T_POINTS_VALUE[index], 28, 4, BG_COLOR);
    delay(500);
    drawScore(oldScore, 120, 3, BG_COLOR);
    score = score + T_POINTS_VALUE[index];
    drawScore(score, 120, 3, TXT_COLOR);
    oldScore = score;
  }
}

Das sollte jetzt für alle Targets fertig sein.

Hammer..... da hab ich echt noch viel zu lernen. Dankeschön !!

Ich habe jetzt mal testweise folgendes geändert......

// Pins für Targets festlegen -> 10mm Target (A1) bis 50mm Target (A5)
constexpr byte TARGET_PINS[] {A1, A2, A3, A4, A5, A6};
constexpr byte NUM_TARGET_PINS {sizeof(TARGET_PINS) / sizeof(TARGET_PINS[0])};

// Punkte für 10mm Target bis 50mm Target
constexpr byte T_POINTS_VALUE[NUM_TARGET_PINS] {50, 40, 30, 20, 10, 100};

Allerdings zählt er den 6. Taster nicht. Angedacht ist aber, das der 6. Taste die Punkte auf 0 setzen soll. damit ich den Nano nicht immer neu starten muss. Habe dran gedacht, wenn er diesen Taster mit 100 Zählen würde (funktioniert allerdings nicht), daß ich die "100" durch "-score" tausche. Nach dem Motto : Punkte = Punkte - Punkte (was ja dann logischerweise 0 ergibt).

Soweit ich weiß, kannst Du die Pins A6 und A7 nicht als digitale Pins verwenden.

Auszug aus der Arduino Referenz:

Die analogen Inputpins können als Digitalpins verwendet werden mit den Namen A0, A1, etc. Eine Ausnahme bilden die Pins A6 und A7 von Arduino Nano, Pro Mini und Mini, die nur als analoge Eingänge verwendet werden können.

Musst Du zwei andere verwenden. Der Programmlogik ist das egal, welche Pin-Nummern du in das Array schreibst.

Evtl. kannst Du die Zeile, welche den Score errechnet wie folgt abändern:

score = (T_POINTS_VALUE[index] < 100) ? score + T_POINTS_VALUE[index] : 0;

Bedeutet soviel wie, solange die zu vergebene Punktezahl < 100 ist, dann addiere diese, ansonsten setze den Score auf 0.

Jou.... das funktioniert. Hatte erst einen Pin deklariert, der so aussah (ging auch)

//  StatusReset = digitalRead(ResetPin);
//  if (StatusReset == HIGH){
//    drawScore(oldScore, 120, 3, BG_COLOR);
//    score = 0;
//    drawScore(score, 120, 3, TXT_COLOR);
//    oldScore = score;

Aber diese Methode sieht eleganter aus. Hab es ein wenig geändert und den Taster auf A0 mit 0 Punkte gesetzt und hab das draus gemacht :

    score = (T_POINTS_VALUE[index] > 5) ? score + T_POINTS_VALUE[index] : 0;

Vielen Dank !! Jetzt geht´s an´s konstruieren und ab auf den Drucker...... (damit habe ich zum Glück keine Probleme :rofl:

Wenn alles funktioniert, kannst Du ja Beitrag #10 als Lösung markieren…

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.