Laby­rinth-Spiel mit TFT und Fernbedienung

Lese­zeit: 7 Minu­ten

Lösung
Seite als PDF

Mit Hil­fe einer Fern­be­die­nung wird auf einem TFT-Dis­play ein Ball durch ein klei­nes Laby­rinth bewegt. Beim Druck auf die *-Tas­te wird die Zeit­mes­sung gestartet.

Benö­tig­te Bauteile:

  • Keyes Fern­be­die­nung oder belie­bi­ge ande­re Fernbedienung
  • Infra­rotem­pfän­ger
  • 1,77 oder 1,8 Zoll TFT-Display
  • Lei­tungs­dräh­te

Baue die Schal­tung auf:

⇒Pin­be­le­gung ver­schie­de­ner TFT-Displays

1,77 und 1,8-Zoll gro­ße TFT-Modu­le haben eine Bild­schirm­auf­lö­sung von 128×160 Pixeln.

Ach­te auf die Pin­be­le­gung der Infrarotempfänger.

Ach­te dar­auf, dass die Bat­te­rie rich­tig ein­ge­legt wur­de. Der Minus-Pol liegt oben.

Die Fern­be­die­nung sen­det beim Druck auf die Tas­ten einen Zahlencode.

Tas­ten­codes Keyes-Fernbedienung

Pfeil oben
Tas­ten­code70 (0×46)
Pfeil linksTas­te OKPfeil rechts
Tas­ten­code68 (0×44)64 (0×40)67 (0×43)
Pfeil unten
Tas­ten­code21 (0×15)
Tas­te 1Tas­te 2Tas­te 3
Tas­ten­code22 (0×16)25 (0×19)13 (0xD)
Tas­te 4Tas­te 5Tas­te 6
Tas­ten­code12 (0xC)24 (0×18)94 (0x5E)
Tas­te 7Tas­te 8Tas­te 9
Tas­ten­code8 (0xB)28 (0x1C)90 (0x5A)
Tas­te *Tas­te 0Tas­te #
Tas­ten­code66 (0×42)82 (0×52)74 (0x4A)

⇒Tas­ten­codes Open­Smart Fernbedienung

⇒Test­pro­gramm belie­bi­ge Fernbedienung

Benö­tig­te Biblio­theken:

Die Tas­ten­codes kannst du mit fol­gen­dem Pro­gramm her­aus­fin­den. Sie wer­den im Seri­el­len Moni­tor angezeigt. 

// benötigte Bibliothek einbinden
#include "IRremote.h"

// der Pin, an dem der Infrarot-Empfänger angeschlossen ist
int EmpfaengerPin = 11;

void setup() 
{
  // Seriellen Monitor starten
  Serial.begin(9600);
  
  // Infrarot-Empfänger starten
  IrReceiver.begin(EmpfaengerPin);
}

void loop() 
{
  // decode() -> Daten lesen
  if (IrReceiver.decode()) 
  {
    // kurzes delay, damit nur ein Tastendruck gelesen wird
    
    delay(200);

    // resume -> nächsten Wert lesen
    IrReceiver.resume();

    /*
      der Empfänger empfängt zwischendurch Signale, 
      die nicht ausgewertet werden können
      es sollen dehalb nur die korrekt erkannten Tasten ausgewertet werden
      die Dezimalwerte der korrekten erkannten Tasten liegen zwischen > 0 und < 95
      es wird abgefragt, ob das empfangene Kommando decodedIRData.command
      zwischen 0 und (&&) 95 liegt
    */
    if (IrReceiver.decodedIRData.command > 0 && IrReceiver.decodedIRData.command < 95) 
    {
      Serial.print("Dezimalwert: ");

      // IrReceiver.decodedIRData.command = Wert der gedrückten Taste
      Serial.print(IrReceiver.decodedIRData.command);
      Serial.print(" -> ");

      // Werte abfragen und anzeigen
      if (IrReceiver.decodedIRData.command == 22) Serial.println("Taste 1");
      if (IrReceiver.decodedIRData.command == 25) Serial.println("Taste 2");
      if (IrReceiver.decodedIRData.command == 13) Serial.println("Taste 3");
      if (IrReceiver.decodedIRData.command == 12) Serial.println("Taste 4");
      if (IrReceiver.decodedIRData.command == 24) Serial.println("Taste 5");
      if (IrReceiver.decodedIRData.command == 94) Serial.println("Taste 6");
      if (IrReceiver.decodedIRData.command == 8) Serial.println("Taste 7");
      if (IrReceiver.decodedIRData.command == 28) Serial.println("Taste 8");
      if (IrReceiver.decodedIRData.command == 90) Serial.println("Taste 9");
      if (IrReceiver.decodedIRData.command == 82) Serial.println("Taste 0");
      if (IrReceiver.decodedIRData.command == 66) Serial.println("Taste *");
      if (IrReceiver.decodedIRData.command == 74) Serial.println("Taste #");
      if (IrReceiver.decodedIRData.command == 68) Serial.println("Pfeil links");
      if (IrReceiver.decodedIRData.command == 67) Serial.println("Pfeil rechts");
      if (IrReceiver.decodedIRData.command == 70) Serial.println("Pfeil oben");
      if (IrReceiver.decodedIRData.command == 21) Serial.println("Pfeil unten");
      if (IrReceiver.decodedIRData.command == 64) Serial.println("OK");
    }
  }
}

Bin­de die benö­ti­gen Biblio­the­ken ein und defi­nie­re die Varia­blen.
Das Aus­se­hen kann durch ver­schie­de­ne Para­me­ter beein­flusst werden:

  • Far­be der Blö­cke im Par­cours (Far­be­Bloe­cke)
  • Far­be des Krei­ses (Kreis­far­be)
  • Far­be der Schrift beim Start und bei der Anzei­ge der ver­stri­che­nen Zeit (Schrift­far­be)
  • Radi­us des Krei­ses (Radi­us)
  • Geschwin­dig­keit der Kreis­be­we­gung (Geschwin­dig­keit)
  • Anzahl der Pixel bei der Vor­wärts­be­we­gung (Bewe­gung)
#include "IRremote.h"
#include "Adafruit_ST7735.h"

/*
  Arduino
  SCK  13
  RST   9
  DC    8
  CS   10
  COPI 11
  #define TFT_CS        10
  #define TFT_RST        9
  #define TFT_DC         8
*/

#define TFT_CS 10
#define TFT_RST 9
#define TFT_DC  8

Adafruit_ST7735 tft = Adafruit_ST7735(TFT_CS, TFT_DC, TFT_RST);

/*
  Farben als hexadezimal definiert
  alternativ:
  int SCHWARZ = 0;
  int FARBE = 15;
  . . .
*/

// Pin des IR-Empfängers
int EmpfaengerPin = D6;

// Farben
#define SCHWARZ 0x0000     // dezimal 0
#define BLAU 0x000F        // dezimal 15
#define ROT 0xF800         // dezimal 406664
#define GRUEN 0x0E81       // dezimal 3713
#define CYAN 0x07FF        // dezimal 2047
#define MAGENTA 0xF81F     // dezimal 63519
#define GELB 0xAFE5        // dezimal 65504
#define WEISS 0xFFFF       // dezimal 65535
#define BRAUN 0xFC00       // dezimal 64512
#define GRAU 0xF7F0        // dezimal 63472
#define GRUENGELB 0xAFE5   // dezimal 45029
#define DUNKELCYAN 0x03EF  // dezimal 1007
#define ORANGE 0xFD20      // dezimal 64800
#define PINK 0xFC18        // dezimal 64536

// Farbe der Blöcke
#define FarbeBloecke GRUEN

// Farbe des Kreises
#define Kreisfarbe ROT

// Farbe der Schrift
#define Schriftfarbe WEISS

// Spiel starten wenn * gedrückt wurde
bool SpielStart = false;

// Radius des Kreises
const int Radius = 10;
const int Abstand = Radius * 2;

// je höher, dest langsamer
const int Geschwindigkeit = 100;

// Vorwärtsbewegung des Kreises in Pixeln
const int Bewegung = 5;

// Startposition des Kreises
int CursorX = Radius;
int CursorY = tft.height() / 2 - Abstand;

// Variable für die Zeitmessung
long Start;

Der set­up-Teil:

void setup() 
{
  // Startbildschirm
  // schwarzes Farbschema horizontale Ausrichtung
  // Cursor setzen, Schriftgröße und -farbe definieren
  tft.initR(INITR_BLACKTAB);
  tft.setRotation(0);
  tft.fillScreen(SCHWARZ);
  tft.setTextSize(2);
  tft.setCursor(1, 10);
  tft.setTextColor(Schriftfarbe);

  tft.println("Start:");
  tft.print("-> *");
  Serial.begin(9600);
  IrReceiver.begin(EmpfaengerPin);
}

Der loop-Teil. Beach­te die Kommentare.

void loop() 
{
  // nur ausführen, wenn SpielStart true
  if (IrReceiver.decode() && !SpielStart) 
  {
    // nächsten Wert lesen
    IrReceiver.resume();

    // Start mit *
    if (IrReceiver.decodedIRData.command == 66) 
    {
      // Spiel wird gestartet
      SpielStart = true;

      // Parcours bauen
      ParcoursBauen();

      // Zeitmessung starten
      Start = millis();
    }
  }

  // wenn die Taste * gedrückt wurde
  if (SpielStart) 
  {
    if (IrReceiver.decode()) 
    {
      // nächsten Wert lesen
      IrReceiver.resume();

      // nach oben
      if (IrReceiver.decodedIRData.command == 0x46) 
      {
        // Kreis an der aktuellen Position "löschen"
        tft.fillCircle(CursorX, CursorY, Radius, SCHWARZ);

        // wenn der Bildschirmrand noch nicht erreicht wurde
        // rückwärts (Richtung x = 1) bewegen
        if (CursorY > Radius) CursorY -= Bewegung;
        tft.fillCircle(CursorX, CursorY, Radius, Kreisfarbe);
        delay(Geschwindigkeit);
      }

      // nach unten
      if (IrReceiver.decodedIRData.command == 21) 
      {
        tft.fillCircle(CursorX, CursorY, Radius, SCHWARZ);
        if (CursorY < tft.height() - Radius) CursorY += Bewegung;
        tft.fillCircle(CursorX, CursorY, Radius, Kreisfarbe);
        delay(Geschwindigkeit);
      }

      // nach links
      if (IrReceiver.decodedIRData.command == 68) 
      {
        tft.fillCircle(CursorX, CursorY, Radius, SCHWARZ);
        if (CursorX > Radius) CursorX -= Bewegung;
        tft.fillCircle(CursorX, CursorY, Radius, Kreisfarbe);
        delay(Geschwindigkeit);
      }

      // nach rechts
      if (IrReceiver.decodedIRData.command == 67) 
      {
        tft.fillCircle(CursorX, CursorY, Radius, SCHWARZ);
        CursorX += Bewegung;
        tft.fillCircle(CursorX, CursorY, Radius, Kreisfarbe);
        delay(Geschwindigkeit);
      }
    }

    // rechter Bildschirmrand erreicht -> Spielende
    if (CursorX > tft.height() - Radius * 2) 
    {
      ErgebnisZeigen();
    }
  }
}

Jetzt feh­len noch die ⇒Funk­tio­nen Ergeb­nis­Zei­gen() und ParcoursBauen():

void ErgebnisZeigen() 
{
  // Zeit berechnen
  int Sekunden;
  long VerstricheneZeit = millis() - Start;
  Sekunden = int(VerstricheneZeit / 1000);

  // Zeit anzeigen
  tft.fillScreen(SCHWARZ);
  tft.setTextSize(2);
  tft.setCursor(1, 10);
  tft.println("Zeit:");
  tft.println(String(Sekunden) + " s");

  tft.setCursor(1, 40);
  tft.setTextColor(ROT);
  tft.println();
  tft.println("Neustart:");
  tft.println("-> *");

  // Neustart
  SpielStart = false;
}

void ParcoursBauen() 
{
  CursorX = Radius;
  CursorY = tft.height() / 2 - Abstand;
  tft.fillScreen(SCHWARZ);

  // Kreis anzeigen
  tft.fillCircle(CursorX, CursorY, Radius, Kreisfarbe);

  // Parcours "bauen"
  tft.fillRect(65, 35, 5, 45, FarbeBloecke);
  tft.fillRect(1, 1, 35, 35, FarbeBloecke);
  tft.fillRect(1, 80, 70, 80, FarbeBloecke);
  tft.fillRect(110, 1, 70, 95, FarbeBloecke);
  tft.fillRect(110, 130, 140, 160, FarbeBloecke);
}

Startseite
Aufgaben A-Z
Suchen
Downloads
Fehlermeldungen
Seite als PDF

Ver­wand­te Anleitungen:


Letzte Aktualisierung: Jan. 30, 2025 @ 13:20