TFT Display und SD Karte über SPI

Hallo Leute,

Ich brauche eure Hilfe. Es geht darum, dass ich ein TFT Display, genauer einen mit ili9340 Chip, zusammen mit einer SD Karten Modul benutzen möchte.

Mein Vorhaben:

Eine Text Datei von der SD Karte lesen und auf dem Display zeigen. Diese soll jeden Tag neu eingelesen und auf dem Display aktualisiert werden. Das Einlesen klappt bis jetzt ganz gut, jedoch möchte es in Verbindung mit dem Display nicht funktionieren.
Das Problem ist glaube ich hierbei, dass beide über SPI kommunizieren. Jedoch bin ich in diesem bereich relativ unerfahren.

Für das Display benutze ich die Library von Adafruit.

Mein Sketch bis jetzt:

#include "SPI.h"
#include "Adafruit_GFX.h"
#include "Adafruit_ILI9340.h"
#include "Sodaq_DS3231.h"
#include <SD.h>
#define MAX_ZEILE 210
//#include <Fonts/FreeSansBold18pt7b.h>

// These are the pins used for the UNO
// for Due/Mega/Leonardo use the hardware SPI pins (which are different)
#define _sclk 13
#define _miso 12
#define _mosi 11
#define _cs 10
#define _dc 9
#define _rst 8



Adafruit_ILI9340 tft = Adafruit_ILI9340(_cs, _dc, _rst);


String dateString;
int minuteNow=0;
int minutePrevious=0;
int dateNow=0;
int datePrevious=0;
char timeChar[80];
char dateChar[50] = {"00.00.0000"};
int zeile;
DateTime now;


const int READ_BUFFER_SIZE = 40;
char serialBuffer[READ_BUFFER_SIZE];
File myFile;

char *str [7] = {"0"};
char datum [50] = {"15.06.2016"};

void setup() {
  pinMode(4,OUTPUT);    // SD Card.
  digitalWrite(4,HIGH); 

  pinMode(10,OUTPUT);    // TFT
  digitalWrite(10,HIGH);
 
 
 
  SPI.begin();
  SD.begin(4);
  setRTCTime();
  tft.begin();
  rtc.begin();
 
 
  myFile = SD.open("test.txt");
  getRow(dateChar);
   
 
 
  tft.fillScreen(ILI9340_BLACK);
  tft.setRotation(3);
   
 
 
 
 
      printText(str[0],ILI9340_YELLOW,43,100,2);
      printText(str[1],ILI9340_YELLOW,43,120,2);
      printText(str[2],ILI9340_YELLOW,43,140,2);
      printText(str[3],ILI9340_YELLOW,43,160,2);
      printText(str[4],ILI9340_YELLOW,43,180,2);
     
      getDate();
 
   printText(dateChar, ILI9340_YELLOW,43,56,4);
 
}
uint32_t old_ts;
void loop() {
   now = rtc.now(); //get the current date-time

   uint32_t ts = now.getEpoch();

    if (old_ts == 0 || old_ts != ts) {
      old_ts = ts;
 
    minuteNow = now.minute();
    if(minuteNow!=minutePrevious) {
      minutePrevious = minuteNow;
      getTime();
      tft.fillRect(64, 0, 200, 55, ILI9340_BLACK);
      printText(timeChar, ILI9340_WHITE,65,5,6);
     
    }
    dateNow = now.date();
    if(dateNow!=datePrevious) {
      datePrevious = dateNow;
      getDate();
     getRow(dateChar);
   
      printText(str[0],ILI9340_YELLOW,220,100,2);
     
     
     
     
     
      tft.fillRect(44,57,240,30,ILI9340_BLACK);
      printText(dateChar, ILI9340_YELLOW,43,56,4);
     
     
     }
     
   }
 
  delay(1000);

}

bool readStream(File& myFile)  // Zeile für Zeile einlesen
{
  static byte index;
 
  while (myFile.available())
  {
    char c = myFile.read();

    if (c >= 32 && index < READ_BUFFER_SIZE - 1)
    {
      serialBuffer[index++] = c;
     
    }
    else if (c == '\n' && index > 0)
    {
      serialBuffer[index] = '\0';
      index = 0;
      return true;
    }
  }

  return false;
}



void getRow(char *datum){ // Akt. Datum in der Text Datei finden und einordnen.
  int i = 0;
  int z = 0;
 
 
  digitalWrite(10,HIGH);
   digitalWrite(4,LOW); 
  while(i<MAX_ZEILE && readStream(myFile)){
     
     if(strcmp(datum,serialBuffer) == 0){
     zeile = (i-1);
     
     
     }
   
     if(i>=zeile&& i<=(zeile+7) ){
      str[z] = strdup(serialBuffer);
      z++;
     
    }
     
     i++;
  }
    digitalWrite(4,HIGH); 
     digitalWrite(10,LOW);
}

Sketch wurde gekürzt.

SPI ist ein Bus; es können mehrere Geräte (slave) komunizieren. Jedes gerät braucht ein eigenes SS (EN) Signal.

zB Das Arduino-Ethernetshield hat den Ethernet-Chp auf Pin 10 und die SD Karte auf Pin 4.

Grüße Uwe

Ja soweit habe ich es auch verstanden. Ich habe mich vorher eingelesen. Laut Library ist die Sd karte auf Pin 4 und das Display pin 10. Ich habe die Sd Karte auf Low und das Display auf High geschaltet, wenn ich einlesen möchte und umgekehrt. Jedoch kann ich nur beim starten lesen aber später, wenn sich das Datum ändert, liest es nicht mehr. Oder mein Sketch hat Fehler…

Adafruit_ILI9340 tft = Adafruit_ILI9340(_cs, _dc, _rst);
SD.begin(4);

Die Signale an Pin 4 und 10 werden von den Bibliotheken übernommen, laß mal Deine Befehle dazu weg.

agmue:
Die Signale an Pin 4 und 10 werden von den Bibliotheken übernommen, laß mal Deine Befehle dazu weg.

Meinst du mit Befehle die hier:

digitalWrite(10,HIGH);
digitalWrite(4,LOW);

Ja, einschließlich noch pinMode(), das machen die Bibliotheken für Dich.

Soweit ich das verstanden habe kann man nur ein Gerät ansprechen und mit diesen Befehlen bestimme ich halt welches Gerät ich ansprechen möchte. Oder brauche ich das nicht?

Das machst Du schon an anderer Stelle, siehe #3. Bei myFile = SD.open("test.txt"); weiß die Bibliothek wegen SD.begin(4);, wie SPI einschließlich CS angesteuert werden muß.

Jetzt bekomme ich zwar den Text angezeigt, jedoch möchte ich den Text ja täglich aktualisieren. Und deswegen übergebe ich der Methode immer das akt. Datum. Der Text bleibt aber unverändert.

  dateNow = now.date();
    if(dateNow!=datePrevious) {
      datePrevious = dateNow;
      getDate();
     getRow(dateChar);
   
      printText(str[0],ILI9340_YELLOW,220,100,2);
     
     
     
     
     
      tft.fillRect(44,57,240,30,ILI9340_BLACK);
      printText(dateChar, ILI9340_YELLOW,43,56,4);
     
     
     }
     
   }

  delay(1000);

}

getRow(dateChar) ist die Methode.

Dein Sketch ist, wie Du ja schreibst, unvollständig und daher für mich nicht nachvollziehbar. Auch der Inhalt von test.txt ist nicht bekannt.

Den vollständigen Sketch und die Text Datei habe ich angehängt.

sketch_jun21a.ino (4.36 KB)

test.txt (1.52 KB)

Ich habe den Sketch an mein TFT angepaßt und sehe:
TFT 27sharp.png
Was soll anders sein?

Die Uhrzeiten sind falsch. Wenn du auf die Text Datei guckst, dann siehst man, dass z.B die erste Uhrzeit am 22.06.2016 3:48 sein muss. Das heißt das Programm nimmt immer nur den 21.06.2016 bzw. den obersten Eintrag.

Gruß

Wäre das so besser?
TFT 27sharp_2.png

Genau. Jetzt fehlt mir noch, dass sich das ganze jeden Tag bzw. wenn sich das Datum ändert auch aktualisiert.

Da ich nicht bis Mitternacht warten will, habe ich den Tageswechsel durch Verstellen der Uhr vorgezogen.

Inhalt der Textdatei:


22.06.2016
3:22
5:11
13:42
18:02
22:01
23:22
23.06.2016
3:23
5:11
13:42
18:02
22:01
23:23

Das ergibt folgende Anzeige:
TFT 27sharp_3.png
Das Anzeigen der Daten des nächsten Tages scheint also zu funktionieren, oder? :slight_smile:

Funktioniert tatsächlich :o Hast du etwas am Sketch verändert? Bei mir klappt das ja irgendwie nicht..

27sharp:
Hast du etwas am Sketch verändert?

Ja, geringfügig. Etwas mehr hinsichtlich meiner Hardware (8 Bit TFT mit Mega2560). Für Dich relevant sollten die Änderungen im Bereich getRow sein. Mein Testsketch:

#include <Wire.h>
#include "SPI.h"
#include "Adafruit_GFX.h"
#include <Adafruit_TFTLCD.h> // Hardware-specific library 
#include "Sodaq_DS3231.h"
#include <SD.h>

#define SD_CS 53   // Set the chip select line for SD-card
#define LCD_CS 31  // Chip Select 
#define LCD_CD A15 // Command/Data 
#define LCD_WR A14 // LCD Write 
#define LCD_RD 30  // LCD Read 
#define LCD_RESET 42 // Can alternately just connect to Arduino's reset pin 

Adafruit_TFTLCD tft(LCD_CS, LCD_CD, LCD_WR, LCD_RD, LCD_RESET);

// Color definitions
#define ILI9341_BLACK       0x0000      /*   0,   0,   0 */
#define ILI9341_NAVY        0x000F      /*   0,   0, 128 */
#define ILI9341_DARKGREEN   0x03E0      /*   0, 128,   0 */
#define ILI9341_DARKCYAN    0x03EF      /*   0, 128, 128 */
#define ILI9341_MAROON      0x7800      /* 128,   0,   0 */
#define ILI9341_PURPLE      0x780F      /* 128,   0, 128 */
#define ILI9341_OLIVE       0x7BE0      /* 128, 128,   0 */
#define ILI9341_LIGHTGREY   0xC618      /* 192, 192, 192 */
#define ILI9341_DARKGREY    0x7BEF      /* 128, 128, 128 */
#define ILI9341_BLUE        0x001F      /*   0,   0, 255 */
#define ILI9341_GREEN       0x07E0      /*   0, 255,   0 */
#define ILI9341_CYAN        0x07FF      /*   0, 255, 255 */
#define ILI9341_RED         0xF800      /* 255,   0,   0 */
#define ILI9341_MAGENTA     0xF81F      /* 255,   0, 255 */
#define ILI9341_YELLOW      0xFFE0      /* 255, 255,   0 */
#define ILI9341_WHITE       0xFFFF      /* 255, 255, 255 */
#define ILI9341_ORANGE      0xFD20      /* 255, 165,   0 */
#define ILI9341_GREENYELLOW 0xAFE5      /* 173, 255,  47 */
#define ILI9341_PINK        0xF81F

#define MAX_ZEILE 210

String dateString;
int minuteNow = 0;
int minutePrevious = 0;
int dateNow = 0;
int datePrevious = 0;
char timeChar[7] = {"00.00"};
char dateChar[15] = {"00.00.0000"};

DateTime now;
const int READ_BUFFER_SIZE = 40;
char serialBuffer[READ_BUFFER_SIZE];
File myFile;

char *str [7] = {"01234"};

void setup() {
  Serial.begin(9600);
  Serial.println("Anfang");
  SPI.begin();
  SD.begin(SD_CS);
  Wire.begin();
  rtc.begin();
  // setRTCTime(); // nur zum Setzen der Zeit in der RTC
  tft.reset();
  tft.begin(0x9341);
  tft.invert();
  tft.setRotation(1);
  tft.fillScreen(ILI9341_BLACK);
  myFile = SD.open("test.txt");
}
uint32_t old_ts;

void loop() {
  now = rtc.now(); //get the current date-time

  uint32_t ts = now.getEpoch();

  if (old_ts == 0 || old_ts != ts) {
    old_ts = ts;

    minuteNow = now.minute();
    if (minuteNow != minutePrevious) {
      minutePrevious = minuteNow;
      getTime();
      tft.fillRect(64, 0, 200, 55, ILI9341_BLACK);
      printText(timeChar, ILI9341_WHITE, 65, 5, 6);
    }
    dateNow = now.date();
    if (dateNow != datePrevious) {
      datePrevious = dateNow;
      getDate();
      tft.fillRect(44, 57, 240, 30, ILI9341_BLACK);
      printText(dateChar, ILI9341_YELLOW, 43, 56, 4);
      getRow(dateChar);
      printText(str[0], ILI9341_CYAN, 43, 100, 2);
      printText(str[1], ILI9341_CYAN, 43, 120, 2);
      printText(str[2], ILI9341_CYAN, 43, 140, 2);
      printText(str[3], ILI9341_CYAN, 43, 160, 2);
      printText(str[4], ILI9341_CYAN, 43, 180, 2);
      printText(str[5], ILI9341_CYAN, 43, 200, 2);
    }
  }
  delay(1000);
}

bool readStream(File& myFile)  // Zeile für Zeile einlesen
{
  static byte index;
  while (myFile.available())
  {
    char c = myFile.read();
    if (c >= 32 && index < READ_BUFFER_SIZE - 1)
    {
      serialBuffer[index++] = c;
    }
    else if (c == '\n' && index > 0)
    {
      serialBuffer[index] = '\0';
      index = 0;
      return true;
    }
  }
  return false;
}

void getRow(char *datum) { // Akt. Datum in der Text Datei finden und einordnen.
  int i = 0;
  int z = 0;
  int zeile = MAX_ZEILE;
  while (i < MAX_ZEILE && readStream(myFile)) {
    Serial.print(datum);
    Serial.print("   ");
    Serial.print(serialBuffer);
    Serial.print("   i: ");
    Serial.print(i);
    if (strcmp(datum, serialBuffer) == 0) {
      zeile = i;
    }
    if (i > zeile && i < (zeile + 7) ) {
      str[z] = strdup(serialBuffer);
      Serial.print("   z: ");
      Serial.print(z);
      z++;
    }
    if (i >= (zeile + 6)) {
      i = MAX_ZEILE;
    } else {
      i++;
    }
    Serial.println();
  }
  for (byte j = 0; j < 7; j++) {
    Serial.print(str[j]);
    Serial.print("  ");
  }
  Serial.println();
}

void setRTCTime()
{
  DateTime dt(2016, 6, 22, 20, 58, 00, 3); // Year, Month, Day, Hour, Minutes, Seconds, Day of Week
  rtc.setDateTime(dt); //Adjust date-time as defined 'dt' above
}
void printText(char *text, uint16_t color, int x, int y, int textSize)
{
  tft.setCursor(x, y);
  tft.setTextColor(color);
  tft.setTextSize(textSize);
  tft.setTextWrap(true);
  tft.print(text);
}
void getDate()
{
  now = rtc.now(); //get the current date-time

  if (now.date() < 10 && now.month() < 10)
  {
    dateString = "0" + String(now.date()) + "." + "0" + String(now.month()) + "." + String(now.year());
  }
  else if (now.date() < 10)
  {
    dateString = "0" + String(now.date()) + "." + String(now.month()) + "." + String(now.year());
  }
  else if (now.month() < 10)
  {
    dateString = String(now.date()) + "." + "0" + String(now.month()) + "." + String(now.year());
  }
  else
  {
    dateString = String(now.date()) + "." + String(now.month()) + "." + String(now.year());
  }

  dateString.toCharArray(dateChar, 15);

}
void getTime()
{
  String hours = String(now.hour());

  if (now.hour() < 10 && now.minute() < 10) {
    hours = "0" + hours + ":0" + String(now.minute());
  }
  else if (now.minute() < 10)
  {
    hours = hours + ":0" + String(now.minute());
  }
  else if (now.hour() < 10)
  {
    hours = "0" + hours + ":" + String(now.minute());
  }
  else
  {
    hours = hours + ":" + String(now.minute());
  }

  hours.toCharArray(timeChar, 7);
}

Danke funktioniert prima! :grinning:

Jetzt habe ich noch zwei Fragen.

  1. darf ich in diesem Fall myFile immer offen lassen ohne es mit close() zu schließen?

  2. Wie du wahrscheinlich bemerkt hast benutze ich in der getRow() Methode den Befehl “strdup”. Dies erzeugt ja dynamisch Speicher. Jetzt muss ich es ja wieder mit free() leeren, oder ?

Wenn ja, wie könnte ich es am besten tun?
Ich dachte daran den Inhalt von “str” zu einem neuen array zu kopieren und dann mit free(str) zu leeren.
Aber so ganz weiß ich nicht wie ich es machen soll.

27sharp: Danke funktioniert prima! :grinning:

Das freut mich :)

Zu 1: Ich habe bislang immer close() verwendet, also keine praktischen Erfahrungen ohne. Da Du nur lesend zugreifst, könnte es funktionieren.

Zu 2: Ist str nicht ein Zeiger und free() will einen Zeiger? Habe ich aber auch keine praktischen Erfahrungen. Diesen Zeiger verlagere ich daher zum -> Forum.