SD Card file read with TFT and touch

I have an SD card with 5 files on it. It will never have more than 5 files.
What I want to be able to do, from the TFT screen, is access the SD card, read the file names and display on the TFT screen, select one of the files from the touch pad and run it.

I have found a sketch that does exactly what I need by using the Arduino Serial monitor.
I have left the Serial.print, Serial.write etc calls in there and mimiced them with TFT calls so I have identical displays on the Arduino Serial monitor and my TFT display.
What I cant do is get the touch control to mimic the Serial monitor in putting in a value (eg. 1 for File 1), pressing the send button or pressing enter, and getting it to open the file.
Code is as follows.
I have highlighted and commented out the touch section in the sketch. If that is commented out, the program runs perfectly via the Serial Monitor. If left in, the Serial monitor prints the number "1" but states its an" invalid number" and will not open the file.
Any help would be appreciated.

#include<SPI.h>
#include "SdFat.h"
#include "FreeStack.h"

#include <Adafruit_GFX.h>
#include <MCUFRIEND_kbv.h>
#include <XPT2046_Touchscreen.h>   //.kbv
#include <Fonts/FreeSansBold24pt7b.h>
//#include <SD.h>
MCUFRIEND_kbv tft;
XPT2046_Touchscreen ts(53, 255);
const int TS_LANDSCAPE = 1;  //XPT2046_TouchScreen.h
const int TS_LEFT = 338, TS_RT = 3879, TS_TOP = 3767, TS_BOT = 237; //Red ST7796 Shield (landscape)
int pixel_x, pixel_y;     //Touch_getXY() updates global vars

bool Touch_getXY(void)

{
  bool pressed = ts.touched();
  if (pressed) {
    TS_Point p = ts.getPoint();
    if (TS_LANDSCAPE) mapxy(p.y, p.x);
    else mapxy(p.x, p.y);
    extern int x, y;  //to suit your global variables
    x = pixel_x;
    y = pixel_y;
  }
  return pressed;
}

void mapxy(int x, int y)
{
  //  int aspect = tft.getRotation();     //LANDSCAPE
  int tft_width = tft.width();
  int tft_height = tft.height();

  //LANDSCAPE
  pixel_x = map(y, TS_TOP, TS_BOT, 0, tft_width);
  pixel_y = map(x, TS_RT, TS_LEFT, 0, tft_height);

}

File root;

#define BLACK 0x0000
#define WHITE 0xFFFF

// SD card chip select pin.
const uint8_t SD_CS_PIN = 48;
int x, y;
SdFat sd;
SdFile dirFile;
SdFile file;

// Number of files found.
uint16_t numberOfFiles = 0;

// Position of file's directory entry.
uint16_t dirIndex[50];
SdFile parIndex[50];
//------------------------------------------------------------------------------

void setup()
{
  Serial.begin(9600);
  tft.reset();
  tft.begin(0x9488);
  ts.begin();          //.kbv XPT2046
  tft.setRotation(1);  //0 Landscape
  tft.fillScreen(BLACK);

  while (!Serial) {}

  // Initialize at the highest speed supported by the board that is
  // not over 50 MHz. Try a lower speed if SPI errors occur.
  if (!sd.begin(SD_CS_PIN, SD_SCK_MHZ(50)))
  {
    sd.initErrorHalt();
  }
  if (dirFile.open("/", O_READ))
  {
    printDirectory(dirFile, 0);
  }
}

void printDirectory (SdFile CFile, int numTabs)
{
  SdFile file;
  while (file.openNext(&CFile, O_READ))
  {
    if (file.isHidden() || false)
    {
      //file hidden, skip
    }
    else
    {
      for (uint8_t i = 0; i < numTabs; i++)
      {
        //create tabs for spacing
        Serial.print('\t');
      }
      if (file.isSubDir())
      {
        SdFile SubDirFile;
        printDirectory(SubDirFile, numTabs + 1);
      }
      else
      {
        // Save dirIndex of file in directory.
        dirIndex[numberOfFiles] = file.dirIndex();
        parIndex[numberOfFiles] = CFile;
        // Print the file number and name.
        tft.setTextColor(WHITE);
        tft.setTextSize(2);
        tft.print(numberOfFiles);
        Serial.print(numberOfFiles);
        tft.write(' ');
        Serial.write(' ');
        file.printName(&tft);
        file.printName(&Serial);
        tft.println();
        Serial.println();
        numberOfFiles++;
      }
    }
    file.close();
  }
}

void loop() {
  int c;
  char rx_byte = 1;
  // Read any existing Serial data.
  do {
    delay(10);
  } while (Serial.available() && Serial.read() >= 0);
  tft.fillRect(380, 10, 60, 60, WHITE);
  tft.setCursor (400, 30);
  tft.setTextColor(BLACK);
  tft.print("1");
  tft.setTextColor(WHITE);
  tft.setCursor (10, 100);
  tft.setTextSize(2);
  tft.print(F("\r\nEnter File Number: "));
  Serial.print(F("\r\nEnter File Number: "));

  while (!Serial.available()) {
    SysCall::yield();


    /*
        ///////////////////////////////////////////comment out below and use Serial Screen and it works
        while (true)
        {

          if (Touch_getXY())  //.kbv call a single function

          {

            //Serial.print(x); Serial.print(","); Serial.println(y);  //added 3march22

            if (x > 380  && x < 440)
            {

              if (y > 10 && y < 70)
              {
                Serial.print("1 ");
                delay(100);
              }
              /////////////////////////////////////////comment out above and use Serial Screen and it works
    */

  }
  c = Serial.read();
  uint8_t i = c - '0';
  if (!isdigit(c) || i >= numberOfFiles) {
    Serial.println(F("Invalid number"));
    return;

  }
  tft.println(i);
  Serial.println(i);
  if (!file.open(&parIndex[i], dirIndex[i], O_READ)) {
    sd.errorHalt(F("open"));
  }
  tft.println();
  Serial.println();

  char last = 0;

  // Copy up to 500 characters to Serial.
  for (int k = 0; k < 500 && (c = file.read()) > 0; k++)  {
    tft.write(last = (char)c);
    Serial.write(last = (char)c);
  }
  // Add new line if missing from last line.
  if (last != '\n') {
    tft.println();
    Serial.println();
  }
  file.close();
  Serial.flush();
  delay(100);

}
//    } ////////////////////////////////////comment out for Serial Screen
//  }  ////////////////////////////////   comment out for Serial Screen
//} ///////////////////////////////////   comment out for Serial Screen

None of this code...

        while (true)
        {

          if (Touch_getXY())  //.kbv call a single function

          {

            //Serial.print(x); Serial.print(","); Serial.println(y);  //added 3march22

            if (x > 380  && x < 440)
            {

              if (y > 10 && y < 70)
              {
                Serial.print("1 ");
                delay(100);
              }

sets up variable c ... which is used to determine the file number. I'm not sure what you expect to happen, but at some point you need to set c = "1" from the TFT logic, and not from the serial.monitor.

Probably should do this when you do...

                Serial.print("1 ");
                c = '1';  //   Add this line.

and also remove this line...

  c = Serial.read();

Thanks for that.
I had tried the c=‘1’ in the touch call before and it didn’t work. What I hadn’t done was remove the c=Serial.read(); from the original sketch. That was the trick to get the Touch working.
Thanks again for your help.

I added that sketch to my menu program but there are problems.
If I go straight to the SD read functions from setup, it works as expected.( see comments at end of Setup())
If I go to the SD read functions via a menu choice, it doesn't.
Izt appears that the files read section within the loop() function is not called ie. the screen display for selecting the file doesn't occur.

Code is as follows - with comments


#include <SPI.h>
#include <Adafruit_GFX.h>
#include <MCUFRIEND_kbv.h>
#include <XPT2046_Touchscreen.h>   //.kbv
#include <Fonts/FreeSansBold24pt7b.h>
//#include <SD.h>
#include "SdFat.h"
#include "FreeStack.h"
File root;

MCUFRIEND_kbv tft;

#define BLACK 0x0000
#define NAVY 0x000F
#define DARKGREEN 0x03E0
#define DARKCYAN 0x03EF
#define MAROON 0x7800
#define PURPLE 0x780F
#define OLIVE 0x7BE0
#define LIGHTGREY 0xC618
#define DARKGREY 0x7BEF
#define BLUE 0x001F
#define GREEN 0x07E0
#define CYAN 0x07FF
#define RED 0xF800
#define MAGENTA 0xF81F
#define YELLOW 0xFFE0
#define WHITE 0xFFFF
#define ORANGE 0xFD20
#define GREENYELLOW 0xAFE5
#define PINK 0xF81F

float Zsteprate = 1;
float XYsteprate = 10;
int Feedrate = 100;
float tp;  //touchpad thickness
float retract; //Z retract after touch
float dt; // distance to move down before reporting an error

XPT2046_Touchscreen ts(53, 255);
const int TS_LANDSCAPE = 1;  //XPT2046_TouchScreen.h
const int TS_LEFT = 300, TS_RT = 3830, TS_TOP = 3910, TS_BOT = 320; //Red ST7796 Shield (landscape) TS_LEFT = 338, TS_RT = 3879, TS_TOP = 3767, TS_BOT = 237
int pixel_x, pixel_y;     //Touch_getXY() updates global vars

#define path "/pics"
//#define CSPin 48

String *picList;
File dir;
int npics = 0;

bool Touch_getXY(void)

{

  bool pressed = ts.touched();

  if (pressed) {
    TS_Point p = ts.getPoint();

    if (TS_LANDSCAPE) mapxy(p.y, p.x);

    else mapxy(p.x, p.y);

    extern int x, y;  //to suit your global variables

    x = pixel_x;

    y = pixel_y;

  }

  return pressed;

}

void mapxy(int x, int y)
{
  int aspect = tft.getRotation();     //LANDSCAPE
  int tft_width = tft.width();
  int tft_height = tft.height();

  switch (aspect & 3) {

    case 0:      //PORTRAIT
      pixel_x = map(x, TS_LEFT, TS_RT, 0, tft_width);
      pixel_y = map(y, TS_TOP, TS_BOT, 0, tft_height);
      break;

    case 1:      //LANDSCAPE
      pixel_x = map(y, TS_TOP, TS_BOT, 0, tft_width);
      pixel_y = map(x, TS_RT, TS_LEFT, 0, tft_height);
      break;

    case 2:      //PORTRAIT REV
      pixel_x = map(x, TS_RT, TS_LEFT, 0, tft_width);
      pixel_y = map(y, TS_BOT, TS_TOP, 0, tft_height);
      break;

    case 3:      //LANDSCAPE REV
      pixel_x = map(y, TS_BOT, TS_TOP, 0, tft_width);
      pixel_y = map(x, TS_LEFT, TS_RT, 0, tft_height);
      break;
  }

}

//int x, y;

const uint8_t SD_CS_PIN = 48;
int x, y;
SdFat sd;
SdFile dirFile;
SdFile file;

// Number of files found.
uint16_t numberOfFiles = 0;

// Position of file's directory entry.
uint16_t dirIndex[50];
SdFile parIndex[50];
//------------------------------------------------------------------------------

void setup() {
  pinMode(48, OUTPUT);
  digitalWrite(48, HIGH);
  pinMode(53, OUTPUT);
  digitalWrite(53, HIGH);

  Serial.begin(9600);   //Use serial monitor for debugging .kbv 9600 is easier

  tft.reset();
  tft.begin(0x9488);
  ts.begin();          //.kbv XPT2046
  tft.setRotation(1);  //0 Landscape
  tft.fillScreen(BLACK);
  while (!Serial) {}

  // Initialize at the highest speed supported by the board that is
  // not over 50 MHz. Try a lower speed if SPI errors occur.
  if (!sd.begin(SD_CS_PIN, SD_SCK_MHZ(50)))
  {
    sd.initErrorHalt();
  }
  if (dirFile.open("/", O_READ))
  {
    //printDirectory(dirFile, 0);  //// if used, SD read works
    startmenu();                   //// if used and printDirectory(dirFile,0); is
                                   ///// selected from startmenu, doesn't work
  }
}

void loop() {
  int c;
  char rx_byte = 1;
  // Read any existing Serial data.
  do {
    delay(10);
  } while (Serial.available() && Serial.read() >= 0);
  tft.fillRect(390, 10, 60, 45, WHITE);
  tft.fillRect(390, 60, 60, 45, WHITE);
  tft.fillRect(390, 110, 60, 45, WHITE);
  tft.fillRect(390, 160, 60, 45, WHITE);
  tft.fillRect(390, 210, 60, 45, WHITE);
  tft.fillRect(390, 260, 60, 45, WHITE);
  tft.setCursor (410, 20);
  tft.setTextColor(BLACK);
  tft.print("0");
  tft.setCursor (410, 70);
  tft.print("1");
  tft.setCursor (410, 120);
  tft.print("2");
  tft.setCursor (410, 170);
  tft.print("3");
  tft.setCursor (392, 220);
  tft.print("Clear");
  tft.setCursor (395, 270);
  tft.print("Exit");
  tft.setTextColor(WHITE);
  tft.setCursor (10, 70);
  tft.setTextSize(2);
  tft.print(F("\r\nEnter File Number: "));
  Serial.print(F("\r\nEnter File Number: "));

  while (!Serial.available()) {
    SysCall::yield();

    while (true)
    {

      if (Touch_getXY())  //.kbv call a single function

      {

        Serial.print(x); Serial.print(","); Serial.println(y);  //added 3march22

        if (x > 380  && x < 440)
        {

          if (y > 20 && y < 40)
          {
            tft.fillRect(0, 110, 375, 220, BLACK);
            tft.fillRect(0, 109, 30, 30, BLACK);
            Serial.print("0 ");
            c = '0';
            delay(100);
          }
          if (y > 70 && y < 90)
          {
            tft.fillRect(0, 110, 375, 220, BLACK);
            tft.fillRect(0, 109, 30, 30, BLACK);
            Serial.print("1 ");
            c = '1';
            delay(100);
          }
          if (y > 120 && y < 140)
          {
            tft.fillRect(0, 140, 375, 220, BLACK);
            tft.fillRect(0, 109, 30, 30, BLACK);
            Serial.print("2 ");
            c = '2';
            delay(100);
          }
          if (y > 170 && y < 190)
          {
            tft.fillRect(0, 140, 375, 220, BLACK);
            tft.fillRect(0, 109, 30, 30, BLACK);
            Serial.print("3 ");
            c = '3';
            delay(100);
          }
          if (y > 225 && y < 245)
          {
            tft.fillRect(0, 140, 375, 220, BLACK);
            tft.fillRect(0, 109, 30, 30, BLACK);
            Serial.print("Clear ");
            delay(100);
          }
          if (y > 275 && y < 300)
          {
            Serial.print("Exit ");

            delay(100);
          }
        }
        // c = Serial.read();  // only need if using serialmonitor.
        uint8_t i = c - '0';
        if (!isdigit(c) || i >= numberOfFiles) {
          Serial.println(F("Invalid number"));
          return;

        }
        tft.setCursor(0, 110);
        tft.println(i);
        Serial.println(i);
        if (!file.open(&parIndex[i], dirIndex[i], O_READ)) {
          sd.errorHalt(F("open"));
        }
        tft.println();
        Serial.println();

        char last = 0;

        // Copy up to 500 characters to Serial.
        for (int k = 0; k < 500 && (c = file.read()) > 0; k++)  {
          tft.write(last = (char)c);
          Serial.write(last = (char)c);
        }
        // Add new line if missing from last line.
        if (last != '\n') {
          tft.println();
          Serial.println();
        }
        file.close();
        Serial.flush();
        delay(100);
      }
    }
  }
}


void startmenu() {
  int tft_width = tft.width();
  int tft_height = tft.height();
  tft.fillScreen(BLACK);
  tft.fillRoundRect(5, 50, 190, 50, 5, WHITE);
  tft.fillRoundRect(5, 120, 190, 50, 5, WHITE);
  tft.setCursor(100, 5);
  tft.setTextSize(3);
  tft.setTextColor(WHITE);
  tft.print ("MAIN MENU");
  tft.setTextColor(BLACK);
  tft.setTextSize(2);
  tft.setCursor(25, 65);
  tft.println("Second Screen");
  tft.setCursor(15, 135);
  tft.println("Read File List");
  delay(500);
  while (true)

  {

    if (Touch_getXY())  //.kbv call a single function

    {

      Serial.print(x); Serial.print(','); Serial.println(y);

      if (x > 5 && x < 200) //your RoundRect positions

      {

        if (y > 50 && y < 50 + 50)

        {

          secondscreen();
          delay(100);

        }

        if (y > 120 && y < 120 + 50)

        {
          tft.fillScreen(BLACK);
          printDirectory(dirFile, 0);

        }
      }
    }
  }
}

void secondscreen()
{
  tft.fillScreen(BLACK);
  tft.setCursor(10, 10);
  tft.setTextColor(WHITE);
  tft.setTextSize(3);
  tft.print("Second Screen");
  tft.setCursor(380, 280);
  tft.print("Exit");

  while (true)
  {

    if (Touch_getXY())

    {

      Serial.print(x); Serial.print(','); Serial.println(y);

      if (x > 340 && x < 480)   //your EXIT pixel positions

      {

        if ( y > 270 && y < 320)

        {
          startmenu();
          delay(500);
        }
      }
    }
  }
}

void printDirectory (SdFile CFile, int numTabs)
{
  SdFile file;
  while (file.openNext(&CFile, O_READ))
  {
    if (file.isHidden() || false)
    {
      //file hidden, skip
    }
    else
    {
      for (uint8_t i = 0; i < numTabs; i++)
      {
        //create tabs for spacing
        Serial.print('\t');
      }
      if (file.isSubDir())
      {
        SdFile SubDirFile;
        printDirectory(SubDirFile, numTabs + 1);
      }
      else
      {
        // Save dirIndex of file in directory.
        dirIndex[numberOfFiles] = file.dirIndex();
        parIndex[numberOfFiles] = CFile;
        // Print the file number and name.
        tft.setTextColor(WHITE);
        tft.setTextSize(2);
        tft.print(numberOfFiles);
        Serial.print(numberOfFiles);
        tft.write(' ');
        Serial.write(' ');
        file.printName(&tft);
        file.printName(&Serial);
        tft.println();
        Serial.println();
        numberOfFiles++;
      }
    }
    file.close();
  }
}

In startmenu() and secondscreen() there does not appear to be any way to exit the while(true) loops. You will never return from these calls.

They also call each other recursively.

When I go to the startmenu(), I have two choices; Second Screen “secondscreen()” and Read File List “ printDirectory(dirFile,0).
If I select Second Screen and I want to exit it back to MAIN MENU, I call “startmenu()”. Isn’t making the choice exiting the while(true)) loops. Isn’t that a normal way to select a function then exiting back? I’ve never had this problem with menu selections before but then again I normally don’t have any code in the loop() function.
Can you explain how they are calling each other recursively?
Can you give me a clue as to how this can be fixed?

OK. I added a “ break; “ statement after each “call back” in the “while(true)” loops and that seems to have fixed the problem. I’ll do a bit more testing and get back.

Edit.

Three more menu items and submenus and it works perfectly.
Thanks for the help and making me think rather than doing it for me.
Only way to learn.

Yes.. this will make it exit the while loop... and then return to the caller. That's what you want. :slight_smile:

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