Project tutorial
TFT Shield for Arduino Nano - Start

TFT Shield for Arduino Nano - Start © GPL3+

Shield, which facilitates connection to the Arduino Nano inexpensive TFT SPI display, micro SD card, Bluetooth module and cameras.

  • 1,744 views
  • 0 comments
  • 9 respects

Components and supplies

About this project

The story

There is hardly a person who has not seen and does not know what a color display is. And, probably, many have done (or would like to do) some project on Arduino using a color display. Moreover, such displays today are very widespread and affordable. There are many displays that differ in resolution, screen size, interface. I would like to dwell on one of these displays. We will be interested in a display with an interface of SPI, a resolution of 320x240 pixels and a screen diagonal size of 2.8 "(as well as 2.4" and 3.2 ").The SPI interface is very convenient for connecting to a microcontroller, since has a small number of signal lines. And the speed of SPI allows you to quickly update the contents of the screen. In general, a lot of advantages. But there are uncomfortable moments. For example, it is necessary to further coordinate the logic levels in the case of connecting the display to the Arduino boards with 5-volt power. For quick and easy connection of one of these displays (with the SPI interface) to Arduino Nano, we will use a small fee - TFT shield.

This shield is the second (lightweight, for Arduino Nano) version of TFT Shield for Arduino Uno, which you can read about here and here and here.

Brief description of TFT shield:

  • The size of the board is 64x49 mm,
  • 30-pin connector for connecting Arduino Nano,
  • 14-pin connector for connecting a TFT display 320x240 with an SPI interface (including a touch screen),
  • Connector for microSD card,
  • Connector for the Bluetooth module (HC-06),
  • 20-pin connector for camera OV7670 (as well as others),
  • Mini USB connector, as well as a separate 2-pin connector for power supply 5V.

So, let's begin.

Assembly

Assembling boards is very simple. But care must be taken to read the contact designations before installation.First you need to install the Arduino Nano board as shown in the photo. After that, a display is connected, which can be connected both on one side of the board (method 1) and on the other (method 2). After that, you can connect the power with a mini USB cable.The following are photos.

Method 1:

Method 2:

After assembly, you can proceed to the download of sketches, but before these do not forget to install the necessary library for working with the TFT shield. The library is located on the link: https://github.com/YATFT/YATFT.

Demo 1. Graphics and text.

This chapter provides an example of working with text, graphics, and a touch screen. It is recommended for convenience that you first program the Arduino Nano board separately and then assemble the device (but you can also program the board as part of the device). Sketch for working with text and graphics:

/******************************************************************************
* SOFTWARE AND DOCUMENTATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
* KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION, ANY WARRANTY
* OF MERCHANTABILITY, TITLE, NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR
* PURPOSE. IN NO EVENT SHALL AUTHOR OR ITS LICENSORS BE LIABLE OR
* OBLIGATED UNDER CONTRACT, NEGLIGENCE, STRICT LIABILITY, CONTRIBUTION,
* BREACH OF WARRANTY, OR OTHER LEGAL EQUITABLE THEORY ANY DIRECT OR INDIRECT
* DAMAGES OR EXPENSES INCLUDING BUT NOT LIMITED TO ANY INCIDENTAL, SPECIAL,
* INDIRECT, PUNITIVE OR CONSEQUENTIAL DAMAGES, LOST PROFITS OR LOST DATA,
* COST OF PROCUREMENT OF SUBSTITUTE GOODS, TECHNOLOGY, SERVICES, OR ANY
* CLAIMS BY THIRD PARTIES (INCLUDING BUT NOT LIMITED TO ANY DEFENSE THEREOF),
* OR OTHER SIMILAR COSTS.
*******************************************************************************/
#include <YATFT2.h>                      // Hardware-specific library
#include <Adafruit_GFX.h>                // Include Adafruit-GFX library
#include <Fonts/FreeSerif9pt7b.h>        // Include Adafruit fonts
#include <Fonts/FreeSerifItalic24pt7b.h>
#include <Fonts/FreeSans24pt7b.h>
YATFT tft(0);
uint32_t  total_time;
uint16_t  Color[4] = {BRIGHTBLUE, BRIGHTGREEN, BRIGHTRED, BRIGHTYELLOW};
uint16_t  Gray[7] = {GRAY0, GRAY1, GRAY2, GRAY3, GRAY4, GRAY5, GRAY6};
/******************************************************************************/
void ClearScreen (void)
{
   tft.SetColor(BLACK);   // Set fone color
   tft.ClearDevice();     // Fill all screen
}
void setup()
{
   Serial.begin(115200);  // initialize the serial port
   Serial.println("Arduino TFT_shield Example 1!");
   tft.begin();           // initialize the display
}
void loop()
{
   uint16_t  x, y, x2, y2, mask_gray;
   uint16_t  i;
   ClearScreen();
   // Fonts
   Serial.print("1) View Fonts (");
   total_time = millis();
   tft.SetColor(BRIGHTBLUE);
   tft.SetFont(NULL);
   tft.OutTextXY(5, 5, "Demonstration of work with the TFT display.");
   tft.SetColor(BRIGHTGREEN);
   tft.SetFont(&FreeSerif9pt7b);
   tft.OutTextXY(5, 20, "The   example   uses   fonts   from   Adafruit.");
   tft.SetFont(&FreeSerifItalic24pt7b);
   tft.SetColor(BRIGHTCYAN);
   tft.OutTextXY(5, 45, "3,5''");
   tft.SetColor(BRIGHTRED);
   tft.OutTextXY(90, 45, "QVGA");
   tft.SetColor(BRIGHTMAGENTA);
   tft.OutTextXY(230, 45, "disp.");
   tft.SetColor(BRIGHTYELLOW);
   tft.SetFont(&FreeSans24pt7b);
   tft.OutTextXY(5, 100, "A R D U I N O      +  T F T");
   tft.SetFont(NULL);
   for (i = 0; i < 7; i++)
   {
       tft.SetColor(Gray[i]);
       tft.OutTextXY(5, 170+10*i, "Demonstration of work with the TFT display.");
   }
   PrintTotalTime();
   delay(3000);
   ClearScreen();
   // Circle
   Serial.print("2) Draw circle (");
   total_time = millis();
   tft.SetColor(BRIGHTRED);
   for (i = 10; i < GetMaxY()>>1; i += 10) {
       tft.DrawCirc(GetMaxX()>>1, GetMaxY()>>1, i);
   }
   PrintTotalTime();
   delay(1000);
   // DrawFillCircle & DrawFillRect
   Serial.print("3) Draw FillCircle and FillRect (");
   total_time = millis();
   tft.SetColor(BRIGHTRED);
   tft.DrawFillCirc(GetMaxX()>>1,GetMaxY()>>1,110);
   tft.SetColor(BRIGHTCYAN);
   tft.DrawFillRect(GetMaxX()/2-77,GetMaxY()/2-77, GetMaxX()/2+77,GetMaxY()/2+77);
   tft.SetColor(BRIGHTGREEN);
   tft.DrawFillCirc(GetMaxX()>>1,GetMaxY()>>1,77);
   tft.SetColor(BRIGHTMAGENTA);
   tft.DrawFillRect(GetMaxX()/2-54,GetMaxY()/2-54, GetMaxX()/2+54,GetMaxY()/2+54);
   tft.SetColor(BRIGHTBLUE);
   tft.DrawFillCirc(GetMaxX()>>1,GetMaxY()>>1,54);
   tft.SetColor(BRIGHTYELLOW);
   tft.DrawFillRect(GetMaxX()/2-37,GetMaxY()/2-37, GetMaxX()/2+37,GetMaxY()/2+37);
   PrintTotalTime();
   delay(1000);
   ClearScreen();
   // Arc
   Serial.print("4) Draw Arc (");
   total_time = millis();
   ClearScreen();
   tft.SetColor(BRIGHTBLUE);
   tft.DrawArc((GetMaxX()>>1)-60,(GetMaxY()>>1)-60,(GetMaxX()>>1)+60,(GetMaxY()>>1)+60,20,30,0xFF);
   tft.SetColor(BRIGHTGREEN);
   tft.DrawArc((GetMaxX()>>1)-40,(GetMaxY()>>1)-40,(GetMaxX()>>1)+40,(GetMaxY()>>1)+40,20,30,0xFF);
   tft.SetColor(BRIGHTRED);
   tft.DrawArc((GetMaxX()>>1)-20,(GetMaxY()>>1)-20,(GetMaxX()>>1)+20,(GetMaxY()>>1)+20,20,30,0xFF);
   PrintTotalTime();
   delay(1000);
   Serial.print("5) Draw FillBevel (");
   total_time = millis();
   tft.SetColor(BRIGHTBLUE);
   tft.DrawFillBevel((GetMaxX()>>1)-60,(GetMaxY()>>1)-60,(GetMaxX()>>1)+60,(GetMaxY()>>1)+60,30);
   tft.SetColor(BRIGHTGREEN);
   tft.DrawFillBevel((GetMaxX()>>1)-40,(GetMaxY()>>1)-40,(GetMaxX()>>1)+40,(GetMaxY()>>1)+40,30);
   tft.SetColor(BRIGHTRED);
   tft.DrawFillBevel((GetMaxX()>>1)-20,(GetMaxY()>>1)-20,(GetMaxX()>>1)+20,(GetMaxY()>>1)+20,30);
   PrintTotalTime();
   delay(1000);
   ClearScreen();
   Serial.print("6) Draw Arc (");
   total_time = millis();
   for (i = 0; i < 4; i++) {
       tft.SetColor(Color[i]);
       tft.DrawArc((GetMaxX()>>1),(GetMaxY()>>1)-50,(GetMaxX()>>1),(GetMaxY()>>1)+50,50,60,0x11<<i);
   }
   for (i = 0; i < 4; i++) {
       tft.SetColor(Color[i]);
       tft.DrawArc((GetMaxX()>>1),(GetMaxY()>>1)-30,(GetMaxX()>>1),(GetMaxY()>>1)+30,35,45,0x11<<i);
   }
   for (i = 0; i < 4; i++) {
       tft.SetColor(Color[i]);
       tft.DrawArc((GetMaxX()>>1),(GetMaxY()>>1),(GetMaxX()>>1),(GetMaxY()>>1),20,30,0x11<<i);
   }
   PrintTotalTime();
   delay(1000);
   ClearScreen();
   // Draw 1000 random lines
   Serial.print("7) Draw 1000 random lines (");
   total_time = millis();
   for (i = 0; i < 1000; i++) {
       tft.SetColor(random(65535));
       x  = random(GetMaxX());
       y  = random(GetMaxY());
       x2 = random(GetMaxX());
       y2 = random(GetMaxY());
       tft.DrawLine(x, y, x2, y2);
   }
   PrintTotalTime();
   delay(1000);
   // ReDraw Fill Screen
   Serial.println("8) ReDraw 10 Fill Screen:");
   RedrawFillScreen(BLACK);
   RedrawFillScreen(BRIGHTBLUE);
   RedrawFillScreen(YELLOW);
   RedrawFillScreen(BRIGHTGREEN);
   RedrawFillScreen(BRIGHTRED);
   RedrawFillScreen(BRIGHTCYAN);
   RedrawFillScreen(GREEN);
   RedrawFillScreen(BRIGHTYELLOW);
   RedrawFillScreen(BRIGHTCYAN);
   RedrawFillScreen(BLACK);
}
void  PrintTotalTime (void)
{
   total_time = millis() - total_time;
   Serial.print(total_time);
   Serial.println(" ms)");
}
void  RedrawFillScreen (uint16_t color)
{
   // ReDraw Fill Screen
   Serial.print("ReDraw Fill Screen (");
   total_time = millis();
   tft.SetColor(color);   // Set fone color
   tft.ClearDevice();     // Fill all screen
   PrintTotalTime();
   delay(1000);
}

Some screenshots:

Demo 2. Touchscreen.

/******************************************************************************
* SOFTWARE AND DOCUMENTATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
* KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION, ANY WARRANTY
* OF MERCHANTABILITY, TITLE, NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR
* PURPOSE. IN NO EVENT SHALL AUTHOR OR ITS LICENSORS BE LIABLE OR
* OBLIGATED UNDER CONTRACT, NEGLIGENCE, STRICT LIABILITY, CONTRIBUTION,
* BREACH OF WARRANTY, OR OTHER LEGAL EQUITABLE THEORY ANY DIRECT OR INDIRECT
* DAMAGES OR EXPENSES INCLUDING BUT NOT LIMITED TO ANY INCIDENTAL, SPECIAL,
* INDIRECT, PUNITIVE OR CONSEQUENTIAL DAMAGES, LOST PROFITS OR LOST DATA,
* COST OF PROCUREMENT OF SUBSTITUTE GOODS, TECHNOLOGY, SERVICES, OR ANY
* CLAIMS BY THIRD PARTIES (INCLUDING BUT NOT LIMITED TO ANY DEFENSE THEREOF),
* OR OTHER SIMILAR COSTS.
*******************************************************************************/
#include <YATFT2.h>                      // Hardware-specific library
#include <SPI.h>                         // Include SPI library
#include <XPT2046_Touchscreen.h>         // Include Touchscreen library
#include <Adafruit_GFX.h>                // Include Adafruit-GFX library
#include <Fonts/FreeSerif9pt7b.h>        // Include Adafruit fonts
#include <Fonts/FreeSerifItalic24pt7b.h>
#include <Fonts/FreeSans24pt7b.h>
// Touchscreen: MOSI=11, MISO=12, SCK=13, CS=2
#define CS_PIN  A0
XPT2046_Touchscreen ts(CS_PIN, 255);
YATFT tft(0);
#define  Y_BAR_TOP      (GetMaxY()-50)
#define  Y_BAR_BOT      GetMaxY()
/* 
  If using the shield, all control and data lines are fixed, and
  a simpler declaration can optionally be used:
*/
uint16_t  pos_x[] = {0,0,0,0};
uint16_t  pos_y[] = {0,0,0,0};
uint8_t   pos_x_cnt = 0;
uint8_t   pos_y_cnt = 0;
uint16_t  pos_x_mid = 0;
uint16_t  pos_y_mid = 0;
uint16_t  color_paint = WHITE;
uint8_t   buttons = 0;
uint16_t  Color[4] = {BRIGHTBLUE, BRIGHTGREEN, BRIGHTRED, BRIGHTYELLOW};
uint16_t  Gray[7] = {GRAY0, GRAY1, GRAY2, GRAY3, GRAY4, GRAY5, GRAY6};
/*************************************************************************************************/
void ClearScreen (void)
{
   tft.SetColor(BLACK);   // Set fone color
   tft.ClearDevice();     // Fill all screen
}
void setup()
{
   Serial.begin(115200);  // initialize the serial port
   Serial.println("Arduino TFT_shield Example1!");
   ts.begin();            // Init Touchscreen
   SPI.end();             // Disable SPI for correct work DB2 (SS) pin 
   tft.begin();           // initialize the display
   RefreshWindow();
}
void loop()
{
   uint16_t  x, y;
   // Touch
   // When the SS pin is set as OUTPUT, it can be used as
   // a general purpose output port (it doesn't influence
   // SPI operations).
   SPI.begin();
   if (ts.touched())
   {
       TS_Point p = ts.getPoint();
       Serial.print(F("Pressure = "));
       Serial.print(p.z);
       Serial.print(F(", x = "));
       Serial.print(p.x);
       Serial.print(F(", y = "));
       Serial.print(p.y);
       Serial.println();
       delay(3);     // Delay for filtering
       SPI.end();  // Disable SPI for correct work DB2 (SS) pin 
       // Calculate coordinates x, y from code ADC
       Serial.print(F("Pressure = "));
       Serial.print(p.z);
       Serial.print(F(", x = "));
       Serial.print(p.x);
       Serial.print(F(", "));
       Serial.print(x);
       Serial.print(F(", y = "));
       Serial.print(p.y);
       Serial.print(F(", "));
       Serial.print(y);
       Serial.println();
       if (p.x <  350) p.x = 350;
       if (p.x > 3850) p.x = 3850;
       if (p.y <  250) p.y = 250;
       if (p.y > 3850) p.y = 3850;
       x = (uint16_t)(320L - ((uint32_t)p.x - 350L)*100L/1094L);
       y = (uint16_t)(240L - ((uint32_t)p.y - 250L)*100L/1510L);
       // Filtering 
       pos_x_mid = (pos_x[0] + pos_x[1] + pos_x[2] + pos_x[3])/4;
       pos_y_mid = (pos_y[0] + pos_y[1] + pos_y[2] + pos_y[3])/4;
       pos_x[pos_x_cnt++] = x;
       pos_y[pos_y_cnt++] = y;
       pos_x_cnt &= 0x03;
       pos_y_cnt &= 0x03;
       if (x > (pos_x_mid - 10) && x < (pos_x_mid + 10) && y > (pos_y_mid - 10) && y < (pos_y_mid + 10 )) {
           if (y > Y_BAR_TOP && y < Y_BAR_BOT) {
               if (x < 1*(GetMaxX()+1)/5) {  // Touch Bar 1
                   color_paint = Color[0];
                   RefreshTitle();
               } else
               if (x < 2*(GetMaxX()+1)/5) {  // Touch Bar 2
                   color_paint = Color[1];
                   RefreshTitle();
               } else
               if (x < 3*(GetMaxX()+1)/5) {  // Touch Bar 3
                   color_paint = Color[2];
                   RefreshTitle();
               } else
               if (x < 4*(GetMaxX()+1)/5) {  // Touch Bar 4
                   color_paint = Color[3];
                   RefreshTitle();
               } else {                     // Clear screen
                   RefreshWindow();
               }
           } else {
               tft.SetColor(color_paint);
               tft.DrawFillRect(x-1, y-1, x+1, y+1);
           }
       }
   }
   SPI.end();  // Disable SPI for correct work DB2 (SS) pin 
}
void  RefreshWindow(void)
{
   color_paint = WHITE;
   ClearScreen();
   for (uint8_t i = 0; i < 4; i++) {
       tft.SetColor(Color[i]);
       tft.DrawFillRect((i+1)*((GetMaxX()+1)/5), Y_BAR_TOP, (i)*((GetMaxX()+1)/5), Y_BAR_BOT);
   }
   RefreshTitle();
   tft.SetColor(WHITE);
   tft.OutTextXY(GetMaxX() - 50, GetMaxY() - 45, "Clear");
   tft.OutTextXY(GetMaxX() - 55, GetMaxY() - 25, "screen");
}
void  RefreshTitle(void)
{
   tft.SetColor(color_paint);
   tft.SetFont(&FreeSerif9pt7b);
   tft.OutTextXY(3, 20, "Touch     color     bar     and     screen     or     press     key.");
}

Some screenshots:

Demo 3. Logic game "Columns".

/******************************************************************************
* SOFTWARE AND DOCUMENTATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
* KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION, ANY WARRANTY
* OF MERCHANTABILITY, TITLE, NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR
* PURPOSE. IN NO EVENT SHALL AUTHOR OR ITS LICENSORS BE LIABLE OR
* OBLIGATED UNDER CONTRACT, NEGLIGENCE, STRICT LIABILITY, CONTRIBUTION,
* BREACH OF WARRANTY, OR OTHER LEGAL EQUITABLE THEORY ANY DIRECT OR INDIRECT
* DAMAGES OR EXPENSES INCLUDING BUT NOT LIMITED TO ANY INCIDENTAL, SPECIAL,
* INDIRECT, PUNITIVE OR CONSEQUENTIAL DAMAGES, LOST PROFITS OR LOST DATA,
* COST OF PROCUREMENT OF SUBSTITUTE GOODS, TECHNOLOGY, SERVICES, OR ANY
* CLAIMS BY THIRD PARTIES (INCLUDING BUT NOT LIMITED TO ANY DEFENSE THEREOF),
* OR OTHER SIMILAR COSTS.
*******************************************************************************/
#include <YATFT2.h>
#include <XPT2046_Touchscreen.h>
#include <SPI.h>
#include <Adafruit_GFX.h> // Core graphics library
#include <Fonts/FreeMonoBoldOblique12pt7b.h>
#include <Fonts/FreeSerif9pt7b.h>
#define CS_PIN  A0
// MOSI=11, MISO=12, SCK=13
XPT2046_Touchscreen ts(CS_PIN, 255);
YATFT tft(0);
/* 
  If using the shield, all control and data lines are fixed, and
  a simpler declaration can optionally be used:
*/
long randNumber;
#define KEY_EMPTY            0
#define KEY_SWAP             1
#define KEY_FALL             2
#define KEY_LEFT             3
#define KEY_RIGHT            4
#define DISPLAY_MAX_X 320
#define DISPLAY_MAX_Y 240
#define MaxCol               8 
#define MaxRow               17
#define SmeX                 3
#define SmeY                 3
#define razmer               15
#define LL                   250
#define NumCol               6
#define MaxLevel             8
#define PeriodLevel          80
#define DISP_LEFT    ((DISPLAY_MAX_X - MaxCol*razmer)/2 - 2)
#define DISP_RIGHT   ((DISPLAY_MAX_X + MaxCol*razmer)/2 + 2)
#define DISP_TOP     ((DISPLAY_MAX_Y - (MaxRow-4)*razmer)/2 - 2 - 10)
#define DISP_BOT     ((DISPLAY_MAX_Y + (MaxRow-4)*razmer)/2 + 2 - 10)
uint8_t  MasSt[MaxCol][MaxRow], MasTmp[MaxCol][MaxRow], MasOld[MaxCol][MaxRow], fignext[3];
uint8_t  Level=1, OldLevel, tr, flfirst=1;
uint16_t MasCol[]={WHITE, BLACK, BRIGHTRED, BRIGHTBLUE, BRIGHTGREEN, BRIGHTYELLOW, BRIGHTMAGENTA, BRIGHTCYAN};
unsigned long Counter,Score=0, TScore=0, Record=0, OldRecord, OldScore, myrecord;
uint16_t tempspeed;
bool     fl, Demo=true, myfl=false, Arbeiten=false, FlNew, FlZ=false;
int8_t   VAL, Mp, x,y;
int8_t   mmm [4][2]={{-1,0},{0,-1},{1,0},{0,1}};
uint16_t MasSpeed[MaxLevel]={500,450,400,350,300,250,200,100};
/******************************************************************/
void  setup(void)
{
   // initialize the serial port
   Serial.begin(115200);
   Serial.println("TFT_shield_Game1 example!");
   ts.begin();  // Init Touchscreen
   SPI.end();
   tft.begin(); // initialize the display
   randomSeed(analogRead(5));
   tft.SetColor(WHITE);
   tft.ClearDevice();
   tft.SetColor(RED);
   tft.SetFont(&FreeSerif9pt7b);
   tft.OutTextXY( 20,  20, "LEVEL");
   tft.OutTextXY(240,  20, "NEXT");
   tft.OutTextXY( 20,  75, "SCORE");
   tft.OutTextXY( 25, 130, "TOP");
   FlNew = true;
   ViewStacan();
   GetNext();
   delay(100);
   tft.SetColor(BLACK);
   tft.DrawLine(DISP_LEFT + 1, DISP_TOP + 0, DISP_LEFT + 1, DISP_BOT - 1);
   tft.DrawLine(DISP_LEFT + razmer*MaxCol+5-MaxCol,DISP_TOP + 0,DISP_LEFT + razmer*MaxCol+5-MaxCol, DISP_BOT - 1);
   tft.DrawLine(DISP_LEFT + 1, DISP_BOT - 1, DISP_LEFT + 1+razmer*MaxCol+5-MaxCol-1, DISP_BOT - 1);
}
void  loop(void)
{
   if (Demo)  ProcDemo();
   else {
       if (Arbeiten) {
           mydelay(tempspeed);
           figmove(0,1);
       } else  if (mypush()==KEY_SWAP) NewGame();
   }
}
uint8_t  mypush(void)
{
   unsigned long tpr = millis();
   uint8_t res = KEY_EMPTY;
   uint8_t button = 0;
   static uint8_t button_old;
   static uint8_t cnt = 0;
   button = Touch();
   if (button) {
     cnt = 5;
     Serial.print("Scan Button: ");
     Serial.print(button, HEX);
     Serial.println();
     if (button != button_old) {
       if (button & 0x01) res = KEY_SWAP;
       if (button & 0x02) res = KEY_FALL;
       if (button & 0x04) {};
       if (button & 0x08) res = KEY_LEFT;
       if (button & 0x10) res = KEY_RIGHT;
       button_old = button;
     }
   }
   if (!cnt) {
     button_old = button;
   } else {
     cnt--;
   }
   return(res); 
}
void  ViewQuad(uint8_t i,uint8_t  j,uint8_t mycolor)
{
   if (j<3) return; 
   uint16_t wy = DISP_TOP + SmeY + (j-3)*razmer - j;
   uint16_t wx = DISP_LEFT + SmeX + i*razmer - i;
   if (mycolor!=0) {
       tft.SetColor(BLACK);
       tft.DrawRect(wx, wy, wx+razmer-1, wy+razmer-1);
       tft.SetColor(MasCol[mycolor]);
       tft.DrawFillRect(wx+1, wy+1, wx+1+razmer-3, wy+1+razmer-3);
   } else {
       tft.SetColor(WHITE);
       tft.DrawFillRect(wx+1, wy+0, wx+1+razmer-3, wy+1+razmer-3);
   }
}
void  ViewStacan(void)
{
   char myStr2[5];
   uint8_t h = tft.GetTextHeight(&FreeMonoBoldOblique12pt7b);
   tft.SetFont(&FreeMonoBoldOblique12pt7b);
   if (OldScore!=Score || FlNew) {
       sprintf(myStr2,"%05d",Score);
       int16_t w = tft.GetTextWidth(myStr2, &FreeMonoBoldOblique12pt7b);
       tft.SetColor(WHITE);
       tft.DrawFillRect(20,100,20+w+5,100+h);
       tft.SetColor(GREEN);
       tft.OutTextXY(20,100,myStr2);
       OldScore=Score;
   }
   if (OldRecord!=Record || FlNew)  {
       sprintf(myStr2,"%05d",Record );
       int16_t w = tft.GetTextWidth(myStr2, &FreeMonoBoldOblique12pt7b);
       tft.SetColor(WHITE);
       tft.DrawFillRect(20,155,20+w+5,155+h);
       tft.SetColor(GREEN);
       tft.OutTextXY(20,155,myStr2);
       OldRecord=Record;
   }
   if (OldLevel!=Level || FlNew)  {
       sprintf(myStr2,"%01d",Level );
       int16_t w = tft.GetTextWidth(myStr2, &FreeMonoBoldOblique12pt7b);
       tft.SetColor(WHITE);
       tft.DrawFillRect(25,45,25+w+5,45+h);
       tft.SetColor(GREEN);
       tft.OutTextXY(25,45,myStr2);
       OldLevel=Level;
   }
   FlNew=false;
   for (byte j=3;j<MaxRow;j++)
       for (byte i=0;i<MaxCol;i++)
           if (MasSt[i][j]!=MasOld[i][j]) ViewQuad(i,j,MasSt[i][j]);
   for (byte j=3;j<MaxRow;j++)
       for (byte i=0;i<MaxCol;i++)
           MasOld[i][j]=MasSt[i][j];
}
void  ClearMas(byte MasStx[MaxCol][MaxRow])
{
   for (byte j=0;j<MaxRow;j++)
       for (byte i=0;i<MaxCol;i++)
           (MasStx[i][j]=0);
}
void  Sosed (int i,int j,int dx,int dy, byte mode)
{
   int nx=i+dx;
   int ny=j+dy;
   if (nx>=0 && ny>=0 && nx<MaxCol && ny<MaxRow && MasSt[nx][ny]==MasSt[i][j]) {
       if (mode==1) MasTmp[i][j]++;
       else
       if (mode==2 && (MasTmp[nx][ny]>1 || MasTmp[i][j]>2 )) {
           MasTmp[nx][ny]=3; 
           MasTmp[i][j]=3;
       } else
       if (mode==3 && MasTmp[nx][ny]==3) {
           if (MasTmp[i][j]!=3) {
               MasTmp[i][j]=3; 
               fl=true;
           }
       }
   }
}
void  Sos(int i,int j, byte mode)
{
   for (byte k=0;k<4;k++) Sosed(i,j,mmm[k][0],mmm[k][1],mode);      
}
bool  FindFull(void)
{
   byte  i,j,k; bool  res; 
   res = false; 
   for (byte k=2;k<8;k++) {
       ClearMas(MasTmp);
       for (j=3;j<MaxRow;j++)
           for (i=0;i<MaxCol;i++)
               if (MasSt[i][j]==k) Sos(i,j,1);
       for (j=3;j<MaxRow;j++)
           for (i=0;i<MaxCol;i++)
               if (MasTmp[i][j]>1) Sos(i,j,2);
       do {
           fl=false;
           for (j=3;j<MaxRow;j++)
               for (i=0;i<MaxCol;i++)
                   if (MasTmp[i][j]>0) Sos(i,j,3);
       } while (fl);
       for (j=3;j<MaxRow;j++)
           for (i=0;i<MaxCol;i++)
               if (MasTmp[i][j]==3) {
                   MasSt[i][j]=1;
                   TScore++;
               }
   }
   if (TScore>0) {
       ViewStacan();
       FlZ=true;
       mydelay(500);
   }
   for (j=0;j<MaxRow;j++)
       for (i=0;i<MaxCol;i++) {
           while (MasSt[i][MaxRow-1-j]==1) {
               for (k=0;k<MaxRow-2-j;k++) MasSt[i][MaxRow-1-k-j]= MasSt[i][MaxRow-2-k-j];
               res=true;  
           }
       }
   return(res);
}
void  GetNext(void)
{
   byte dx=255;
   byte dy=60;
   x=3;
   y=0;
   for (byte i=0;i<3;i++) {
       //fig[i]=fignext[i];
       if (!Demo) MasSt[x][i]=fignext[i];
       fignext[i]=random(NumCol)+2;
       tft.SetColor(BLACK);
       tft.DrawRect(dx,dy+(razmer-1)*i,dx+razmer, dy+(razmer-1)*(i+1)+1);
       tft.SetColor(MasCol[fignext[i]]);
       tft.DrawFillRect(dx+1,dy+(razmer-1)*i+1, dx+razmer-1, dy+(razmer-1)*(i+1));
   }
   if (!Demo) {
       Counter++;
       if (Counter==PeriodLevel) {
           Counter=0; 
           Level++; 
           if (Level>MaxLevel) Level=MaxLevel;
       }
       tempspeed=MasSpeed[Level-1];
   }
}
void  MyScore(void)
{
   TScore=0;
   while(FindFull()) {
       if (TScore>7) Score=Score+TScore+(TScore-8)*2;
       else Score=Score+TScore;
       ViewStacan();
       FlZ=true;
       mydelay(1000);
   }
   FlZ=false;
}
void  ProcDemo(void)
{
   Score=0;
   GetNext();
   for (byte j=3;j<MaxRow;j++)
       for (byte i=0;i<MaxCol;i++)
           MasSt[i][j]=random(6)+2;
   ViewStacan();
   mydelay(1000);
   if (!Demo) return;
   MyScore();
   if (Record<Score) Record=Score;
}
void  mydelay(int md)
{
   unsigned long starttime=millis();  
   while (millis()-starttime < md) {
       VAL=0;
       Mp=mypush();
       if (Mp==KEY_RIGHT) {
           VAL=1;
       } else
       if (Mp==KEY_LEFT) {
           VAL=-1;
       }
       if ((VAL!=0 || Mp!=KEY_EMPTY) && Demo) {
           Demo=false; 
           NewGame();
       }
       if (VAL!=0 && figmove(VAL, 0) && !FlZ) {
           for (byte i=0;i<3;i++) {
               MasSt[x+VAL][y+i]=MasSt[x][y+i];
               MasSt[x][y+i]=0; 
           }
           ViewStacan(); 
           if (MasSt[x][y+3]==0) {
               tft.SetColor(WHITE);
               tft.DrawLine(DISP_LEFT+SmeX+x*(razmer-1)+1, DISP_TOP+SmeY+y*(razmer-1)-3, DISP_LEFT+SmeX+(x+1)*(razmer-1)-1, DISP_TOP+SmeY+y*(razmer-1)-3);
           }
           x=x+VAL; 
       }
       if (Mp==KEY_SWAP && !FlZ) {
           byte aa=MasSt[x][y];
           MasSt[x][y]=MasSt[x][y+2];
           MasSt[x][y+2]=MasSt[x][y+1];
           MasSt[x][y+1]=aa;
           ViewStacan();
       }
       if (Mp==KEY_FALL && !FlZ) tempspeed=50; 
   }
}
void  NewGame(void)
{
   for (byte i=0; i<(MaxCol+1); i++) {
       tft.SetColor(BLACK);
       tft.DrawLine(DISP_LEFT+3+(razmer-1)*i, DISP_TOP, DISP_LEFT+3+(razmer-1)*i, DISP_BOT-3);
   }
   for (byte j=3;j<MaxRow;j++)
       for (byte i=0;i<MaxCol;i++)
           MasOld[i][j]=255;
   Score=0;
   FlNew=true;
   OldScore=Score;
   ClearMas(MasSt);
   Arbeiten=true;
   GetNext();
   Counter=0;
   Level=1;
   tempspeed=MasSpeed[0];
   Record=myrecord;
   ViewStacan();
}
void  gameover(void)
{
   Arbeiten=false;
   tft.SetColor(BLACK);
   tft.DrawRect(112,90,202,145);
   tft.SetColor(RED);
   tft.DrawFillRect(113,91,201,144);
   tft.SetFont(&FreeSerif9pt7b);
   tft.SetColor(WHITE);
   tft.OutTextXY(132, 100, "GAME");
   tft.OutTextXY(135, 120, "OVER");
}
bool  figmove(int dx, int dy)
{
   bool fff=false;
   if (x+dx<0 || x+dx>MaxCol-1) return(false);
   if (dx!=0) if (MasSt[x+dx][y+dy+2]==0) return(true); else return(false);
   if  (dy>0) {
       if (y+dy+2>MaxRow-1  || MasSt[x+dx][y+dy+2]>0) {
           if (y<3) gameover(); 
           else fff=true;
       } else {
           for (byte i=0;i<3;i++) MasSt[x][y+2-i+dy]=MasSt[x][y+2-i];
           MasSt[x][y]=0;                                 
           y=y+dy;
       }
       if (fff) {
           MyScore();
           GetNext(); 
       }
       ViewStacan(); 
   }
   return(true);
}
uint8_t  Touch(void)
{
   uint16_t  x, y;
   uint8_t  button = 0;
   // Touch
   // When the SS pin is set as OUTPUT, it can be used as
   // a general purpose output port (it doesn't influence
   // SPI operations).
   SPI.begin();
   if (ts.touched())
   {
       TS_Point p = ts.getPoint();
       delay(3);     // Delay for filtering
       SPI.end();
       // Calculate coordinates x, y from code ADC
       if (p.x < 450) p.x = 450;
       if (p.y < 500) p.y = 500;
       x = (uint16_t)(320L - ((uint32_t)p.x - 450L)*10L/106L);
       y = (uint16_t)(240L - ((uint32_t)p.y - 500L)*10L/140L);
       if (x < 80) { // Left
           button = 0x08;
       } else
       if (x > 240) { // Right
           button = 0x10;
       } else
       if (y < 120) { // Swap
           button = 0x01;
       } else
           button = 0x02; // Fall
   }
   SPI.end();
   return button;
}

Some screenshots:

Demo video

To be continued.

Thanks for attention!

Previous articles:

1) Unique TFT Shield for Arduino Uno - Start,

2) Unique TFT Shield for Arduino Uno - OV7670 Cam Live View,

3) Unique TFT Shield for Arduino Uno - Arduino Bluetooth Camera (ABC).

Next articles:

4) Photos and RGB video on TFT SPI display.

Code

Comments

Similar projects you might like

Display BMP Pictures from SD Card on TFT LCD Shield

Project tutorial by SurtrTech

  • 3,860 views
  • 0 comments
  • 8 respects

Interfacing and Fixing Touch Problem on TFT LCD 2.4″ Shield

Project tutorial by SurtrTech

  • 4,393 views
  • 7 comments
  • 25 respects

Unique TFT Shield for Arduino Uno (Start)

Project showcase by Alf81010

  • 3,083 views
  • 5 comments
  • 19 respects

Arduino Compatible Nano NeoPixel Controller

Project tutorial by Team Whimsy Makerspace

  • 17,390 views
  • 1 comment
  • 21 respects

Automatic LED Stairs Lighting Arduino Shield

Project tutorial by Aivaredze

  • 5,573 views
  • 3 comments
  • 17 respects

Spot Welder Controlled with an Arduino Nano

Project tutorial by Michael Marinis and PCBWay

  • 4,172 views
  • 5 comments
  • 20 respects
Add projectSign up / Login