Interfacing 128 X 64 LCD Module with Arduino (2/3): Snake Game With Push Button Switches

Overview: 

In our first tutorial about 128 X 64 LCD module, we used a 10k potentiometer to adjust its contrast, displayed text, and even flashed our favorite cartoon character images.

In this tutorial, we will be adding tactile push button switches to our project so we can play the iconic and classic SNAKE GAME  that many 90's kids enjoyed. This tutorial shows the versatility of the 128 X 64 LCD module. Yes! It is used in many devices to display data and controls, but it can also be used in recreational activities.

 

Hardware:

Arduino Uno x 1



128 x 64 Graphical LCD x 1


Tactile Push Button x 5

10k Resistors x 1

10k Potentiometer x 1


Breadboard x1

Connecting wires

 

Software: 

Arduino IDE

 

Application Discussion:

In the first project, we have used a potentiometer where a knob is turned clockwise or anti-clockwise, and the LCD’s contrast changed. For our second tutorial, we're going to take advantage of the size of the ST7920 128X64 GLCD by playing one of the classic 90s childhood games, a basic SNAKE GAME.

We will use five tactile push button switches, the first four buttons will be used to control the movement of the snake: UP, DOWN, LEFT, RIGHT. The remaining one will be used to reset the game once you have touched the four edges of the screen or the snake itself.

 

Tactile Push Button Switch

Tactile push button essentially completes an electric circuit once you press or click on it. These are usually built as metal or thermoplastic.

When it's on, a small metal spring inside makes contact with two wires, allowing electricity to flow in the system.

There are types of push button switches, namely momentary and non-momentary.

Momentary switches only work as long as you push them, like buttons on phone, keyboard, or buzzer.

Non-momentary switches take one push to turn on, another to turn off like on/off button from tv remote control or from your cellphones. They kind of latch from the previous state. 

If you want to learn more applications of the push button, click here!

 

ST7920 128X64 GLCD

128 x 64 LCD is a display device that can be used in embedded systems for displaying data, image, custom characters and even play games!

There are 20 pins in the 128 X 64 GLCD. Here are the following symbol and description with its function.

Symbol

Description

Function

VSS

Ground

0V

VDD

Power Supply for Logic Circuit

+5V

VO

LCD Contrast

Adjustment

Contrast Control

RS

Instruction/Data

Register Selection

RS = 0: Instruction Register

RS = 1:  Data Register

R/W

Read/Write Selection

R/W = 0: Write

R/W = 0: Read

E

Enable Signal

 

DB0–DB7

Data Input/output Lines

8 – Bit

CS1

Chip (Seg. Driver) Selection

CS1 = 1: Select Chip1

CS2

Chip (Seg. Driver) Selection

CS2 = 1: Select Chip2

RST

Reset Signal

RST = 0: Display OFF,

Display from Line 0

VEE

Negative Voltage for LCD Driving

-10 V

LED+

Supply Voltage forLed+

+5V

LED-

Supply Voltage for Led-

0V

 

If you want to make a project by using this type of LCD you can purchase it at CreateLabz Store, where you can choose from 2 available colors: GREEN AND BLUE.

 

Hardware Set-up:

 

The first two buttons on the left are to move the snake from the left and right, while the other two buttons are for up and down. Once the snake has touched the borders or itself, the button below the 128x 64 LCD is for resetting the game..

 

Software Set-up:

Open your Arduino IDE and upload this code to a new sketch.
You can copy the Arduino code found on our Github here.

There are quick explanation in every segment of the code. We have also used this library by Olikarus. This is primarily used in most projects involving the 128 x 64 LCD.

U8G is a graphics library for monochrome displays. we also have other enhanced libraries like the U8G2, but for this project we will be only using the U8G.
#include "U8glib.h"
The line below is for setting up the used GLCD pins.
Pin 13 is for enable,
Pin 11 is for the Read/Write
Pin 10 is for the Data or Instruction. 
U8GLIB_ST7920_128X64 u8g(13, 11, 10);
Here are the connections of each button to the Arduino:
4 pins for 4 buttons, the reset button can
be easily be connected to the RST on the Arduino.
const int BLEFT = 2; 
const int BUP = 3;
const int BDOWN = 4;
const int BRIGHT = 5;
Setting the food and snake, this means that the food 
is 6x6 in size all through out the game. you can make it 
larger or smaller depending on your preference.
The difference between int and const int is that int is read/write
while const int is read-only.
int foodX = 6; 
int foodY= 6;
int maxSnakeLength = 200;
int snakeLength = 6;
int snakeX[maxSnakeLength];
int snakeY[maxSnakeLength];

Strings are used to store text. They can be used to display text on an LCD
or in the Arduino IDE serial monitor window.
String command; 
String Createlabz;
String cons;
bool have two values, true or false.
in this case, all the buttons are false, false is defined as zero
meaning when the system is on, all buttons have to be pressed so
it will work according to their designated directions.
bool MLEFT = false; 
bool MRIGHT = false;
bool MUP = false;
bool MDOWN = false; bool Start = false;
bool Stop = false;
bool arduinoControl = true;
u8g.firstPage sets the text you wanted to display.
u8g.nextPage basically moves into another text display.
clearLCD rebuild the picture after some delay.
randomSeed initializes a pseudo-random number generator, which causes it to start at an arbitrary point in its random sequence.
analogRead reads the value from the specified analog pin. 
void setup() {
Serial.begin(115200);
Serial.println("Snake");
pinMode(BLEFT, INPUT);
pinMode(BUP, INPUT);
pinMode(BDOWN, INPUT);
pinMode(BRIGHT, INPUT);

u8g.firstPage();
do { first();
}
while( u8g.nextPage() );

delay(2000);
clearlcd();
u8g.firstPage();

do { second();
}
while( u8g.nextPage() );
delay(2000);
clearlcd();

randomSeed(analogRead(0));
snakeX[0] = 20;
snakeY[0] = 20;
drawSnake();
drawFood();
}
void first() and void second() functions will be the first thing
that you will see once the game is running. It will display the
"CreateLabz Tutorials" and "Classic Snake Game" Texts.
u8g.setFont  is to set the font of the text which is included in the library.
u8g.drawStr is to set characters or text on the LCD.
void first() 
{ u8g.setFont(u8g_font_unifont);
u8g.drawStr( 20, 35, "CreateLabz");
u8g.drawStr( 17, 52, "Tutorials"); }
void second()
{ u8g.setFont(u8g_font_unifont);
u8g.drawStr( 12, 15, "C L A S S I C");
u8g.drawStr( 25, 35, "S N A K E");
u8g.drawStr( 30, 55, "G A M E"); }
void clearlcd(){ u8g.firstPage();
do { }
while( u8g.nextPage() );
}
Next void Control() is for controlling the snake direction and synchronizing it to the buttons. The -1 and +1 is for the direction of the snake, for example
snakeX[0] = snakeX[0] - 1 will turn to the negative side
of the x-axis which is going to the LEFT.
snakeY[0] = snakeY[0] +1 will turn to the positive side
of the y-axis which is going UP.
void Control()
{ for(int i = snakeLength; i > 0; i--)
{ snakeX[i] = snakeX[i-1];
snakeY[i] = snakeY[i-1];
}

if (MLEFT == true)
{ snakeX[0] = snakeX[0] - 1;
}

else if (MUP == true)
{ snakeY[0] = snakeY[0] + 1;
}

else if (MDOWN == true)
{ snakeY[0] = snakeY[0] - 1;
}

else if (MRIGHT == true)
{ snakeX[0] = snakeX[0] + 1;
}
}

bool IsSnake(int x, int y)

{ for (int i = 0; i < snakeLength - 1; i++)
{ if ((x == snakeX[i]) && (y == snakeY[i]))
{ return true;
}
else { return false; }
}
}
Once the buttons are pressed (either of the four) the
snake will turn or move in its designated movement with the
delay of 2 milliseconds. 
We use two or more if statements since multiple if statement conditions could be true at the same time.
void Buttons() 
{ if (arduinoControl == true)
{ if ((digitalRead(BLEFT)) == HIGH && MRIGHT != true && MLEFT != true)
{ delay(200);
if ((digitalRead(BLEFT)) == LOW) {
MLEFT = true;
MUP = false;
MDOWN = false;
MRIGHT = false;
Serial.println("Left");
}
}
if ((digitalRead(BUP)) == HIGH && MDOWN != true && MUP != true) {
delay(200);
if ((digitalRead(BUP)) == LOW)
{ MLEFT = false;
MUP = true;
MDOWN = false;
MRIGHT = false;
Serial.println("Up");
}
} if ((digitalRead(BDOWN)) == HIGH && MUP != true && MDOWN != true)
{ delay(200); if ((digitalRead(BDOWN)) == LOW)
{ MLEFT = false;
MUP = false;
MDOWN = true;
MRIGHT = false;
Serial.println("Down"); } }

if ((digitalRead(BRIGHT)) == HIGH && MLEFT != true && MRIGHT != true) {
delay(200); if ((digitalRead(BRIGHT)) == LOW)
{MLEFT = false;
MUP = false;
MDOWN = false;
MRIGHT = true;
Serial.println("Right"); } } } }
In the function void DrawSnake(), the initial snake size is the same as the food size (6x6).
The for loop statement indicates that the more food the snake eats, the longer it gets.
void DrawSnake() 
{ for (int i = 0; i < snakeLength; i++)
{ u8g.drawBox(snakeX[i], snakeY[i], 6, 6);
} void DrawFood()
{ if (OnScreen(foodX, foodY)
)
{ u8g.drawBox(foodX, foodY);
}
} bool OnScreen(int x, int y)

{ if (x >= 0 && x < 128 && y >= 0 && y < 64)
{ return true; }
else
{ return false; }
}
void GiveFood() would randomly place another 'food' on the screen.
128 and 64 have been subtracted by 6 so that the 6x6 'food'
can be fully seen on the screen.
random function generates pseudo-random numbers.
void GiveFood() {
foodX = random(6, 122); 
foodY = random(6, 58);
}

void Eat() {
if (snakeX[0] == foodX && snakeY[0] == foodY)
{ if(snakeLength < maxSnakeLength)
{ snakeLength++;
u8g.drawBox(snakeX[0], snakeY[0], 6, 6);
}
return true; }
else {
return false;
}
}
Once the snake touches the screen borders, the void TouchedItSelf() function will be called and the game will restart once the restart button is pressed.
void Dead() will be called once void TouchedItSelf() conditions
were satisfied, it will not go back to the void first() and void second()
but rather it will tell you if you are ready to play again. 
The loop() will start right after the initial Text displays at bootup. If the snake has eaten the 'Food', GiveFood() will be called, together with the Control() and Buttons() functions. If not, only the Buttons() and Control() are active. If the snake has touched itself or the borders, the TouchedItSelf() will be called while
the Dead() will ask if you are ready to play again.
void loop() {

if (OnScreen(snakeX[0], snakeY[0])){
drawSnake();
drawFood();
if (Eat()) {
GiveFood();
Buttons();
Control();
} else {
Buttons();
Control();
} if (OnScreen(snakeX[0], snakeY[0]))
{ TouchedItSelf(); u8g.firstPage();
do {
drawSnake();
drawFood();
} 
while (
u8g.nextPage() );
}
else {
Dead();
}
}

For visual explanation about the system, you can refer to this flow chart.

Output: 

Upon uploading the code in your Arduino, you will be welcomed by three texts and the game will start once you have pressed any of the four buttons.

 

 

Conclusion:

GLCDs are very versatile, from displaying data and control, to even play games for fun. Stay tuned for the next tutorial as we are going to use a sensor to view its data.

 

Reference: 

16*2 LCD Tester - Snake (My 1st Arduino Project) : 4 Steps - Instructables

 




128x64GamesGlcdPotentiometerPush buttonSnake gameSt7920Tact switchTactile push button switch

Leave a comment

All comments are moderated before being published