Can't write on 2.8 TFT TouchScreen

Hi y'all

I'm writing a code for a laser tag game. I'm using a Arduino Mega 2560 and a Adafruit 2.8 TFT Touch Screen Display.
My Problem is that I'm unable to print to the display in the loop (function "displayScores" at the bottom). In setup I can. Why is that?
Below my code:

#include "DFRobotDFPlayerMini.h"
#include "SoftwareSerial.h"
#include <AltSoftSerial.h>

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

// For the Adafruit shield, these are the default.
#define TFT_DC 9
#define TFT_CS 10

// Use hardware SPI (on Uno, #13, #12, #11) and the above for CS/DC
Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC);
// If using the breakout, change pins as desired
//Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC, TFT_MOSI, TFT_CLK, TFT_RST, TFT_MISO);


//AltSoftSerial altSerial;  // Receive = 8, Transmit = 9
SoftwareSerial HC12(50, 51);


int initial_score = 0;
const int num_players = 4;
const int num_scores = 2;
int score_players[num_players][num_scores] = {  // define an array for storing scores
  { initial_score, initial_score },
  { initial_score, initial_score },
  { initial_score, initial_score },
  { initial_score, initial_score }
};

byte incomingByte;
const unsigned int READ_BUFFER_SIZE = 11;  //Platz für 10 Zeichen + Terminator




void setup() {
  // Serial coms set up to help with debugging.
  //altSerial.begin(9600);
  Serial.begin(9600);
  HC12.begin(9600);
  tft.begin();
  Serial.println("Startup...");

  tft.setRotation(-1);
  tft.fillScreen(ILI9341_BLACK);
  tft.setCursor(0, 0);
  tft.setTextColor(ILI9341_GREEN);
  tft.setTextSize(2);
  tft.println("PLAYER1");
  tft.setTextColor(ILI9341_RED);
  tft.println("TargetHits:");
  tft.setCursor(200, 16);
  tft.println("Hits:");

  tft.setCursor(0, 60);
  tft.setTextColor(ILI9341_GREEN);
  tft.println("PLAYER2");
  tft.setTextColor(ILI9341_RED);
  tft.println("TargetHits:");
  tft.setCursor(200, 76);
  tft.println("Hits:");

  tft.setCursor(0, 120);
  tft.setTextColor(ILI9341_GREEN);
  tft.println("PLAYER3");
  tft.setTextColor(ILI9341_RED);
  tft.println("TargetHits:");
  tft.setCursor(200, 136);
  tft.println("Hits:");

  tft.setCursor(0, 180);
  tft.setTextColor(ILI9341_GREEN);
  tft.println("PLAYER4");
  tft.setTextColor(ILI9341_RED);
  tft.println("TargetHits:");
  tft.setCursor(200, 196);
  tft.println("Hits:");
}





// Main loop most of the code is in the sub routines
void loop() {



  char* str = readLine(HC12);
  if (str != nullptr) {
    Serial.print("Eingelesen: ");
    Serial.println(str);
    compare(str);
    displayScores();
  }
}


// SUB ROUTINES



char* readLine(Stream& stream) {
  static byte index;
  static char buffer[READ_BUFFER_SIZE];

  while (stream.available()) {
    char c = stream.read();
    //Serial.println("Stream:");
    //Serial.println(c);

    if (c == '\n')  //wenn LF eingelesen
    {
      buffer[index] = '\0';  //String terminieren
      index = 0;
      return buffer;  //melden dass String fertig eingelesen wurde

    } else if (c >= 32 && index < READ_BUFFER_SIZE - 1)  //solange noch Platz im Puffer ist
    {
      buffer[index++] = c;  //Zeichen abspeichern und Index inkrementieren
    }
  }
  return nullptr;
}

void compare(char* str) {
 
  
  //Serial.println("compare running!");
  if (strstr(str, "Shooter")) {
    //Serial.println("Shooter received!");
    char* ptr = strchr(str, ':');
    int PlayerID = atoi(ptr + 1);
    score_players[PlayerID - 1][0]++;
  }

    if (strstr(str, "Killed")) {
      Serial.println("Killed received!");
      char* ptr2 = strchr(str, ':');
      int PlayerID2 = atoi(ptr2 + 1);
      Serial.println("Killed Player");
      Serial.println(PlayerID2);
      score_players[PlayerID2 - 1][1]++;
    }
  }


void displayScores() {

  tft.setTextSize(2);
  tft.fillScreen(ILI9341_BLACK);
  tft.setTextColor(ILI9341_RED);
  tft.setCursor(150, 16);
  tft.print(score_players[0][0]);
  tft.print(" ");

}

I'm going to guess its working as intended but because you are constantly filling the screen with black, its not able to show the text long enough.

Does "Eingelesen: " ever show in the Serial monitor?
Try printing the score to the Serial monitor too from displayScores()

If nothing shows for the scores then that would mean there is a problem with your compare function and its just not updating the scores.

Yes, I think you're right. I do get all the Serial Prints. And strangely, after a while the display goes completely dark except for the number from the array I'm trying to print.

I now removed the tft.fillScreen(ILI9341_BLACK); in setup and in the while. Now I can print the ints, but the old values stay displayed. Is there an easy way to clear the old values?
Thanks guys!

According to the lines below:

your display is connected to hardware SPI pins, which will be 50 (MISO), 51 (MOSI), 52 (SCK), 53 (SS) on Arduino Mefa.
However, you use the same pins to connect HC-12 modules:

Because the hardware SPI pins are unchangeable, you need to move your HC-12 connection to some other pins.

You would need to check if the score has changed and if so, clear that space and write the new value.
You will need another variable to keep track of the old value. Then you need to check if the new value equals the old value. If they are different, update the screen and update the old value.

Hi guys
I managed to make the code work in the meantime. Although one thing is not as smooth as it is supposed to be yet. And that concerns the rotary encoder. The pulses get detected only if I rorate the encoder very slowly. It seems to be some kind of a delay problem that the pulses get "lost". Does anyone have an idea on how to solve this?
Below the entire actual code:

#include <Keyboard.h>


#include "DFRobotDFPlayerMini.h"
#include <AltSoftSerial.h>
#include <Arduino.h>
#include "SPI.h"
#include "Adafruit_GFX.h"
#include "Adafruit_ILI9341.h"
#include <Fonts/FreeSansBold9pt7b.h>
#include <RotaryEncoder.h>

// For the Adafruit shield, these are the default.
#define TFT_DC 9
#define TFT_CS 10

#define PIN_IN1 23
#define PIN_IN2 22

//RotaryEncoder encoder(PIN_IN1, PIN_IN2, RotaryEncoder::LatchMode::FOUR3);
RotaryEncoder encoder(PIN_IN1, PIN_IN2, RotaryEncoder::LatchMode::TWO03);

// Use hardware SPI (on Uno, #13, #12, #11) and the above for CS/DC
Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC);
// If using the breakout, change pins as desired
//Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC, TFT_MOSI, TFT_CLK, TFT_RST, TFT_MISO);




int initial_score = 0;
const int num_players = 4;
const int num_scores = 2;
int score_players[num_players][num_scores] = {  // define an array for storing scores
  { initial_score, initial_score },
  { initial_score, initial_score },
  { initial_score, initial_score },
  { initial_score, initial_score }
};

byte incomingByte;
const unsigned int READ_BUFFER_SIZE = 11;  //Platz für 10 Zeichen + Terminator

int BattVolts = A15;
float BattVoltage;
int BuzzerPin = 30;
unsigned long newPos;

int Button = 31;
bool Countdown = false;

unsigned long startTime;



void setup() {
  // Serial coms set up to help with debugging.
  //altSerial.begin(9600);
  Serial.begin(9600);
  Serial1.begin(9600);
  tft.begin();
  Serial.println("Startup...");

  pinMode(BattVolts, INPUT);
  pinMode(BuzzerPin, OUTPUT);
  pinMode(Button, INPUT);

  tft.setRotation(-1);
  delay(1000);
  //tft.setFont(&FreeSansBold9pt7b);
  tft.setTextWrap(false);
  tft.fillScreen(ILI9341_WHITE);
  tft.setCursor(5, 10);
  tft.setTextColor(ILI9341_BLACK);
  tft.setTextSize(2);
  tft.print("PLAYER1");
  tft.setTextColor(ILI9341_BLUE);
  tft.setCursor(5, 26);
  tft.println("TargetHits:");
  tft.setCursor(205, 26);
  tft.setTextColor(ILI9341_RED);
  tft.println("Hits:");

  tft.setCursor(5, 60);
  tft.setTextColor(ILI9341_BLACK);
  tft.print("PLAYER2");
  tft.setCursor(5, 76);
  tft.setTextColor(ILI9341_BLUE);
  tft.println("TargetHits:");
  tft.setCursor(205, 76);
  tft.setTextColor(ILI9341_RED);
  tft.println("Hits:");

  tft.setCursor(5, 110);
  tft.setTextColor(ILI9341_BLACK);
  tft.print("PLAYER3");
  tft.setTextColor(ILI9341_BLUE);
  tft.setCursor(5, 126);
  tft.println("TargetHits:");
  tft.setCursor(205, 126);
  tft.setTextColor(ILI9341_RED);
  tft.println("Hits:");

  tft.setCursor(5, 160);
  tft.setTextColor(ILI9341_BLACK);
  tft.print("PLAYER4");
  tft.setTextColor(ILI9341_BLUE);
  tft.setCursor(5, 176);
  tft.println("TargetHits:");
  tft.setCursor(205, 176);
  tft.setTextColor(ILI9341_RED);
  tft.println("Hits:");

  for (int i = 1; i < 254; i++) {  // Loop plays start up noise
    playTone((3000 - 9 * i), 2);
  }
}





// Main loop most of the code is in the sub routines
void loop() {



  char* str = readLine(Serial1);      // read incoming from radio module
  if (str != nullptr) {
    Serial.print("Eingelesen: ");
    Serial.println(str);
    compare(str);
    displayScores();
  }
  Battery();
  //static int pos = 0;
  encoder.tick();
  newPos = encoder.getPosition();       // get pulses from the encoder
  newPos = constrain(newPos, 0, 120);
  Time();
  if (Countdown) {
    CountdownTime();
  }
}


// SUB ROUTINES



char* readLine(Stream& stream) {      // handle the serial from the radio
  static byte index;
  static char buffer[READ_BUFFER_SIZE];

  while (stream.available()) {
    char c = stream.read();


    if (c == '\n')  // when LF read
    {
      buffer[index] = '\0';  // terminate string
      index = 0;
      return buffer;  //  

    } else if (c >= 32 && index < READ_BUFFER_SIZE - 1) 
    {
      buffer[index++] = c;  // store character and increment
    }
  }
  return nullptr;
}

void compare(char* str) {


  //Serial.println("compare running!");
  if (strstr(str, "Shooter")) {           // if "shooter" is received
    //Serial.println("Shooter received!");
    char* ptr = strchr(str, ':');
    int PlayerID = atoi(ptr + 1);
    score_players[PlayerID - 1][0]++;  // the player gets a kill point
  }

  if (strstr(str, "Killed")) {            // if "kill" is received
    Serial.println("Killed received!");
    char* ptr2 = strchr(str, ':');
    int PlayerID2 = atoi(ptr2 + 1);
    Serial.println("Killed Player");
    Serial.println(PlayerID2);
    score_players[PlayerID2 - 1][1]++;  // the player gets a hit point
  }
}


void displayScores() {                    // printing all the scores to the display

  tft.setTextSize(2);  // scores Player 1
  //tft.fillScreen(ILI9341_BLACK);
  tft.setTextColor(ILI9341_BLUE, ILI9341_WHITE);
  tft.setCursor(150, 26);
  tft.print(score_players[0][0]);
  tft.setCursor(270, 26);
  tft.setTextColor(ILI9341_RED, ILI9341_WHITE);
  tft.print(score_players[0][1]);
  Serial.println(score_players[0][1]);
  delay(500);

  tft.setTextColor(ILI9341_BLUE, ILI9341_WHITE);
  tft.setCursor(150, 76);
  tft.print(score_players[1][0]);
  tft.setCursor(270, 76);
  tft.setTextColor(ILI9341_RED, ILI9341_WHITE);
  tft.print(score_players[1][1]);

  tft.setTextColor(ILI9341_BLUE, ILI9341_WHITE);
  tft.setCursor(150, 126);
  tft.print(score_players[2][0]);
  tft.setCursor(270, 126);
  tft.setTextColor(ILI9341_RED, ILI9341_WHITE);
  tft.print(score_players[2][1]);

  tft.setTextColor(ILI9341_BLUE, ILI9341_WHITE);
  tft.setCursor(150, 176);
  tft.print(score_players[3][0]);
  tft.setCursor(270, 176);
  tft.setTextColor(ILI9341_RED, ILI9341_WHITE);
  tft.print(score_players[3][1]);
}

void Battery() {                            // print the battery voltage to the display

  float BattVal = analogRead(BattVolts);
  BattVoltage = ((BattVal / 1024.0) * 10.0);
  //Serial.println("BattVoltage");
  //Serial.println(BattVal);
  tft.setTextColor(ILI9341_BLACK, ILI9341_WHITE);
  tft.setCursor(5, 210);
  tft.print("Battery:");
  tft.setCursor(100, 210);
  tft.print(BattVoltage);
}

void Time() {                     // set the countdown time with the rotary encoder
  tft.setCursor(170, 210);
  tft.print("Time:");
  tft.setCursor(250, 210);
  tft.print(newPos);
  //tft.print(" ");
  int ButtonVal = digitalRead(Button);  // start the game by pushing the encoder button
  if (ButtonVal == LOW) {
    Countdown = true;
    Serial1.println("GameStart");
    startTime = millis();
  }
  //Serial.println("ButtonVal:");
  //Serial.println(ButtonVal);
}

void CountdownTime() {                // handles the countdown time of the game

  unsigned long factor{ newPos };
  constexpr unsigned long constExpression{ 60ul * 1000ul };
  unsigned long interval{ factor * constExpression };

  unsigned long difTime = millis() - startTime;
  if (difTime >= interval) {
    Serial.println("Gametime ended");
    Serial.println("Restart");
    tft.setCursor(240, 210);
    tft.print("      ");
    startTime = millis();
    difTime = 0;
    Countdown = false;
    digitalWrite(BuzzerPin, HIGH);
    delay(2000);
    digitalWrite(BuzzerPin, LOW);
  }
  unsigned long seconds = (interval - difTime) / 1000;
  unsigned long minutes = seconds / 60;
  seconds %= 60;
  minutes %= 60;

  char buf[10];
  tft.setCursor(240, 210);
  sprintf(buf, "%02lu:%02lu", minutes, seconds);
  tft.print(buf);
  delay(500);
  //tft.print(minutes);
  //tft.print(":");
  //tft.print(seconds);
  //tft.print(".................");
}


void playTone(int tone, int duration) {  // A sub routine for playing tones like the standard arduino melody example
  for (long i = 0; i < duration * 1000L; i += tone * 2) {
    digitalWrite(BuzzerPin, HIGH);
    delayMicroseconds(tone);
    digitalWrite(BuzzerPin, LOW);
    delayMicroseconds(tone);
  }
}

writing to TFTs can take a long time in computer terms causing delays in time critical actions such as reading rotary encoders
I would tend to move to a microcontroller with hardware QUI decoders, e.g. ESP32

one way to update sections of TFT text to change the text color to the background and rewrite the original text - change to required text color and output new text
only update screen when information changes

You are using delay() in your code that could be getting called more often than you want.
It may not be your actual issue but it would be better to find a "non-blocking" way to have a delay in your code.

There is an example sketch called "Blink without Delay" this is the go to sketch we tell everyone to learn as it extremely helpful when timing and flow are a factor.

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