Annotated Embedded Report
Annotated Embedded Report
Guided By:
Prof Francis Pellicano
([email protected])
TA : Bhanu Pratap
([email protected])
Table of Content
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.
We will use USB UART A, which utilizes PA9 and PA10 as TX and RX,
respectively. Description of the program is outlined below.
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
Flowchart
Explanation of the function of modules
General Introduction of Microcontroller :
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.
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
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.
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
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.
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:
2) Configure Port A, Port B, Port C, Port D as inputs for joystick and Port E as
Output.
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 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
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.
PACMAN2_main.c
PACMAN1.mcpar
Visual TFT
* Date of creation
10-12-2023
* Test configuration:
MCU: STM32F107VC
Dev.Board: EasyMx_PRO_v7_for_STM32_ARM_9A
Oscillator: 72000000 Hz
http://www.mikroe.com/mikroc/arm/
*/
#include <stdio.h>
#define ENTITY_SIZE 10
#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 customRand();
TIM3_SR.UIF = 0; // Reset UIF flag so next interrupt can be recognized when UIF is set
gameTick = 1 ;
if(speed_counter == adcVal)
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);
// Leftmost wall
walls[0].x0 = 50;
walls[0].x1 = 60 + ENTITY_SIZE;
walls[0].y0 = 60;
walls[1].x0 = 90;
walls[1].y0 = 70;
walls[1].color = CL_PURPLE;
walls[2].x0 = 130;
walls[2].y0 = 100;
walls[2].color = CL_PURPLE;
walls[3].x0 = 140;
walls[3].y0 = 130;
walls[3].color = CL_PURPLE;
walls[4].x0 = 200;
walls[4].y0 = 100;
walls[4].color = CL_PURPLE;
walls[5].x0 = 70;
walls[5].y0 = 190;
walls[5].y1 = 200 + ENTITY_SIZE;
walls[5].color = CL_PURPLE;
walls[6].x0 = 280;
walls[6].y0 = 50;
walls[6].color = CL_PURPLE;
walls[7].x0 = 240;
walls[7].y0 = 60;
walls[7].color = CL_PURPLE;
walls[8].x0 = 70;
walls[8].y0 = 30;
walls[8].y1 = 40 + ENTITY_SIZE;
walls[8].color = CL_PURPLE;
/*
walls[8].x0 = 70;
walls[8].y0 = 30;
walls[8].y1 = 40 + ENTITY_SIZE;
walls[8].color = CL_PURPLE;
walls[8].x0 = 310;
walls[8].y0 = 20;
walls[8].color = CL_PURPLE;
*/
void PlayScreen() {
TFT_Rectangle(30,30,40,40);
MoveGhost(&ghost, walls);
TFT_Fill_Screen (CL_BLACK);
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(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);
if (Food[i].isAlive) {
Food[i].isAlive = 0;
// You may also increase the score or perform other actions here
if(playerDir == 0 ) {
Player.x0 = 160;
Player.x1 = 160+ENTITY_SIZE;
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
Player.x0 -= ENTITY_SIZE;
Player.x1 -= ENTITY_SIZE;
//redrawing
break;
case 4://UP
Player.y0 -= ENTITY_SIZE;
Player.y1 -= ENTITY_SIZE;
break;
case 5: //Down
Player.y0 += ENTITY_SIZE;
Player.y1 += ENTITY_SIZE;
break;
case 6: //Right
Player.x0 += ENTITY_SIZE;
Player.x1 += ENTITY_SIZE;
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 foodx0[20]={
int foody0[20]={25,25,25,25,25,80,110,170,200,140,190,20,80,110,140,170,200,230,260 */
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
}
void Timer3IntConfiguration(){
RCC_APB1ENR |= (1 << 1);// Enable TIMER3 clock. RCC: Clock Configuration Register
TIM3_ARR = 2250; // Reload timer count register with this value when count register resets
void External_Int_Configuration()
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()
ADC1_CR2 |= (0b111 << 17); // Set software start as external event for regular group conversion
delay_ms(10);
// Bit 20 is set to start conversion of an external channel, bit 22 starts the conversion
while(!(ADC1_SR & 0b10)); // Wait until the ADC conversion has ended
return ADC1_DR; // Read value from data register. This also clears start bit
switch (randomDirection) {
case 1: // Move up
ghost->y0 -= ENTITY_SIZE;
ghost->y1 -= ENTITY_SIZE;
break;
ghost->y0 += ENTITY_SIZE;
ghost->y1 += ENTITY_SIZE;
break;
case 3: // Move left
ghost->x0 -= ENTITY_SIZE;
ghost->x1 -= ENTITY_SIZE;
break;
ghost->x0 += ENTITY_SIZE;
ghost->x1 += ENTITY_SIZE;
break;
default:
break;
int customRand() {
**************************************************************************************************
//PACMAN2_Screen.c
#include "PACMAN2_resources.h"
//PACMAN2_Screens.c
void GameOverScreen(){
void HighScoreScreen(){
void TitleScreen(){
TFT_Write_Text("PACMAN-GROUP2",40,100);
delay_ms(2020);
void HomeScreen(){
TFT_Fill_Screen(CL_WHITE);
TFT_Fill_Screen(CL_WHITE);
TFT_Set_Pen(CL_BLACK, 1);
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
//GPIOE_ODR.B12 = ~GPIOE_ODR.B12;
playerDir = 2; //left
}
playerDir = 4; // up
playerDir = 5; // down
playerDir = 6; // right
void JoyStickConfiguration(){
//PA6 as input
GPIOD_CRL = 0x40400;
AFIO_EXTICR1 = 0x0300;
NVIC_ISER0.B8 =1;
NVIC_ISER0.B10 =1;
NVIC_ISER0.B23 =1;
*********************************************************************************************************************
struct EntityProperties{
int x0;
int x1;
int y0;
int y1;
int color;
};