0% found this document useful (0 votes)
15 views47 pages

Annotated Embedded Report

Embedded system : PACMAN Game

Uploaded by

Sharad Patel
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
15 views47 pages

Annotated Embedded Report

Embedded system : PACMAN Game

Uploaded by

Sharad Patel
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 47

UNIVERSITY OF NEW HAVEN

Embedded System - Microcontroller


Project : Pacman 1980 using microcontroller STM32107

Project Made By: GROUP 2


● Priyanka Akkala
● Sharadkumar Patel
● Parishad Ajallooeian
● Uravang Hareshbhai Patel

Guided By:
Prof Francis Pellicano
([email protected])
TA : Bhanu Pratap
([email protected])
Table of Content

1. Description of the Project……………………………………………………………….3


2. Approach to Design and Implementation of the project……………………………..6
3. Flowchart ………………………………………………………………………………...7
4. Explanation of the function of modules……………………………………………….9
a. Configuring TFT Display………………………………………………………..9
b. Joystick Configuration………………………………………………………...10
c. USART 1, USART 2…………………………………………………………..15
d. Timers & Interrupts……….…………………………………………………..23
5. Reporting and analyzing results………………………………………………….…26
6. Conclusion and what you have learned from the project.…………………………27
7. Appendix……………………………………………..…………………………………28
Description of the Project

Project Overview: Pacman Game Implementation

In the culmination of our coursework, we undertook the ambitious task of implementing


the classic Pacman game. This project served as a comprehensive application of the
theoretical concepts covered in our lectures, primarily focusing on joystick interrupts,
timers, and interfacing with a TFT Display.

1. Utilizing the learned principles of GPIO manipulation, develop a function to


enable movement using the Joystick. The Joystick GPIO inputs are connected to
the following:

UP - PD4
LEFT - PD2
RIGHT - PA6
DOWN - PB5
CLICK - PC13

Note that the PCB includes a pulldown resistor on the switch, thus each port bi
must be pulled UP (Active HIGH) to function. To test the success of the joystick,
we will activate LED's on PORTE/H.

When UP is pressed, PE11 and PE15 will turn on.

When DOWN is pressed, PE8 and PE12 will turn on.

When LEFT is pressed, PE13 and PE14 will turn on.

When RIGHT is pressed, PE9 and PE10 will turn on.

When CLICK is pressed, all LEDs will turn on.

2. In this project, we want to learn how to establish a simple asynchronous channel


for communication. UART is one of the most common methods to exchange data
between the MCU and other peripherals. We will use UART to exchange
information between our MCU and another terminal (MikroC Pro for ARM) for
debugging and game monitoring.

We will use USB UART A, which utilizes PA9 and PA10 as TX and RX,
respectively. Description of the program is outlined below.

Objective 1: Draw a flow diagram showing the LOGIC to implement UART as


described below.

Objective 2: Write a program which communicates with the USART terminal


using a baud rate of 56,000. When the user interacts with the Joystick, the MCU
will write to the terminal the ASCII characters “UP Pressed”, “DN Pressed”, “LT
Pressed”, “RT Pressed ”, or “CK Pressed”, depending on which direction was
pressed

Objective 3: The user can write from the terminal to the MCU "P" or "p" to pause
and unpause the game. When the user writes "P" or "p", the MCU will respond
with "Paused" or "Unpaused" to indicate the game status.

Bonus Objective 4: Count the number of times each button has been pressed. If
the user types "Q", the MCU will respond with the following text:

3. In this project, we complete the setup for our main project and prepare for the
final section of making the display. By the end, we will have interrupt based
controls, a game clock, and a game speed variable.

Objective 1: Draw a flow diagram showing the logic to implement the objectives
as described below.
Objective 2: Implement Timer 1 for a 1 second counter. To test this, configure
PORTE as an output which will toggle every second. This timer will be used as
our game’s running clock Display this as a flashing LED on any port. Also, create
a counter variable which will output the amount of seconds since start when the
user types "Q". If you did the bonus assignment, it will display this in addition to
the number of joystick presses.

Objective 3: Configure Timer 3 to trigger at the speed configured from the analog
read on PC0 from part 1 on an interrupt basis. This timer will be used to
implement our game’s variable speed. Display this as a flashing LED on any port.

Objective 4: Rewrite your joystick code to trigger up, down, left, and right, PA6,
PB5, PD2, and PD4 on an interrupt basis.

4. For the final part of our final project, we will combine our work from the first three
parts and finish the game.

Objective 1: Draw wireframe diagrams of each screen for the game. You will
have a home page, a play screen, and a high score screen. You may also add
additional screens if you like.

Objective 2: Create the logic to generate the PACMAN character and move
around the screen. The speed which the character moves should be tied to the
timer which is controlled by the analog input from the previous part. The
movement should be done with interrupts as created in the previous part.

Objective 3: Create the logic to generate the 'bits' which your character can
collide with to increment the score. For undergrads, display the score on
MET1155. For graduates, display the score on the display.

Objective 4: Create the map border and walls which your character cannot pass.

Objective 5: Implement I2C to save a high score to the on board EEPROM. The
score is a two byte number. Enter the score manually through the UART terminal
to test it, and ensure when the power is cycled the value entered returns.

Objective 6: Create the home screen and high score pages, navigatable using
the joystick.

Bonus Objective 7: Implement sound for the character moving and collecting
bits.

Bonus Objective 8: Add enemy characters which can end the game when hit.
They do not need to be animated or have any movement, but they should be
randomly placed around the map.
ororororororororororororororor

1. GPIO for the joystick.


2. UART for debugging / communication with a console.
3. Interrupt controller for joystick modes.
4. Move characters around the display.
5. Generate map with collision detection, collect orbs to gain points, show score.
6. Score is stored on EEPROM using I2C protocol.
7. Control game speed with analog signal using Potentiometer.
8. Implement sound using an on board piezo buzzer.
9. Include enemies randomly moving around the map. You do not need to
implement full logic, I would recommend starting with them randomly choosing a
new direction when they hit a wall. If you have time, you can implement
intelligence to try and find a path to the character.

Approach to Design and Implementation of the project

● Utilizing the learned principles of GPIO manipulation, develop a function to enable


movement using the Joystick.
● UART is used for a simple asynchronous channel for communication. UART is one
of the most common methods to exchange data between the MCU and other
peripherals. We will use UART to exchange information between our MCU and
another terminal (MikroC Pro for ARM) for debugging and game monitoring.
● Implement the TIMER for the second counter. It is used as our game’s running
clock display as the flashing LED on port. Another TIMER used to trigger at the
speed configured from the analog read on an interrupt basis.
● Interrupt Service Routine (ISR) - An interrupt is based on the internal or external
events in which a program will stop execution of the main program and instead
execute another program. Then after it continues executing the main program.
● Finally we implement above mentioned functions to generate the PACMAN
character and move around the screen. Create the logic to increment the score,
build the walls, home screen, high score screen, navigable using the joystick and
add the enemy characters.

Flowchart
Explanation of the function of modules
General Introduction of Microcontroller :

A microcontroller (MCU) is a small computer on a single integrated circuit that is


designed to control specific tasks within electronic systems. It combines the
functions of a central processing unit (CPU), memory, and input/output
interfaces, all on a single chip.

Microcontrollers are widely used in embedded systems, such as home


appliances, automotive systems, medical devices, and industrial control systems.
They are also used in consumer electronics products, such as gaming systems,
digital cameras, and audio players.

Microcontrollers are programmable, which means that they can be customized to


perform specific tasks. The programming languages used to write code for
microcontrollers vary depending on the manufacturer and the type of
microcontroller. Some of the commonly used programming languages include C,
C++, and assembly language.

Architecture of Microcontroller :
Microcontroller is divided into three main parts : CPU, Memory and Input-Output
peripherals.

● CPU : It is used for arithmetic logical operations, Data path and control unit.
● Memory : Program memory, which stores long-term information about the
instructions that the CPU carries out. Program memory is non-volatile memory,
meaning it holds information over time without needing a power source.
Data memory, which is required for temporary data storage while the
instructions are being executed. Data memory is volatile, meaning the data it holds
is temporary and is only maintained if the device is connected to a power source.
● Input-Output Peripherals : Input/Output pins are used for simple “on”/”off”
communication, such as reading a button or turning on an LED. GPIOs can be
more complex than simply “on” and “off” however, with features such as pull-up and
pull-down.

General Purpose Input-Output(GPIO):

The goal of the chapter is to show the principles of GPIO manipulation and to develop a
function to enable movement using a joystick. This project or objective uses GPIO
manipulation, and push buttons on the MikroElektronika
"EasyMx_PRO_v7_for_STM32_ARM" microcontroller. The main objective of this project is
to show the GPIO manipulation when the push buttons have been pressed or to activate
the LEDs on PORT E/H when the push button is pressed. This project uses many ports as
input ports and port E as output ports. In this the PCB includes a pulldown resistor on the
switch, thus each port bit must be pulled UP (ACTIVE HIGH) to function. Port E/H LEDs
were activated to test the joystick’s success. The first step of this objective is to draw a
flow diagram showing the logic to implement the joystick and further this project shows the
GPIO pins should be set to activate the LEDs. This project has multiple objectives which
show the GPIO manipulations and the working of the joystick. In this project PCB includes
a pulldown resistor on the switch, thus each port bit must be pulled UP (Active HIGH) to
function. To test the success of using the joystick, we will activate LEDs on PORTE/H. This
project shows when UP is pressed, PE11 and PE15 will turn on. when DOWN is
pressedOE8 and PE12 will turn on. when LEFT is pressed, PE13 and PE14 will turn on.
when RIGHT is pressed, PE9 and PE10 will turn on. when CLICK is pressed, PE9 and
PE14 will turn on. All LEDs are off otherwise

INITIALIZATIONS : Configuring the GPIO manipulations


1. Enabling the clock for required ports. i.e., Port A, Port B, Port C, Port D and Port E
2. Configuring Port A, Port B, Port C, Port D as input ports and Port E as output

OBJECTIVE 2
Thus each port pins must be pulled UP (Active HIGH) to function respective Port Led’s to
test the success of the joystick.
Implementing the Joystick() functions
LEFT: When Joystick button moved to left PE13 and PE14 Leds will turn on
RIGHT: When Joystick button moved to right PE9 and PE10 Leds will turn on
UP: When Joystick button moved to Upper side then PE11 and PE15 Leds will turn on
DOWN: When Joystick button moved to down PE8 and PE12 Leds will turn on
CLICK: When the Joystick button is pressed all Leds will turn on when there is no button
pressed, all Leds will turn off.

Implementing the above-mentioned logics in C code

The expected outcomes for the code implemented on the development board

LEFT RIGHT UP
DOWN CLICK

OBJECTIVE 3
Configuring Analog input Potentiometer on PC0 which will be used for the game speed.
Setting up the PC0 jumper
Implementing the analog input from potentiometer values to Digital output to display on
output leds Configuring the potentiometer

Code is setting up and using the ADC to read values from a potentiometer.
To convert the ADC output to a range between 1 and 100, need to scale the ADC reading
accordingly. Assuming the ADC provides a reading between 0 and its maximum value (for
example 4095 for a 12 bit ADC), we can use simple mapping to scale the ADC reading to
get the desired range.
Example

unsigned int adcReading = 2048;


unsigned int scaledValue = convertToRange(adcReading);
scaledValue = ((adcReading - adcMin) * (desiredMax - desiredMin)) / (adcMax - adcMin) +
desiredMin scaledValue = ((2048 - 0) * (100 - 1)) / (4095 - 0) + 1 scaledValue = (2048 * 99)
/ 4095 + 1 scaledValue ≈ 49.989

Converting the approximate values into next roundup value

uint16_t scaledValue = (adcValue % 100) + 1;


Example Scaled value =49.989 Will give 50

Some sample outcomes from the above example.

Universal Asynchronous Receiver / Transmitter(UART) :

OBJECTIVE 1:
1. Enable clock for Port A, B, C, D and E.
2. Configure Port A, Port B, Port C, Port D as inputs for joystick and Port E as Output.
3. Configure Registers for USART1 communication.
4. Set Baud rate of 56,000 for the communication of USART1 terminal.
5. Initialize Port E as zeros (0x0000).
6. Start Infinity loop.
7. When UP(PD4) is pressed then PE11 and PE15 will be turned on and the MCU will
write UP in the terminal.
8. When DOWN(PB5) is pressed then PE8 and PE12 will be turned on and the MCU
will write DOWN in the terminal.
9. When LEFT(PD2) is pressed then PE13 and PE14 will be turned on and the MCU
will write LEFT in the terminal.
10. When RIGHT(PA6) is pressed then PE9 and PE10 will be turned on and the MCU
will write RIGHT in the terminal.
11. When CLICK(PC13) is pressed then PE9 and PE14 will be turned on and the MCU
will write CLICK in the terminal.
12. When UP is sent from the terminal to the MCU, then PE11 and PE15 will be turned
on and the MCU will write UP Pressed in the terminal.
13. When UP is sent again from the terminal to the MCU, then PE11 and PE15 will be
turned off and the MCU will write UP Released in the terminal.
14. When DN is sent from the terminal to the MCU, then PE8 and PE12 will be turned
on and the MCU will write DN Pressed in the terminal.
15. When DN is sent again from the terminal to the MCU, then PE8 and PE12 will be
turned off and the MCU will write DN Released in the terminal.
16. When LT is sent from the terminal to the MCU, then PE13 and PE14 will be turned
on and the MCU will write LT Pressed in the terminal.
17. When LT is sent again from the terminal to the MCU, then PE13 and PE14 will be
turned off and the MCU will write LT Released in the terminal.
18. When RT is sent from the terminal to the MCU, then PE9 and PE10 will be turned
on and the MCU will write RT Pressed in the terminal.
19. When RT is sent again from the terminal to the MCU, then PE9 and PE10 will be
turned off and the MCU will write RT Released in the terminal.
20. When CK is sent from the terminal to the MCU, then PE9 and PE14 will be turn on
and the MCU will write CK Pressed in the terminal.
21. When CK is sent again from the terminal to the MCU, then PE9 and PE14 will be
turn off and the MCU will write CK Released in the terminal

If Q is sent from the terminal to the MCU, then the MCU will respond no. of joystick
presses in terminal.
End of Infinity Loop.

OBJECTIVE 2 :
Initializing UART1 With Baud Rate of 56,000
1) Configure Registers for USART1 communication.
2) Set Baud rate of 56,000 for the communication of USART1 terminal.
3) Enable clock for Port A, B, C, D and E.
4) Configure Port A, Port B, Port C, Port D as inputs for joystick and Port E as Output.

The respective initializeUSART1() and Joystick() fucntions are calling from void main()
function to perform respective actions as mentioned below:
1. Start Infinity loop.
2. When UP Button(PD4) is pressed on the joystick then PE11 and PE15 will be
turned on and the MCU will write UP in the terminal.
3. When DOWN Button(PB5) is pressed on the joystick then PE8 and PE12 will be
turned on and the MCU will write DOWN in the terminal.
4. When LEFT Button (PD2) is pressed then PE13 and PE14 will be turned on and the
MCU will write LEFT in the terminal.
5. When RIGHT Button (PA6) is pressed then PE9 and PE10 will be turned on and the
MCU will write RIGHT in the terminal.
6. When CLICK Button (PC13) is pressed then PE9 and PE14 will be turned on and
the MCU will write CLICK in the terminal.

Expected outcomes are as follows:


Objective 3
user can write from the terminal to the MCU "P" or "p" to pause and unpause the game.
When the user writes "P" or "p", the MCU will respond with "Paused" or "Unpaused" to
indicate the game status.
Initializing an array with unpaused passing the value to pauseArray

unsigned int pauseArray[8] = {'u','n','p','a','u','s','e','d'};

Attaching the code snippet


The expected outcome for the objective 2 as follows.

Objective 4
If the user types "Q", the MCU will respond with the following text: Up: ###
Dn: ###
Lt: ###
Rt: ###
Ck: ###

Initializing an array:
unsigned char qArray[] = {'U','p',' ',':',' ','#','#','\n', 'D','n',' ', ':','#','#','\n','L','t','',':','#','#','\n','R','t','
',':',' ','#','#','\n','C','k',' ',':',' ','#','#'};

Code snippet
Expected outcome for the code:

Interrupt and Timer:


An interrupt service routine (ISR) is a special routine that is executed outside of
the normal program flow. An ISR is invoked in response to a particular interrupt
occurring at an undetermined time. Since an interrupt occurs at an unknown
time, it cannot return a value directly to a program. Thus, all ISRs are of
return-type void. The void type indicates that no value is returned from the
routine. An interrupt is a signal to the processor emitted by hardware or software
indicating an event that needs immediate attention. Whenever an interrupt
occurs, the controller completes the execution of the current instruction and
starts the execution of an Interrupt Service Routine (ISR). A timer is a specialized
type of clock which is used to measure time intervals. A timer that counts from
zero upwards for measuring time elapsed is often called a stopwatch. It is a
device that counts down from a specified time interval and used to generate a
time delay, for example, an hourglass is a timer. In this chapter we are talking
about Implementation of Timer 1 for a 1 second counter. To test this, configure
PORTE as an output which will toggle every second. This timer will be used as
our game’s running clock and Configure Timer 3 to trigger at 100 Hz on an
interrupt basis. This timer will be used to implement our game’s variable speed
and to Configure the UART terminal for 56,000 baud and, if the user types “T”,
the clock time will output every second. We are also using interrupts in this
chapter to Rewrite our joystick code to trigger up, down, left, and right, PA6, PB5,
PD2, and PD4 on an interrupt basis.

Algorithm for Timers and Interrupts:

1) Enable clock for Port A, B, C, D and E.

2) Configure Port A, Port B, Port C, Port D as inputs for joystick and Port E as
Output.

3) Configure Registers for USART1 communication.

4) Set Baud rate of 56,000 for the communication of USART1 terminal.

5) Initialize Port E as zeros (0x0000).

6) Configure and Initialize Timer1 configuration and Time3 configuration.

7) Implementation of Interrupt service routine for Timer1 and Timer3.

8) Implement Timer 1 for Real time clock and Implement timer 3 for for game
variable speed.

9) Implementation of interrupt service routine for JOYSTICK ie. For UP, DOWN,
LEFT, RIGHT, CLICK on interrupt basis.

10) When Typed T on USART, the clock time will output every second.

11) When UP(PD4) is pressed then PE11 and PE15 will be turn on and the MCU
will write UP in the terminal.

12) When DOWN(PB5) is pressed then PE8 and PE12 will be turn on and the
MCU will write DOWN in the terminal.

13) When LEFT(PD2) is pressed then PE13 and PE14 will be turn on and the
MCU will write LEFT in the terminal.

14) When RIGHT(PA6) is pressed then PE9 and PE10 will be turn on and the
MCU will write RIGHT in the terminal.

15) When CLICK(PC13) is pressed then PE9 and PE14 will be turn on and the
MCU will write CLICK in the terminal.

16) When UP is sent from the terminal to the MCU, then PE11 and PE15 will be
turn on and the MCU will write UP Pressed in the terminal.
17) When UP is sent again from the terminal to the MCU, then PE11 and PE15
will be turn off and the MCU will write UP Released in the terminal.

18) When DN is sent from the terminal to the MCU, then PE8 and PE12 will be
turn on and the MCU will write DN Pressed in the terminal.

19) When DN is sent again from the terminal to the MCU, then PE8 and PE12
will be turn off and the MCU will write DN Released in the terminal.

20) When LT is sent from the terminal to the MCU, then PE13 and PE14 will be
turn on and the MCU will write LT Pressed in the terminal.

21) When LT is sent again from the terminal to the MCU, then PE13 and PE14
will be turn off and the MCU will write LT Released in the terminal.

22) When RT is sent from the terminal to the MCU, then PE9 and PE10 will be
turn on and the MCU will write RT Pressed in the terminal.

23) When RT is sent again from the terminal to the MCU, then PE9 and PE10 will
be turn off and the MCU will write RT Released in the terminal.

24) When CK is sent from the terminal to the MCU, then PE9 and PE14 will be
turn on and the MCU will write CK Pressed in the terminal.

Objective 1: Draw a flow diagram showing the logic to implement the objectives
as described below.

Objective 2: Implement Timer 1 for a 1 second counter. To test this, configure


PORTE as an output which will toggle every second. This timer will be used as
our game’s running clock Display this as a flashing LED on any port. Also, create
a counter variable which will output the amount of seconds since start when the
user types "Q". If you did the bonus assignment, it will display this in addition to
the number of joystick presses.

Objective 3: Configure Timer 3 to trigger at the speed configured from the analog
read on PC0 from part 1 on an interrupt basis. This timer will be used to
implement our game’s variable speed. Display this as a flashing LED on any port.

Objective 4: Rewrite your joystick code to trigger up, down, left, and right, PA6,
PB5, PD2, and PD4 on an interrupt basis.
FINAL PART 4
PACMAN GAME

Project Overview: Pacman Game Implementation


In the culmination of our coursework, we undertook the ambitious task of implementing
the classic Pacman game. This project served as a comprehensive application of the
theoretical concepts covered in our lectures, primarily focusing on joystick interrupts,
timers, and interfacing with a TFT Display.

Configuring TFT Display


We are configuring the project type as Visual TFT Project with
EasyMac_Pro_v7_for_STM32_ARM_9A.
To use the display need to use SW1-5(Read-X,6-READ-Y,7-DRIVEA,8-DRIVEB)

The graphical representation of the Pacman game was achieved through the integration of
a TFT Display. This visual component not only brought the game to life but also provided a
clear and immersive interface for players. By utilizing the TFT Display, we were able to
render the maze, Pacman, ghosts, and other game elements with vibrant colors and
smooth animations, elevating the overall gaming experience.

Joystick Interrupts:
To provide responsive and dynamic user input, we harnessed the power of joystick
interrupts. This enabled us to efficiently detect and handle changes in the joystick's
position, allowing Pacman to navigate through the maze with precision. The
interrupt-driven approach significantly enhanced the real-time interactivity of our game,
ensuring a seamless and enjoyable user experience.

Timers:
Timers played a crucial role in managing various aspects of our Pacman game. We
strategically utilized timers to control game mechanics such as ghost movement patterns,
power-up duration, and overall gameplay pacing. This not only added a layer of
sophistication to our implementation but also showcased our proficiency in leveraging
timing mechanisms for precise control in embedded systems.
Initializing the timer3 as
void TIMER3_ISR () iv IVT_INT_TIM3
Below is the configuration part for timer3

Maze
We created our own maze pattern for the game. With hardcoded values of coordinates
TFT_Rectangle(x0,y0,x1,y1). Total we used 13 walls for the game.
Includes food positions with TFT_Circle(x0,y0,radius)
Conclusion and what you have learned from the project.

In this project we learned about how to use GPIO, Joysticks, LCD


Display and Interrupts in microcontrollers. Additionally we created
logic about counterpart and different display.
Appendix
/*

PACMAN2_main.c

* Project name: FINALPROJECT_PACMAN

PACMAN1.mcpar

* Generated by: PRIYANKA,SHARAD,PRISHAD,URAVANG

Visual TFT

* Date of creation

10-12-2023

* Test configuration:

MCU: STM32F107VC

Dev.Board: EasyMx_PRO_v7_for_STM32_ARM_9A

Oscillator: 72000000 Hz

SW: mikroC PRO for ARM

http://www.mikroe.com/mikroc/arm/

*/

#include <stdio.h>

#define ENTITY_SIZE 10

#define BORDER_X 320

#define BORDER_Y 240

#define FOOD_SIZZZE 5

#define FOOD_BIG_SIZE 10

#define NUM_WALLS 10

#include "PACMAN2_objects.h"

#include "PACMAN2_resources.h"

#include "PACMAN2_Screens.h"

extern adcValue;
void Timer3IntConfiguration();

int CheckCollisionWalls(struct EntityProperties Player, struct EntityProperties walls[]);

void InitializeWalls(struct EntityProperties walls[]);

void InitializeFood(struct EntityProperties Food[]);

void InitializeGhost(struct EntityProperties *ghost);

void MoveGhost(struct EntityProperties *ghost, struct EntityProperties walls[]);

int customRand();

unsigned long int ScreenStateMachine =0;

struct EntityProperties Player;

struct EntityProperties ghost[4];

struct EntityProperties walls[NUM_WALLS];

struct EntityProperties Food[100];

unsigned long int playerDir = 0;

unsigned long int gameTick = 0;

unsigned long int randSeed = 1; // Initialize a seed value

unsigned int getAdcReading(); // Begins conversion and returns 12 bit value

unsigned int adcVal;

unsigned int speed_counter = 0 ;

unsigned int variable_speed = 0;

void TIMER3_ISR () iv IVT_INT_TIM3 {

TIM3_SR.UIF = 0; // Reset UIF flag so next interrupt can be recognized when UIF is set

gameTick = 1 ;

if(speed_counter == adcVal)

variable_speed = variable_speed + 10;


speed_counter = 0;

speed_counter++;

void main() {

Start_TP();

JoyStickConfiguration();

Timer3IntConfiguration();

ClearScreen();

TitleScreen();

HomeScreen();

InitializeWalls(walls);

InitializeFood(Food);

InitializeGhost(&ghost);

while(1){

PlayScreen();

adcVal = getAdcReading();

delay_ms(500);

void InitializeWalls(struct EntityProperties walls[]) {

// Leftmost wall

walls[0].x0 = 50;

walls[0].x1 = 60 + ENTITY_SIZE;

walls[0].y0 = 60;

walls[0].y1 = 180 + ENTITY_SIZE;


walls[0].color = CL_PURPLE;

// Add more walls in a similar manner

walls[1].x0 = 90;

walls[1].x1 = 100 + ENTITY_SIZE;

walls[1].y0 = 70;

walls[1].y1 = 140 + ENTITY_SIZE;

walls[1].color = CL_PURPLE;

walls[2].x0 = 130;

walls[2].x1 = 140 + ENTITY_SIZE;

walls[2].y0 = 100;

walls[2].y1 = 130 + ENTITY_SIZE;

walls[2].color = CL_PURPLE;

walls[3].x0 = 140;

walls[3].x1 = 200 + ENTITY_SIZE;

walls[3].y0 = 130;

walls[3].y1 = 140 + ENTITY_SIZE;

walls[3].color = CL_PURPLE;

walls[4].x0 = 200;

walls[4].x1 = 210 + ENTITY_SIZE;

walls[4].y0 = 100;

walls[4].y1 = 130 + ENTITY_SIZE;

walls[4].color = CL_PURPLE;

walls[5].x0 = 70;

walls[5].x1 = 260 + ENTITY_SIZE;

walls[5].y0 = 190;
walls[5].y1 = 200 + ENTITY_SIZE;

walls[5].color = CL_PURPLE;

walls[6].x0 = 280;

walls[6].x1 = 290 + ENTITY_SIZE;

walls[6].y0 = 50;

walls[6].y1 = 170 + ENTITY_SIZE;

walls[6].color = CL_PURPLE;

walls[7].x0 = 240;

walls[7].x1 = 250 + ENTITY_SIZE;

walls[7].y0 = 60;

walls[7].y1 = 160 + ENTITY_SIZE;

walls[7].color = CL_PURPLE;

walls[8].x0 = 70;

walls[8].x1 = 260 + ENTITY_SIZE;

walls[8].y0 = 30;

walls[8].y1 = 40 + ENTITY_SIZE;

walls[8].color = CL_PURPLE;

/*

walls[8].x0 = 70;

walls[8].x1 = 260 + ENTITY_SIZE;

walls[8].y0 = 30;

walls[8].y1 = 40 + ENTITY_SIZE;

walls[8].color = CL_PURPLE;
walls[8].x0 = 310;

walls[8].x1 = 240 + ENTITY_SIZE;

walls[8].y0 = 20;

walls[8].y1 = 230 + ENTITY_SIZE;

walls[8].color = CL_PURPLE;

*/

void PlayScreen() {

unsigned long int i;

struct EntityProperties ghost;

TFT_Set_Brush(1, CL_RED, 0, 0, 0, 0);

TFT_Rectangle(30,30,40,40);

MoveGhost(&ghost, walls);

TFT_Fill_Screen (CL_BLACK);

TFT_Set_Brush(1, CL_RED, 0,0, 0, 9);

TFT_Set_Pen(CL_WHITE, 1); //Outer Boundaries

TFT_Rectangle (0,0, 10,240); //1

TFT_Rectangle (10, 230,320, 240); //bottom boundary 2

TFT_Rectangle(0, 0,320,10); // top boundary 3

TFT_Rectangle(310,10,320,240);//right boundarylst 4

//WALLS

TFT_Set_Brush(1,CL_PURPLE,0,0,0,0);

TFT_Rectangle(40,50,50,170); // left 5

TFT_Rectangle(80,60,90,140); //Left most opposite 6

TFT_Rectangle(120,90,130,130); //middle box left 10

TFT_Rectangle(130,120,200,130); //middle middle 11

TFT_Rectangle(200,90,210,130); //middle box roght 12


TFT_Rectangle(70,190,260,200); //bottom most 1st 7

TFT_Rectangle(280,50,290,170); //rightmost 8

TFT_Rectangle(240,60,250,160); //rightmost 9

TFT_Rectangle(70,30,260,40); // topmost

TFT_Set_Brush(1,CL_WHITE,0,0,0,0);

for (i = 0; i < 100; i++) {

if (Food[i].isAlive) {

TFT_Circle(Food[i].x0, Food[i].y0, 3);

// Check for collision with player

if ((Player.x0 < Food[i].x1) &&

(Player.x1 > Food[i].x0) &&

(Player.y0 < Food[i].y1) &&

(Player.y1 > Food[i].y0)) {

TFT_Write_Text("Collision Detected!", 10, 50);

TFT_Write_Text("Player X:", 10, 70);

TFT_Write_Text("Player Y:", 10, 90);

TFT_Write_Text("Food X:", 10, 110);

TFT_Write_Text("Food Y:", 10, 130);

// Display the coordinates of the player and food

TFT_Write_Text(Player.x0, 90, 70);

TFT_Write_Text(Player.y0, 90, 90);

TFT_Write_Text(Food[i].x0, 90, 110);

TFT_Write_Text(Food[i].y0, 90, 130);


// Food eaten, make it disappear

Food[i].isAlive = 0;

// You may also increase the score or perform other actions here

//TFT_Circle(30, 20, 3); //(X,Y,RADIUS) Left side food

TFT_Circle(25, 40, 3);

TFT_Circle(25, 70, 3);

TFT_Circle(25, 100, 3);

TFT_Circle(25, 130, 3);

TFT_Circle(25, 170, 3);

TFT_Circle(80, 170, 3); //Bottom Food

TFT_Circle(110, 170, 3);

TFT_Circle(140, 170, 3);

TFT_Circle(170, 170, 3);

TFT_Circle(200, 170, 3);

TFT_Circle(140, 110, 3);

TFT_Circle(190, 110, 3);

TFT_Circle(20, 15, 5);

TFT_Circle(80, 15, 3);

TFT_Circle(110, 15, 3);

TFT_Circle(140, 15, 3);

TFT_Circle(170, 15, 3);

TFT_Circle(200, 15, 3);


TFT_Circle(230, 15, 3);

TFT_Circle(260, 15, 3);

if(playerDir == 0 ) {

//DEFAULT happens only one

Player.x0 = 160;

Player.x1 = 160+ENTITY_SIZE;

Player.y0 = 90; //105

Player.y1 =90+ENTITY_SIZE;

Player.color = CL_YELLOW;

TFT_Set_Brush(1,Player.color,0,0,0,0);

TFT_Rectangle(Player.x0,Player.y0,Player.x1,Player.y1);

} else {

switch(playerDir){

case 2: //left

//check if Player s collided with anything

//move the player

if (!CheckCollisionWalls(Player, walls) && (Player.x0 > 10)) {

Player.x0 -= ENTITY_SIZE;

Player.x1 -= ENTITY_SIZE;

//redrawing

TFT_Set_Brush(1, CL_BLACK, 0, 0, 0, 0);

TFT_Rectangle(Player.x0, Player.y0, Player.x1, Player.y1 );

break;

case 4://UP

//check if Player s collided with anything


//move the player

if (!CheckCollisionWalls(Player, walls) && ((Player.y0 + ENTITY_SIZE) > 20)) {

Player.y0 -= ENTITY_SIZE;

Player.y1 -= ENTITY_SIZE;

TFT_Set_Brush(1, CL_BLACK, 0, 0, 0, 0);

TFT_Rectangle(Player.x0, Player.y0, Player.x1, Player.y1 );

break;

case 5: //Down

//check if Player s collided with anything

//move the player

if (!CheckCollisionWalls(Player, walls) && ((Player.y0 + ENTITY_SIZE) < 230)) {

Player.y0 += ENTITY_SIZE;

Player.y1 += ENTITY_SIZE;

TFT_Set_Brush(1, CL_BLACK, 0, 0, 0, 0);

TFT_Rectangle(Player.x0, Player.y0, Player.x1, Player.y1 );

break;

case 6: //Right

//check if Player s collided with anything

//move the player

if (!CheckCollisionWalls(Player, walls) && ((Player.x0 + ENTITY_SIZE) < 320)) {

Player.x0 += ENTITY_SIZE;

Player.x1 += ENTITY_SIZE;

TFT_Set_Brush(1, CL_BLACK, 0, 0, 0, 0);

TFT_Rectangle(Player.x0, Player.y0, Player.x1, Player.y1 );


break;

default:

break;

TFT_Set_Brush(1,Player.color,0,0,0,0);

TFT_Rectangle(Player.x0,Player.y0,Player.x1,Player.y1);

while(gameTick == 0) {};

gameTick =0;

int CheckCollisionWalls(struct EntityProperties Player, struct EntityProperties walls[]) {

unsigned long int i;

/* int foodx0[20]={

int foody0[20]={25,25,25,25,25,80,110,170,200,140,190,20,80,110,140,170,200,230,260 */

// Calculate the next position based on the direction of movement

int nextX0 = Player.x0;

int nextX1 = Player.x1;

int nextY0 = Player.y0;

int nextY1 = Player.y1;

switch (playerDir) {

case 2: // Left

nextX0 -= ENTITY_SIZE;

nextX1 -= ENTITY_SIZE;

break;

case 4: // Up
nextY0 -= ENTITY_SIZE;

nextY1 -= ENTITY_SIZE;

break;

case 5: // Down

nextY0 += ENTITY_SIZE;

nextY1 += ENTITY_SIZE;

break;

case 6: // Right

nextX0 += ENTITY_SIZE;

nextX1 += ENTITY_SIZE;

break;

default:

break;

// Check for overlap between player and wall in the next position

for (i = 0; i < NUM_WALLS; i++) {

if ((nextX0 < walls[i].x1) && (nextX1 > walls[i].x0) &&

(nextY0 < walls[i].y1) && (nextY1 > walls[i].y0)) {

return 1; // Collision in the next position, stop movement

if(nextX0==30 && nextY0==40&& nextX1==30 && nextY1==40){HomeScreen();}

return 0; // No collision, continue movement

}
void Timer3IntConfiguration(){

RCC_APB1ENR |= (1 << 1);// Enable TIMER3 clock. RCC: Clock Configuration Register

TIM3_CR1 = 0x0000; // Disable timer until configuration is complete

// If reset value of RCC_CFGR is used, then the 8MHz clock will

// be the clock source for timer

TIM3_PSC = 7999; // Clock to TIMx_CNT = 72000000 (clock applied to prescaler register) /

// 7999 (Value in TIMx_PSC) + 1) = 9000

TIM3_ARR = 2250; // Reload timer count register with this value when count register resets

// to 0 after counting from zero to this value

NVIC_ISER0.B29 = 1; // Enable global interrupt for TIMER3 in NVIC

// Interrupt set enable register 0. Position of this interrupt in vector

// table is 29, so set the corresponding bit in interrupt service enable

// register 0. This is a 32 bit register. ISER1 is used for interrupt

// numbers greater than 31.

TIM3_DIER.UIE = 1; // Update interrupt enable

TIM3_CR1 = 0x0001; // Enable TIMER3

void External_Int_Configuration()

RCC_APB2ENR.AFIOEN = 1; // Enable clock for alternate pin function 39

AFIO_EXTICR1 |= 0x00000300; // PD2 as External interrupt

AFIO_EXTICR2 |= 0x00000013; // PD4,PB5,PA6 as External interrupt

AFIO_EXTICR4 |= 0x00000020; // PC13 as External interrupt

EXTI_IMR |= 0x00002074; // Interrupt on PD4,PD2,PB5, are non-maskable

EXTI_RTSR |= 0x00002074; // Set interrupt on rising edge for PD4,PB5

EXTI_FTSR |= 0x00002074; // Set interrupt on falling edge for PD4,PB5

NVIC_ISER0.B10 = 1; // Enable NVIC interrupt for EXTI line four (PD4)

NVIC_ISER0.B8 = 1; // Enable NVIC interrupt for EXTI line two (PD2)

NVIC_ISER0.B23 = 1;
NVIC_IntEnable(IVT_INT_EXTI15_10); // Enable NVIC interrupt for EXTI line [15:10] (PC13)

// Sub function which initializes the registers to enable ADC for PC0

void AdcConfiguration()

RCC_APB2ENR |= 1 << 4; // Enable PORTC clock

RCC_APB2ENR |= 1 << 9 ; // Enable ADC1 Clock

GPIOC_CRL &= ~(0xF << 0); // Configure PC0 as an Analog Input

ADC1_SQR1 = (0b0000 << 20); // 1 conversion

ADC1_SQR3 = 10; // Select Channel 10 as only one in conversion sequence

ADC1_SMPR1 = 0b100; // Set sample time on channel 10

ADC1_CR2 |= (0b111 << 17); // Set software start as external event for regular group conversion

ADC1_CR2.ADON = 1; // Enable ADC1

delay_ms(10);

unsigned int getAdcReading(){

// Bit 20 is set to start conversion of an external channel, bit 22 starts the conversion

ADC1_CR2 |= (1 << 22) | (1 << 20);

while(!(ADC1_SR & 0b10)); // Wait until the ADC conversion has ended

return ADC1_DR; // Read value from data register. This also clears start bit

void InitializeFood(struct EntityProperties Food[]) {

unsigned long int i;

for (i = 0; i < 100; i++) {

Food[i].x0 = 170/* set initial x-coordinate */;

Food[i].x1 = 160 /* set initial x-coordinate */;

Food[i].y0 = 60 /* set initial y-coordinate */;


Food[i].y1 = 80/* set initial y-coordinate */;

Food[i].isAlive = 1; // Set isAlive to 1 to indicate that the food is initially alive

void InitializeGhost(struct EntityProperties *ghost) {

ghost->x0 = 20/* set initial x-coordinate */;

ghost->x1 = 20/* set initial x-coordinate */;

ghost->y0 = 20/* set initial y-coordinate */;

ghost->y1 = 20/* set initial y-coordinate */;

ghost->color = CL_RED/* set ghost color */;

void MoveGhost(struct EntityProperties *ghost, struct EntityProperties walls[]) {

int randomDirection = customRand() % 4 + 1; // Generate random direction (1-4)

// Adjust ghost coordinates based on the random direction

switch (randomDirection) {

case 1: // Move up

if (ghost->y0 - ENTITY_SIZE >= 0) {

ghost->y0 -= ENTITY_SIZE;

ghost->y1 -= ENTITY_SIZE;

break;

case 2: // Move down

if (ghost->y1 + ENTITY_SIZE <= BORDER_Y) {

ghost->y0 += ENTITY_SIZE;

ghost->y1 += ENTITY_SIZE;

break;
case 3: // Move left

if (ghost->x0 - ENTITY_SIZE >= 0) {

ghost->x0 -= ENTITY_SIZE;

ghost->x1 -= ENTITY_SIZE;

break;

case 4: // Move right

if (ghost->x1 + ENTITY_SIZE <= BORDER_X) {

ghost->x0 += ENTITY_SIZE;

ghost->x1 += ENTITY_SIZE;

break;

default:

break;

int customRand() {

randSeed = randSeed * 1103515245 + 12345;

return (randSeed / 65536) % 32768;

**************************************************************************************************

//PACMAN2_Screen.c

#include "PACMAN2_resources.h"

//PACMAN2_Screens.c
void GameOverScreen(){

void HighScoreScreen(){

void TitleScreen(){

TFT_Rectangle(20, 20, 219, 107);

TFT_Write_Text("PACMAN-GROUP2",40,100);

TFT_Write_Text("By", 220, 120);

TFT_Write_Text("PRIYANKA", 200, 140);

TFT_Write_Text("SHARAD", 200, 160);

TFT_Write_Text("PARISHAD", 200, 180);

TFT_Write_Text("URAVANG", 200, 200);

delay_ms(2020);

void HomeScreen(){

TFT_Rectangle(20, 20, 219, 107);

TFT_Fill_Screen(CL_WHITE);

TFT_Write_Text("WELCOME!", 132, 107);

//screen 2(Home page)

delay_mS(2000); // wait 2sec

TFT_Fill_Screen(CL_WHITE);

TFT_Set_Pen(CL_BLACK, 1);

TFT_Line(20, 46, 300, 46); // top line

TFT_Line(20, 220, 300, 220); // bottom line

//TFT_Set_Font(&Impact26x39_Regular, CL_RED, FO_HORIZONTAL);

TFT_Write_Text("PACKMAN", 120, 120);

delay_mS(2000); // wait 2sec


delay_ms(2000);

void HowToScreen(){

void ClearScreen(){

TFT_Set_Pen(CL_SILVER,1);

TFT_Set_Brush(1,CL_SILVER,0,0,0,0);

TFT_RECTANGLE(0,0,320,240);

TFT_Set_Pen(CL_BLACK,1);

TFT_Set_Brush(1,CL_BLACK,0,0,0,0);

TFT_Rectangle(10,10,310,230);

TFT_Set_Font(TFT_defaultFont,CL_BLUE,FO_HORIZONTAL);

TFT_Write_Text("PACMAN-GROUP2",4,225);

//delay_ms(2020);

********************************************************************************************************************

#include "PACMAN2_resources.h"

extern playerDir;

// ISR

//Default state of joystick high, logic 1 when not pressed

//ISR to detect joystick presses

//ISR for EXTI2 to check PD2

void JoyStickLeft() iv IVT_INT_EXTI2 {

//Process left button being pressed

EXTI_PR.B2 = 1; //Pending Register clearing

//GPIOE_ODR.B12 = ~GPIOE_ODR.B12;

playerDir = 2; //left
}

// ISR for EXTI4 (PA4) to check Joystick Up

void JoyStickUp() iv IVT_INT_EXTI4 {

EXTI_PR.B4 = 1; // Clear pending register for PA4

playerDir = 4; // up

// Example debug output in JoyStickRightAndDown ISR

void JoyStickRightAndDown() iv IVT_INT_EXTI9_5 {

if ((EXTI_PR & (1 << 5)) != 0) {

// EXTI line 5 (PB5) triggered the interrupt

//EXTI_PR.B5 = 1; // Clear pending register for PB5

playerDir = 5; // down

// Add debug output or LED toggle here

else if ((EXTI_PR & (1 << 6)) != 0) {

// EXTI line 6 (PA6) triggered the interrupt

EXTI_PR.B6 = 1; // Clear pending register for PA6

playerDir = 6; // right

// Add debug output or LED toggle here

//Function to configure Joystick as interrupt GPIO

void JoyStickConfiguration(){

//PA6 as input

GPIOA_CRL = 0x4000000; //PA6 as floating input

RCC_APB2ENR.IOPAEN =1; //Enable port A clock


GPIOB_CRL = 0x4000000; //PB6 as floating input

RCC_APB2ENR.IOPBEN =1; //Enable port B clock

GPIOD_CRL = 0x40400;

RCC_APB2ENR.IOPDEN =1; //Enable port D clock

RCC_APB2ENR.AFIOEN =1; //Enablr alternate function clock for interrupts

AFIO_EXTICR1 = 0x0300;

AFIO_EXTICR2 = 0x0013; //Configure PA6,PB5,PD4 as interrupt

//EXTI_FTSR = 0x0074; //Enablr falling edge trigger

EXTI_RTSR = 0x0074; //Enablr for falling edge

EXTI_IMR = 0x0074; //Enable interrupt unmasking

NVIC_ISER0.B8 =1;

NVIC_ISER0.B10 =1;

NVIC_ISER0.B23 =1;

*********************************************************************************************************************

void JoyStickConfiguration(); //forward declaration

struct EntityProperties{

int x0;

int x1;

int y0;

int y1;

int color;

int isAlive; // Flag to indicate if the entity is still present

};

You might also like