Tic-tac-toe Game Based on Arduino and HMI

I think it’s fun and not boring to get familiar with a new product by making games, and that’s exactly why I did this project.

This project is to use Arduino UNO and Stone TFT LCD display to develop a simple tic-tac-toe game.

Materials required for the experiment

  • Arduino UNO
  • Stone STWI070WT-01 TFT LCD display

The system principle

Specify the first tap on the screen must be O, the second tap on the screen is X, has been doing this cycle. Set 8 arrays to store the number of O and X in each row, column and diagonal of each grid, as long as there are three of the same mark is the victory, then there will be a flashing red box to prove the victory of the row, column or diagonal, and then tap reset to start the game again.

Simple connection diagram

1

GUI design

code sharing

unsigned int r_flag1 = 0;
uint8_t   RecievedTemp1[30]       = {0};
//uint8_t   *RecievedTemp1 = new uint8_t[30];
uint8_t   cout_i = 0;
unsigned int quan_hang1 = 0;
unsigned int quan_hang2 = 0;
unsigned int quan_hang3 = 0;
unsigned int quan_lie1 = 0;
unsigned int quan_lie2 = 0;
unsigned int quan_lie3 = 0;
unsigned int quan_zuoxia = 0;
unsigned int quan_youxia = 0;

//unsigned int quan[8]={0};
//
unsigned int cha_hang1 = 0;
unsigned int cha_hang2 = 0;
unsigned int cha_hang3 = 0;
unsigned int cha_lie1 = 0;
unsigned int cha_lie2 = 0;
unsigned int cha_lie3 = 0;
unsigned int cha_zuoxia = 0;
unsigned int cha_youxia = 0;
unsigned int cha[8]={0};
void setup()
{
   Serial.begin(115200);
   for(int i=3; i<=8; i++) 
   pinMode(i,OUTPUT);
}

void loop(){

  if(Serial.available() != 0)
  {
//    for(cout_i = 0; cout_i < 30; cout_i ++)
//    {
//        //RecievedTemp1[cout_i] = Serial.readBytes(RecievedTemp1, 15);
//        Serial.readBytes(RecievedTemp1, 20);
//        //Serial.println(RecievedTemp1[cout_i]);
//    }
    Serial.readBytes(RecievedTemp1, 20);
    for(cout_i = 0; cout_i < 19; cout_i ++)
    {
    Serial.println(RecievedTemp1[cout_i]);
    }
    switch(RecievedTemp1[13])
  {
  case 49:
        if((r_flag1 == 0)&&(RecievedTemp1[14]==2))
        {
        Serial.println(F("ST<{\"cmd_code\":\"set_image\",\"type\":\"image\",\"widget\":\"image2\",\"image\":\"circle\"}>ET"));
        r_flag1 = 1;
        quan_hang1++;
        quan_lie1++;
        quan_youxia++;
//        quan[0]++;
//        quan[3]++;
//        quan[7]++;
        Serial.println(F("ST<{\"cmd_code\":\"set_enable\",\"type\":\"widget\",\"widget\":\"button1\",\"enable\":false}>ET"));
        }
        else if((r_flag1 == 1)&&(RecievedTemp1[14]==2))
        {
          Serial.println(F("ST<{\"cmd_code\":\"set_image\",\"type\":\"image\",\"widget\":\"image2\",\"image\":\"x\"}>ET"));
         r_flag1 = 0;
            cha_hang1++;
            cha_lie1++;
            cha_youxia++;
//        cha[0]++;
//        cha[3]++;
//        cha[7]++;
            Serial.println(F("ST<{\"cmd_code\":\"set_enable\",\"type\":\"widget\",\"widget\":\"button1\",\"enable\":false}>ET"));
        }
        
        break;
  case 50:
        if((r_flag1 == 0)&&(RecievedTemp1[14]==2))
        {
        Serial.println(F("ST<{\"cmd_code\":\"set_image\",\"type\":\"image\",\"widget\":\"image3\",\"image\":\"circle\"}>ET"));
        r_flag1 = 1;
        quan_hang1++;
            quan_lie2++;
//        quan[0]++;
//        quan[4]++;
            Serial.println(F("ST<{\"cmd_code\":\"set_enable\",\"type\":\"widget\",\"widget\":\"button2\",\"enable\":false}>ET"));
        }
        else if((r_flag1 == 1)&&(RecievedTemp1[14]==2))
        {
          Serial.println(F("ST<{\"cmd_code\":\"set_image\",\"type\":\"image\",\"widget\":\"image3\",\"image\":\"x\"}>ET"));
         r_flag1 = 0;
         cha_hang1++;
           cha_lie2++;
//        cha[0]++;
//        cha[4]++;
           Serial.println(F("ST<{\"cmd_code\":\"set_enable\",\"type\":\"widget\",\"widget\":\"button2\",\"enable\":false}>ET"));
        }
        break;
  case 51:
        if((r_flag1 == 0)&&(RecievedTemp1[14]==2))
        {
        Serial.println(F("ST<{\"cmd_code\":\"set_image\",\"type\":\"image\",\"widget\":\"image4\",\"image\":\"circle\"}>ET"));
        r_flag1 = 1;
        quan_hang1++;
            quan_lie3++;
            quan_zuoxia++;
//        quan[0]++;
//        quan[5]++;
//        quan[6]++;
            Serial.println(F("ST<{\"cmd_code\":\"set_enable\",\"type\":\"widget\",\"widget\":\"button3\",\"enable\":false}>ET"));
        }
        else if((r_flag1 == 1)&&(RecievedTemp1[14]==2))
        {
          Serial.println(F("ST<{\"cmd_code\":\"set_image\",\"type\":\"image\",\"widget\":\"image4\",\"image\":\"x\"}>ET"));
         r_flag1 = 0;
         cha_hang1++;
           cha_lie3++;
            cha_zuoxia++;
//        cha[0]++;
//        cha[5]++;
//        cha[6]++;
            Serial.println(F("ST<{\"cmd_code\":\"set_enable\",\"type\":\"widget\",\"widget\":\"button3\",\"enable\":false}>ET"));
        }
        break;
  case 52:
        if((r_flag1 == 0)&&(RecievedTemp1[14]==2))
        {
        Serial.println(F("ST<{\"cmd_code\":\"set_image\",\"type\":\"image\",\"widget\":\"image5\",\"image\":\"circle\"}>ET"));
        r_flag1 = 1;
        quan_hang2++;
            quan_lie1++;
            Serial.println(F("ST<{\"cmd_code\":\"set_enable\",\"type\":\"widget\",\"widget\":\"button4\",\"enable\":false}>ET"));
        }
        else if((r_flag1 == 1)&&(RecievedTemp1[14]==2))
        {
          Serial.println(F("ST<{\"cmd_code\":\"set_image\",\"type\":\"image\",\"widget\":\"image5\",\"image\":\"x\"}>ET"));
         r_flag1 = 0;
         cha_hang2++;
           cha_lie1++;
           Serial.println(F("ST<{\"cmd_code\":\"set_enable\",\"type\":\"widget\",\"widget\":\"button4\",\"enable\":false}>ET"));
        }
        break;
  case 53:
        if((r_flag1 == 0)&&(RecievedTemp1[14]==2))
        {
        Serial.println(F("ST<{\"cmd_code\":\"set_image\",\"type\":\"image\",\"widget\":\"image6\",\"image\":\"circle\"}>ET"));
        r_flag1 = 1;
        quan_hang2++;
            quan_lie2++;
            quan_zuoxia++;
            quan_youxia++;
            Serial.println(F("ST<{\"cmd_code\":\"set_enable\",\"type\":\"widget\",\"widget\":\"button5\",\"enable\":false}>ET"));
        }
        else if((r_flag1 == 1)&&(RecievedTemp1[14]==2))
        {
          Serial.println(F("ST<{\"cmd_code\":\"set_image\",\"type\":\"image\",\"widget\":\"image6\",\"image\":\"x\"}>ET"));
          r_flag1 = 0;
          cha_hang2++;
            cha_lie2++;
            cha_zuoxia++;
            cha_youxia++;
            Serial.println(F("ST<{\"cmd_code\":\"set_enable\",\"type\":\"widget\",\"widget\":\"button5\",\"enable\":false}>ET"));
        }
        break;       
  case 54:
        if((r_flag1 == 0)&&(RecievedTemp1[14]==2))
        {
        Serial.println(F("ST<{\"cmd_code\":\"set_image\",\"type\":\"image\",\"widget\":\"image7\",\"image\":\"circle\"}>ET"));
        r_flag1 = 1;
        quan_hang2++;
            quan_lie3++;
//        quan[1]++;
            Serial.println(F("ST<{\"cmd_code\":\"set_enable\",\"type\":\"widget\",\"widget\":\"button6\",\"enable\":false}>ET"));
        }
        else if((r_flag1 == 1)&&(RecievedTemp1[14]==2))
        {
          Serial.println(F("ST<{\"cmd_code\":\"set_image\",\"type\":\"image\",\"widget\":\"image7\",\"image\":\"x\"}>ET"));
         r_flag1 = 0;
         cha_hang2++;
           cha_lie3++;
           Serial.println(F("ST<{\"cmd_code\":\"set_enable\",\"type\":\"widget\",\"widget\":\"button6\",\"enable\":false}>ET"));
        }
        break;       
  case 55:
        if((r_flag1 == 0)&&(RecievedTemp1[14]==2))
        {
        Serial.println(F("ST<{\"cmd_code\":\"set_image\",\"type\":\"image\",\"widget\":\"image8\",\"image\":\"circle\"}>ET"));
        r_flag1 = 1;
        quan_hang3++;
            quan_lie1++;
            quan_zuoxia++;
            Serial.println(F("ST<{\"cmd_code\":\"set_enable\",\"type\":\"widget\",\"widget\":\"button7\",\"enable\":false}>ET"));
        }
        else if((r_flag1 == 1)&&(RecievedTemp1[14]==2))
        {
          Serial.println(F("ST<{\"cmd_code\":\"set_image\",\"type\":\"image\",\"widget\":\"image8\",\"image\":\"x\"}>ET"));
         r_flag1 = 0;
         cha_hang3++;
           cha_lie1++;
            cha_zuoxia++;
            Serial.println(F("ST<{\"cmd_code\":\"set_enable\",\"type\":\"widget\",\"widget\":\"button7\",\"enable\":false}>ET"));
        }
        break;        
  case 56:
        if((r_flag1 == 0)&&(RecievedTemp1[14]==2))
        {
        Serial.println(F("ST<{\"cmd_code\":\"set_image\",\"type\":\"image\",\"widget\":\"image9\",\"image\":\"circle\"}>ET"));
        r_flag1 = 1;
        quan_hang3++;
            quan_lie2++;
            Serial.println(F("ST<{\"cmd_code\":\"set_enable\",\"type\":\"widget\",\"widget\":\"button8\",\"enable\":false}>ET"));
        }
        else if((r_flag1 == 1)&&(RecievedTemp1[14]==2))
        {
          Serial.println(F("ST<{\"cmd_code\":\"set_image\",\"type\":\"image\",\"widget\":\"image9\",\"image\":\"x\"}>ET"));
         r_flag1 = 0;
         cha_hang3++;
           cha_lie2++;
           Serial.println(F("ST<{\"cmd_code\":\"set_enable\",\"type\":\"widget\",\"widget\":\"button8\",\"enable\":false}>ET"));
        }
        break;       
  case 57:
        if((r_flag1 == 0)&&(RecievedTemp1[14]==2))
        {
        Serial.println(F("ST<{\"cmd_code\":\"set_image\",\"type\":\"image\",\"widget\":\"image10\",\"image\":\"circle\"}>ET"));
        r_flag1 = 1;
        quan_hang3++;
            quan_lie3++;
            quan_youxia++;
            Serial.println(F("ST<{\"cmd_code\":\"set_enable\",\"type\":\"widget\",\"widget\":\"button9\",\"enable\":false}>ET"));
        }
        else if((r_flag1 == 1)&&(RecievedTemp1[14]==2))
        {
          Serial.println(F("ST<{\"cmd_code\":\"set_image\",\"type\":\"image\",\"widget\":\"image10\",\"image\":\"x\"}>ET"));
         r_flag1 = 0;
         cha_hang3++;
           cha_lie3++;
            cha_youxia++;
            Serial.println(F("ST<{\"cmd_code\":\"set_enable\",\"type\":\"widget\",\"widget\":\"button9\",\"enable\":false}>ET"));
        }
        break;
  case 48:
            r_flag1 = 0;
            quan_hang1=quan_hang2=quan_hang3=cha_hang1=cha_hang2=cha_hang3=0;
            quan_lie1=quan_lie2=quan_lie3=cha_lie1=cha_lie2=cha_lie3=0;
            quan_zuoxia=quan_youxia=cha_zuoxia=cha_youxia=0;
//            for(char count_i=50;count_i<58;count_i++)
//            {
//              Serial.println((("ST<{\"cmd_code\":\"set_image\",\"type\":\"image\",\"widget\":\"image%c\",\"image\":\"bai\"}>ET"),count_i));
//              }
            Serial.println(F("ST<{\"cmd_code\":\"set_image\",\"type\":\"image\",\"widget\":\"image2\",\"image\":\"bai\"}>ET"));
            Serial.println(F("ST<{\"cmd_code\":\"set_image\",\"type\":\"image\",\"widget\":\"image3\",\"image\":\"bai\"}>ET"));
            Serial.println(F("ST<{\"cmd_code\":\"set_image\",\"type\":\"image\",\"widget\":\"image4\",\"image\":\"bai\"}>ET"));
            Serial.println(F("ST<{\"cmd_code\":\"set_image\",\"type\":\"image\",\"widget\":\"image5\",\"image\":\"bai\"}>ET"));
            Serial.println(F("ST<{\"cmd_code\":\"set_image\",\"type\":\"image\",\"widget\":\"image6\",\"image\":\"bai\"}>ET"));
            Serial.println(F("ST<{\"cmd_code\":\"set_image\",\"type\":\"image\",\"widget\":\"image7\",\"image\":\"bai\"}>ET"));
            Serial.println(F("ST<{\"cmd_code\":\"set_image\",\"type\":\"image\",\"widget\":\"image8\",\"image\":\"bai\"}>ET"));
            Serial.println(F("ST<{\"cmd_code\":\"set_image\",\"type\":\"image\",\"widget\":\"image9\",\"image\":\"bai\"}>ET"));
            Serial.println(F("ST<{\"cmd_code\":\"set_image\",\"type\":\"image\",\"widget\":\"image10\",\"image\":\"bai\"}>ET"));
            Serial.println(F("ST<{\"cmd_code\":\"set_visible\",\"type\":\"widget\",\"widget\":\"gif4\",\"visible\":false}>ET"));
            Serial.println(F("ST<{\"cmd_code\":\"set_visible\",\"type\":\"widget\",\"widget\":\"gif5\",\"visible\":false}>ET"));
            Serial.println(F("ST<{\"cmd_code\":\"set_visible\",\"type\":\"widget\",\"widget\":\"gif6\",\"visible\":false}>ET"));
            Serial.println(F("ST<{\"cmd_code\":\"set_visible\",\"type\":\"widget\",\"widget\":\"gif7\",\"visible\":false}>ET"));
            Serial.println(F("ST<{\"cmd_code\":\"set_visible\",\"type\":\"widget\",\"widget\":\"gif8\",\"visible\":false}>ET"));
            Serial.println(F("ST<{\"cmd_code\":\"set_visible\",\"type\":\"widget\",\"widget\":\"gif9\",\"visible\":false}>ET"));
            Serial.println(F("ST<{\"cmd_code\":\"set_visible\",\"type\":\"widget\",\"widget\":\"gif10\",\"visible\":false}>ET"));
            Serial.println(F("ST<{\"cmd_code\":\"set_visible\",\"type\":\"widget\",\"widget\":\"gif11\",\"visible\":false}>ET"));
            Serial.println(F("ST<{\"cmd_code\":\"set_enable\",\"type\":\"widget\",\"widget\":\"button9\",\"enable\":true}>ET"));
            Serial.println(F("ST<{\"cmd_code\":\"set_enable\",\"type\":\"widget\",\"widget\":\"button8\",\"enable\":true}>ET"));
            Serial.println(F("ST<{\"cmd_code\":\"set_enable\",\"type\":\"widget\",\"widget\":\"button7\",\"enable\":true}>ET"));
            Serial.println(F("ST<{\"cmd_code\":\"set_enable\",\"type\":\"widget\",\"widget\":\"button6\",\"enable\":true}>ET"));
            Serial.println(F("ST<{\"cmd_code\":\"set_enable\",\"type\":\"widget\",\"widget\":\"button5\",\"enable\":true}>ET"));
            Serial.println(F("ST<{\"cmd_code\":\"set_enable\",\"type\":\"widget\",\"widget\":\"button4\",\"enable\":true}>ET"));
            Serial.println(F("ST<{\"cmd_code\":\"set_enable\",\"type\":\"widget\",\"widget\":\"button3\",\"enable\":true}>ET"));
            Serial.println(F("ST<{\"cmd_code\":\"set_enable\",\"type\":\"widget\",\"widget\":\"button2\",\"enable\":true}>ET"));
            Serial.println(F("ST<{\"cmd_code\":\"set_enable\",\"type\":\"widget\",\"widget\":\"button1\",\"enable\":true}>ET"));
            
            break;
  }
  if((quan_hang1==3)||(cha_hang1==3))
      {
            Serial.println(F("ST<{\"cmd_code\":\"set_visible\",\"type\":\"widget\",\"widget\":\"gif4\",\"visible\":true}>ET"));
      }
      else if((quan_hang2==3)||(cha_hang2==3))
      {
            Serial.println(F("ST<{\"cmd_code\":\"set_visible\",\"type\":\"widget\",\"widget\":\"gif5\",\"visible\":true}>ET"));
      }
      else if((quan_hang3==3)||(cha_hang3==3))
      {
            Serial.println(F("ST<{\"cmd_code\":\"set_visible\",\"type\":\"widget\",\"widget\":\"gif6\",\"visible\":true}>ET"));
      }
      else if((quan_lie1==3)||(cha_lie1==3))
      {
            Serial.println(F("ST<{\"cmd_code\":\"set_visible\",\"type\":\"widget\",\"widget\":\"gif7\",\"visible\":true}>ET"));
      }
      else if((quan_lie2==3)||(cha_lie2==3))
      {
            Serial.println(F("ST<{\"cmd_code\":\"set_visible\",\"type\":\"widget\",\"widget\":\"gif8\",\"visible\":true}>ET"));
      }
      else if((quan_lie3==3)||(cha_lie3==3))
      {
            Serial.println(F("ST<{\"cmd_code\":\"set_visible\",\"type\":\"widget\",\"widget\":\"gif9\",\"visible\":true}>ET"));
      }
      else if((quan_zuoxia==3)||(cha_zuoxia==3))
      {
            Serial.println(F("ST<{\"cmd_code\":\"set_visible\",\"type\":\"widget\",\"widget\":\"gif11\",\"visible\":true}>ET"));
      }
      else if((quan_youxia==3)||(cha_youxia==3))
      {
            Serial.println(F("ST<{\"cmd_code\":\"set_visible\",\"type\":\"widget\",\"widget\":\"gif10\",\"visible\":true}>ET"));
      }
  }
}

A demo video of the project will be attached here.

https://www.youtube.com/watch?v=inMMf5RX6Xs

2 Likes

My Man, this looks amazing!

I replied to your last post via phone and had no idea this was the display you had in mind. Still replying from the phone so I can’t look into the code, but the video-demo looks awesome! Good job! I really hope you got familiar with the hardware by communicating the touches and actually drawing things.

I have one issue with your System Principle though: X Should go first, not O. :stuck_out_tongue:

I do have a question about the display: Does it have internal memory that you write to that does the “design” and drawing? I can see the GUI Design being done inside “Stone Designer”, so does the communication with Arduino occur between Display and Arduino directly, or are you sending data to PC and then from PC to the display?

1 Like

Oh yes, thank you for the reminder. I checked the rules of Tic Tac Toe again and found that indeed the first step should be x. This just needs a code change.

Regarding the display, according to my research and their datasheet, it has storage for the GUI design and the display communicates directly with the Arduino through the serial port.

1 Like

Excellent. Good to know that you have made it work. I have heard about Stone LCDs, but not used them yet. I can’t find any device library in your code. How you made the display and touch work without any device driver?

When using the serial tool, you can see that when the screen is pressed it returns a string of hexadecimal data, so I think the Arduino reads these hexadecimal data, and the library that comes with the Arduino can directly use serial.read( ) to read these data.
For example:

ST<0x10 0x01 0x00 0x08 button9 0x01>ET
Hexadecimal data: 53 54 3C 10 01 00 08 62 75 74 74 6F 6E 39 01 3E 45 54 E7 E0 
1 Like

Thanks. How good is the display? Is it worth buying??

I think the Stone’s screen is worth getting, but everyone has their own standards and I don’t know if you’ll think it’s worth it.

I had bought other LCDs, compared to other displays, Stone’s display has high processing performance. The new product I bought has 32-bit color, which is rich in color; the memory is large, 256M can be expanded to 1G or 2G; it also comes with GUI design software that I feel very good to use. Many LCDs are dot matrix fonts, they use vector fonts, and they do not lose frames when zooming in or out.

Another thing that I think is more convenient is that it has multiple interfaces, such as RS232, RS485, TTL, and RS422, which is a great benefit for people who use multiple microcontrollers. In addition, it can download the GUI directly from the computer to the board via data cable or USB flash drive. Many LCDs need to go through the SD card, and I’m not a meticulous person, so I often can not find the SD card.

When you use it, you will find its benefits and will not switch to another LCD.
It’s easy to develop and even an amateur like me can easily use it after learning it.

2 Likes

Thank you. I will get one and try it out.

Excellent work. Thanks for sharing the code.