Home » Arduino

Category Archives: Arduino

Connect Four Game with Arduino

Remote Controlled Connect Four Game

 

1. Images and Video

2. Project Aims

People have been playing board games for a long time. Nowadays many of them are transferred on computers, smartphones and tablets. But the experience of a digital game differs from their physical equivalents. Playing on an actual physical board with moving objects gives different more natural interaction than using controller and watching a 2D screen. Connect 4 is a popular board game made from 7 columns and 6 rows. Players take turns dropping their coloured disks into columns until one of the players gets 4 in a row-horizontally, vertically or diagonally. The goal of this project is to build two Connect 4 boards that will use sensors, motors and microcontrollers to detect user input, process it and send it to the other board. The system will also keep track of whose turn it is check for win, lose or draw case and do remote players moves automatically.

3. System Design

4. Hardware Design and Implementation

4.1 Microcontroller

   Central component to the system is the Microcontroller. It will take readings from sensors process it and control output devices. Microcontrollers are self-contained systems with a processor, memory and peripherals. Arduino Uno Development board was chosen for this project because it provides cheap and easy way to control external devices. It has 14 digital input/output pins, 6 analogue inputs, it can control external shield that will allow it to connect to the internet.

In order to connect to the internet an Ethernet Shield will be used.

4.2 Sensors

Sensors will be used as an input device to the system to detect if a disk is dropped in one of the columns. There are many varieties of sensors that can detect moving objects.
Ultrasonic sensors send a pulse that bounces off an object and measures the time it takes for the pulse to come back to the sensor. These sensors are great for measuring distance to remote object.
Capacitive proximity sensors can measure proximity to non-metallic objects.
Proximity sensors use infrared emitter and receiver to calculate distance by detecting light reflected by an object.
Photo interrupters are similar to the proximity sensor. They use infrared emitter and receiver but placed opposite each other and detect if an object passes in between.

Considering all options the TCRT5000 proximity sensor was a good choice for detecting if a disk is dropped in one of the columns because its relatively cheap and works well in detecting close objects. It includes one infrared emitter and phototransistor in a leaded package which blocks visible light. It can detect reflected light from close distance.

4.3 Multiplexer

More Analogue IO pins are needed than the provided from the Arduino board. One way of expanding the IO is by using a multiplexer. A multiplexer is a device that selects one of several analogue or digital inputs and forwards it to a single line. The 4051 family is a popular multiplexer/demultiplexer that can work with analogue values. It is not possible to read from more than one input at the same time but going through the pins one by one is quite fast.

The 74HC4051 has eight analogue inputs/outputs (Y0 to Y7) and three digital select inputs (S0 to S2), an active-LOW enable input (E), and a common input/output (Z).
VCC and GND are the supply voltage pins for the
digital control inputs (S0 to S2, and E).
S0, S1 and S2 select the pin to read/write from. These pins are connected to digital out pins on the Arduino. Every pin is representing a number S0 = 1; S1 = 2; S2 = 4) and if one of these Select pins is set to HIGH, the number the pin is representing will be transmitted to the 4051. For example:
If S0 and S2 are HIGH and S1 is LOW pin y5 is selected (1+0+4 = 5).
If all pins are HIGH pin y7 is selected (1+2+4 = 7).

4.4 Stepper Motor

Stepper motor is required to provide precise linear motion mechanism that delivers disks to the right column.
Stepper motors are used when motion and position has to be controlled precisely. They rotate a specific number of degrees controlled by pulses supplied on the stator windings. There are two basic types of stepper motors: variable reluctance and permanent magnet. Both are similar except that the permanent magnet stepper has permanent rotor poles and thus keeps the rotor in place when there is no current flowing. Furthermore depending on the winding arrangements steppers can be unipolar or bipolar. A bipolar motor has positive and negative polarities while the unipolar stepper motor can only operate with positive voltage. A unipolar stepper requires extra wire connected in the middle of each winding in order to produce opposite polarities. Driving bipolar stepper is more complicated because it requires bipolar voltage supply. That’s why a unipolar motor will be used.
The 28BYJ-48 Stepper Motor produces good torque for its size. It is widely used and that makes it very cheap. It has five wires and two coils divided by centre connections on each coil.

The ULN2003A driver board will be used to amplify the signal from the Arduino. It contains seven Darlington array pairs with common emitters. Each channel rated at 500mA and can withstand peak currents of 600mA.


The figure below shows how to connect the stepper. Inputs one to four of ULN2003A are connected to Arduino digital pins. External supply is used for stability and is grounded through the Arduino GND.

A separate 5 V power supply is used, as the motor may drain more current and damage the microcontroller. For controlling the stepper, voltage must be applied to each of the coils in a specific sequence. It can be controlled with 4 and 8 steps. Using 8 steps is slower but gives more torque. The table below shows the sequence to rotate the stepper in the clockwise direction using 8 steps.

4.5 Servo

Servo is needed to deliver a disk to the column. Servo is a motor that can rotate 90 degrees in each direction. Choosing the right servo for an entire system to perform as designed is based on the required torque, speed, size and accuracy.
The SG90 was chosen because it’s small, light servo with high output power.

The final system that will deliver disks will consist of 1 stepper, 1 servo, gear rack and gear, pipe that holds the disks and funnel on which the disks will slide into the column.
LEDs will be used as a feedback to indicate player turns, who won and when the game ends in a draw.

5. Circuit Design

The figure below shows the final circuit design of all hardware components discussed.

6. Software

The game play loop is depicted in the figure below. It broadly follows six steps. The first player makes a move on his Connect Four set, which is read by the Arduino. The Arduino transmits this move to the remote player’s machine, where the remote player’s machine completes the first player’s move on the remote player’s game set. In doing so, the Arduino maintains an internal “state of the game” on both machines (and on a web server). In response, the remote player makes his move on his game set, which is similarly completed by the first player’s Arduino on the first player’s machine.

This Sketch makes use of the Ethernet library, SPI library and Servo library. At start all global variables and the 2D array will be reset to 0. After that the shield must be assigned MAC address and IP address using the Ethernet.begin() function.

byte mac[] = { 2xAB, 1xF1, 0xAE, 0x9E, 0x4E, 0x21 };
byte ip[] = { 192, 168, 0, 15 };

DNS server and Default Gateway are used to connect to web pages outside the local network.

byte dns_server[] = { 192, 168, 0, 2 };
byte gateway[] = { 255, 255, 255, 0 };

Ethernet begin will initialize the Ethernet library.

Ethernet.begin(mac, ip, dns_server, gateway);

Reading the Sensors

for (y=0; y<=6; y++) {
// select the bit
s0 = bitRead(y,0);
s1 = bitRead(y,1);
s2 = bitRead(y,2);
digitalWrite(7, s0);
digitalWrite(8, s1);
digitalWrite(9, s2);
// read analog pin 0:
sensorValue = analogRead(A0);
delay(10); // delay in between reads

}

A for loop is counting from 0 to 6. bitRead selects the three least significant bits from the integer y and store them into s0, s1 and s2. For example if y is 3(…00011 in binary), s0 is set to 1, s1 is set to 1 and s2 is set to 0. Then they are sent through pins 7, 8, and 9 to the select pins of the multiplexer and the the value is stored in variable sensorValue. The delay is set to 10 ms and each sensor is read 14 times a second.

Check for Input

void checkForInput(){
if (sensorValue < 500){ //check if disk dropped
while (sensorValue <700){ //check if the disk had passed through the sensor
sensorValue = analogRead(A0);}
storeInArray();
win = checkForWin();
boardIsFull();
sendData(); }
}

When idle the value read by the sensor is around 1000 and when there is an object in front of the sensor the value is around 200. This function checks if there is an object in front of the sensor and then keeps reading the sensor until the object had passed – the value goes above 700. This is done to prevent reading the same inputs few times. After the value goes back above 700 the program continues with storing the input, checking if the game is over and sending the data to the other board.

Storing Data

void storeInArray(int column){ //store values in array depending on player
for (int row = 5; row >= 0; row--){
if (board[row][column] == 0){
board[row][column] = playerTurn;
if(playerTurn==1){ //alternate between players
playerTurn=2;}
else if(playerTurn==2){
playerTurn=1;}
break;}
}
}

Transfer Data

This function stores the data in a 2D array. The for loop goes through all rows in the column y starting from the bottom and checks for an empty row indicated by 0. Column y is a global variable that is updated by the for loop in void loop() function. If there is 0 in the row the value is set by playerTurn. If it’s first player turn a 1 is stored then playerTurn is changed to 2 for the next input.

Send data:

if (client.connect(server, 80)) {
 Serial.println("connected");
 // HTTP request:
 client.print( "GET /mysql_connect.php?");
 client.print("countMove=");
 client.print(countMove);
 client.print("&&");
 client.print("column=");
 client.print(y);
 client.println( " HTTP/1.1");
 client.println( "Host: 192.168.0.2" );
 client.println( "Content-Type: application/x-www-form-urlencoded" );
 client.println( "Connection: close" );
 client.println(); }
else {
 // if didn't connect to the server:
 Serial.println("connection failed");

}

This function sends HTTP GET request to mysql_connect.php with the variables countMove and y(column) that will be stored in a database and displayed on displayData.php.

This is what is sent:
http://192.168.0.2/mysql_connect.php?countMove=countMove&column=y
Everything before the question mark is the address of the web server. The remaining data is the two variables and their values after the equal signs.

Receive data:

if (client.connect(server, 80)) {
Serial.print("connected... ");
// Make a HTTP request:
 client.println("GET /displayData.php?");
 client.println( " HTTP/1.1");
 client.println( "Host: 192.168.0.2" );//web server IP
 client.println( "Content-Type: application/x-www-form-urlencoded" );
 client.println( "Connection: close" );
 client.println(); }
else {
 Serial.println("connection failed"); }
if (client.connected()) {
if(client.find("</tr><tr><td>")){
 move = client.parseInt();
 if(client.find("</td><td>")){
 column = client.parseInt(); }
}
else
Serial.println("result not found");
client.stop();
delay(1000); // check again in 1 seconds }

Send HTPP GET request to displayData.php. It will read the page as a HTML source code. Then look for specific tag that precedes the value I’m looking for. The top row of the table will be …</tr><tr><td>move</td><td>column…. The client will use the find method to search through the incoming data and it will return True if the searched string is found. First lt will search for “</tr><tr><td>” that precedes the move number, then parseInt() function will return the first integer value after the current position and it will stop at the first character that is not an integer. After that another if statement will search for “</td><td>” that precedes the column value.

Control of stepper motor and servo

After receiving the remote players’ data a function call to autoInput will calculate the number of steps and direction according to current position and the distance it has to move.

void autoInput(int remoteColumn){
  int moveDistance = 0;
  if (currentPosition == remoteColumn){
    dropDisk(); }
  //check direction
  else if(currentPosition < remoteColumn){
    moveDistance = remoteColumn-currentPosition;
    clockwise(moveDistance);
    dropDisk(); }
  else if(currentPosition > remoteColumn){
    moveDistance = currentPosition-remoteColumn;
    anticlockwise(moveDistance);
    dropDisk(); }
  else{
    Serial.println("wrong remoteColumn"); 
 }
  currentPosition=remoteColumn; //update current position
}

 

The sequence controlling the motor is stored in constant variable stepSequance[8] = {B1000, B1100, B0100, B0110, B0010, B0011, B0001, B1001};

This particular motor has Stride Angle of 5.625 and is geared down by factor of 64. This gives (360/5.625*64)/8=512 steps per revolution. The gear used has diameter of 15 mm and it will move 47.16 mm in one revolution or 1 mm in 10.8567 steps. Distance between two adjacent columns is 35 mm. That gives 35*10.8567= 380 steps between two neighbouring columns.

void clockwise(int moveDistance){
  //move in the clockwise direction
  for(int i = 0; i < moveDistance*380; i++){
    for(int j = 7; j >= 0; j--){
      setDriverIn(j);
      delay(1); }
  }
}
void anticlockwise(int moveDistance){
  //move in the anticlockwise direction
  for(int i = 0; i < moveDistance*380; i++){
    for(int j = 0; j < 8; j++){
      setDriverIn(j);
      delay(1); }
  }
}
void setDriverIn(int i){
  //send step sequence to stepper
  digitalWrite(2, bitRead(stepSequance[i], 0));
  digitalWrite(3, bitRead(stepSequance[i], 1));
  digitalWrite(5, bitRead(stepSequance[i], 2));
  digitalWrite(6, bitRead(stepSequance[i], 3));
}

Next function rotates the Servo and pushes one disk into the column.

void dropDisk(){
  //drop disck areturn to initial position
  servoDrop.write(180); // turn servo to 90 degrees
  delay(500); // wait half a second
  servoDrop.write(90); // return servo to initial position
  delay(500); // wait half a second
}

Check for Win or Draw

   Horizontal check

for (int i = 0; i < 6; i++){ //horizontal check
  for (int j = 0; j < 4; j++){
    if((board[i][j] == 1) && (board[i][j+1] == 1) && (board[i][j+2] == 1) && (board[i][j+3] == 1)){           return player1;
       break; }
       else if((board[i][j] == 2) && (board[i][j+1] == 2) && (board[i][j+2] == 2) && (board[i][j+3] == 2)){
       return player2;
       break; }
  }
}

This loop checks for horizontal win. The outer loop selects the row and the inner loop checks for four consecutive 1’s or four 2’s in that row. If true return who won and exit the loop.

   Vertical check

for (int k=0; k<6; k++){ //vertical check
  for (int l=0; l<3; l++){
    if((board[l][k] == 1) && (board[l+1][k] == 1) && (board[l+2][k] == 1) && (board[l+3][k] == 1)){   
      return player1;
      break; }
      else if((board[l][k] == 2) && (board[l+1][k] == 2) && (board[l+2][k] == 2) && (board[l+3][k] == 2)){
      return player2;
      break; }
  }
}

This loop checks for vertical win. In this case the outer loop selects the column and the inner loop checks for four consecutive 1’s or four 2’s in that column.

Diagonal check in the NW direction

for (int m=0; m < 3; m++){ //diagonal win "\"

  for (int n=0; n < 4; n++){

    if((board[m][n] == 1) && (board[m+1][n+1] == 1) && (board[m+2][n+2] == 1) && (board[m+3][n+3] == 1)){

      return player1;
      break; }
    else if((board[m][n] == 2) && (board[m+1][n+1] == 2) && (board[m+2][n+2] == 2) && (board[m+3][n+3] == 2)){
      return player2;
      break; }
  }
}

This loop checks for diagonal win in the” \” direction. In this case the outer loop selects the row and the inner loop selects the column. Starting from the top left corner both the row and column are incremented by 1 three times. The loop checks all possible combinations in the “\” direction. The tables below show all cells the loop goes through.

 Diagonal check in the NE direction

for (int o=0; o<3; o++){ //diagonal check "/"

  for (int p=3; p<7; p++){

    if((board[o][p] == 1) && (board[o+1][p-1] == 1) && (board[o+2][p-2] == 1) && (board[o+3][p-3] == 1)){

      return player1;
      break; }
    else if((board[o][p] == 2) && (board[o+1][p-1] == 2) && (board[o+2][p-2] == 2) && (board[o+3][p-3] == 2)){
      return player2;
      break; }
  }
}

In the same way as “\” direction but this time the inner loop is going from columns 3 to 6 and decrementing the column index while incrementing the rows.

Check for Draw

void boardIsFull(){
  countMoves++;
  if (countMoves > 42){
    endDraw(); }
  }

void endDraw(){
  //indicate that the game ended in a draw
  Serial.println("Board is full"); //used for testing change it to indicate with led that the game ended in draw and stop the game
}

This function keeps track of the inputs. Every time there is an input the counter is incremented by 1 and when it reaches 42 then the board is full and no one won the game.

6.1 Web Server

The Ethernet shield can run a server on itself. The first setup tested was one of the Arduino boards acting as a web server and the other as a client and that worked fine. But after combining both sketches so that both boards act as a server and as a client the data didn’t update properly, because the Arduino can’t do two things at once. It had to disconnect the server run the rest of the code, then connects as a client, then disconnect the client and connect as a server again in a loop. One way to overcome this problem was to use a web server on external machine. There are two pages one that receives data from the Arduino and stores it in a database and another that displays the data from the database.

PHP MYSQL

The function to connect to MySQL database is called mysql_connect. It returns a pointer to the database connection. The correct host, username, password and database name have to be provided to establish connection. After connecting @mysql_select_db will selects arduino_db. The php script below shows how to connect to arduino_db get values from the web page and store them in members move and columns of the ard_db table.

Connect to database

<?php
$db_host = "localhost";
$db_username = "root";
$db_pass = "";
$db_name = "arduino_db";

$con = @mysql_connect("$db_host" , "$db_username" , "$db_pass") or die ("could not connect to mysql");
@mysql_select_db("$db_name") or die ("no database");


$move = $_GET['column'];
$count = $_GET['countMove'];


$sql = "INSERT INTO ard_DB (move, columns) VALUES ('$move', '$count')";
mysql_query($sql, $con);
mysql_close($con);
?>

Then another php script will extract the data from ard_db and display it on displayData.php. The script below show how this is done. First connect to the database, and then $sql = “SELECT * FROM ard_db” will select all data from table ard_db. Next line will store it into a variable $myData. After that a while loop will fetch the data and display it in a table.

Displaying the data
</head>
<body>
<?php
$con = @mysql_connect("$db_host" , "$db_username" , "$db_pass") or die ("could not connect to mysql");
@mysql_select_db("$db_name") or die ("no database");

$sql = "SELECT * FROM ard_db";
$myData = mysql_query($sql, $con);
echo "<table border=1>
<tr> <th>Column</th> <th>Move</th> </tr>";


while ($record = mysql_fetch_array($myData)){
echo"<tr>";
echo "<td>" . $record['move'] . "</td>";
echo "<td>" . $record['columns'] . "</td>";
echo "</tr>"; }


echo "</table>";
mysql_close($con);
?>

 

The complete codes for controlling the Arduino and the two web pages are available at GitHub

 

7. Further development

  • adding wireless communication
  • checking if the rules are followed
  • storing scores

 

 

Whac-A-Button With Arduino

Whac-A-Mole like game with Arduino and Arcade style LED buttons.

This is a very simple version of the Whac-a-mole game, where a button lights up and waits for the player to hit it. If the correct button is hit the score is updated and a new button lights up. The player is not punished if they hit the wrong button. Only one button lights up at a time. Time to hit the button reduces each game cycle.

arduino-whac-a-button

Kit includes:
5 LED buttons
All required wires, screws and nuts
Arduino nano
Laser cut acrylic panels
4 digit 7 Segment display TM1637
USB cable

 

Assembly

Start by adding the display and buttons. Make sure the display pins are pointing inwards, the colour arrangement of the buttons is up to you.

arduino-whac-a-button-assembly

Use 2 screws to secure the display in place.

Keep all buttons in the same orientation – it will make wiring easier.

Wiring might look messy but it’s very simple.

Connect all grounds together using the daisy chain 2.8mm crimp connectors. Again if all buttons are in the same orientation it will be much easier. The end with a jumper wire connect to the Arduino GND.

arduino whac-a-mole-wiring

Now connect the rest of the pins as shown in the images below:

Connect the display.

Display –  Arduino

CLK    –   Pin 8

DIO     –   Pin 7

GND    –  GND

5V        –  5V

Arduino TM1637 display

Use jumper wires to connect all LEDs to the Arduino pins.

LED1 – Pin9

LED2 – Pin10

LED3 – Pin11

LED4 – Pin12

LED5 – Pin13

Now use jumper wires to connect all buttons to the Arduino pins. Make sure that if you’ve used for example the green button for LED1 you’ll have to use it as Button1 as well.

Button1 – Pin2

Button2 – Pin3

Button3 – Pin4

Button4 – Pin5

Button5 – Pin6

Tape the wires together to keep them from disconnecting.

Once everything is connected test if it works before assembling the panels.

Code

Download the code from GitHub – Whack-a-button and upload it to the Arduino.

At start the game will be in waiting for input where all LEDs will be flashing until one of the buttons is pressed and that’s when the game will start. After the game ends it will return to the waiting for input state while still showing the latest score and it will stay like that until a button is pressed and new game starts.

After you’ve checked that everything is connected correctly assemble the rest of the panels.

Leave the right panel last as that’s where the usb cable will be coming out.

 

Enjoy your play.

 

Buy Arduino Whac-A-Button Kitarduino-whac-a-button

Using the 8×8 64 RGB LED Matrix With Arduino

64 RGB LED Matrix

 

Buy 8×8 64 LED Matrix WS2812 LED

 

 

 

 

 

 

The WS2812 Integrated Light Source is a full-color LED. Red, green and blue LEDs are integrated alongside a driver chip into a surface-mount package controlled through a single wire. This panel has 64 bright RGB LEDs , arranged in an 8×8 matrix, each pixel is individually addressable. Only one microcontroller pin is required to control all the LEDs, and you get 24 bit color for each LED.

 

Wiring up

There are two 3-pin connection ports – one input and one output to the next panel. Provide 5VDC to the +5V pin and ground to GND pin, then connect the DIN pin to your Arduino. You’ll also need to make a common ground from the 5V power supply to the Arduino. Since each LED can draw as much as 60mA use at least 5V 2A power supply.
You can chain these together. Connect the DIN of the second panel to the first panel’s DOUT. Also connect a ground pin together and power with 5V. You can chain as many as you’d like, you will need a 5V 10A power supply for chaining 4 of these!

Libraries

Using the Adafruit Library

Install Adafruit_NeoPixel via Library Manager

From the Sketch menu – Include Library – Manage Libraries and search for NeoPixel, then click on the Install button. After it’s installed, you can click the close button.

Install NeoPixel Library

Open the strandtest example

Launch the Arduino IDE. From the File menu, select Sketchbook – Libraries – Adafruit_NeoPixel – strandtest

NeoPixel Example

NeoPixel Code Explained

The first line assigns the Arduino pin connected to DIN.

The last line declares a NeoPixel object with three parameters:
1. The number of Pixels in the strip. In the example this is set to 64, change this to match the actual number you’re using.
2. The pin number to which the Matrix is connected.
3. A value indicating the type of Pixels that are connected.

Using the FastLED library

Install the FastLED via Library Manager

From the Sketch menu – Include Library – Manage Libraries and search for FastLED, then click on the Install button. After it’s installed, you can click the close button.

Open the DemoReel100 example and make sure the following lines are set as shown below.

#define DATA_PIN 3     –  the Arduino pin connected to DIN
#define NUM_LEDS 64 – Number of Pixels in this case 64

 

Troubleshooting!

Check your connections. The most common mistake is connecting to the output end of a strip rather than the input – this will light up all leds. Reversing 5V and GND will burn the microcontroller. If only few rows are working check that you’ve set he right number of pixels(64) or rows/columns 8,8 depending on the library you are using. Make sure you are connecting to the pin set in #define PIN.

Other projects – Word Clock

8 Channel Logic Level Bi-directional Converter Module TXS0108E 3v3 5v

Using the 8 Channel Logic Level Bi-directional Converter TXS0108E

Because some controllers, displays and sensors work on 5V while others work on 3.3V, many makers find that they need to perform level shifting to protect the 3.3V device from 5V.

The simplest and most common method of logic level shifting is a voltage divider but it’s not good for high speed transfers and it only works in one direction. That’s where this chip comes in. It can perform bidirectional level shifting and will auto-detect the direction.

This 8-bit noninverting translator uses two separate configurable power-supply rails. The A port is designed to track VCCA. VCCA accepts any supply voltage from 1.2 V to 3.6 V. The B port is designed to track VCCB. VCCB accepts any supply voltage from 1.65 V to 5.5 V. This allows for universal low-voltage bidirectional translation between any of the 1.2-V 1.5-V, 1.8-V, 2.5-V, 3.3-V, and 5-V voltage nodes. VCCA should not exceed VCCB.  When the output-enable (OE) input is low, all outputs are placed in the high-impedance state. It’s s designed so that the OE input circuit   is supplied by VCCA. To ensure the high-impedance state during power-up or power-down, OE should be tied to GND through a pulldown resistor; the minimum value of the resistor is determined by the current-sourcing capability of the driver.

1.2 V to 3.6 V on A Port and 1.65 V to 5.5 V on B Port (VCCA ≤ VCCB)

Logic Level Converter Module TXS0108E

Buy 8 Channel Logic Level Converter TXS0108E

Converting from 5V to 3.3V

logic-level-converter-example

  • VA connects to Arduino 3.3V power supply
  • VB connects to Arduino 5V power supply
  • GND connected to the two power supply grounds
  • When Bx has TTL 5V input, Ax will get TTL 3.3V output
  • Connect OE to 5V

 

 

Using 1.8 Inch TFT Display with Arduino

Using 1.8″ TFT Display with Arduino

 

 

1.8-display-arduino-st7745-

 

 

Buy 1.8″ TFT Display 

 

 

 

 

 

 

This tutorial is for the 1.8″ ST7735 TFT display. This display is a true TFT, the ST7735R driver can display full 18-bit colour.

Wiring

As the display is driven with 3.3V you will need voltage divider or logic level shifter to control it with Arduino.

Using voltage divider

1.8-display-arduino-st7745-connection-voltage-divider

Using Logic Level Shifter

1.8-display-arduino-st7745-connection-level-shifting