Laporan Akhir




1. Prosedur [Kembali]

  1. 1. Rangkai alat sesuai prosedur modul

    2. Buka software proteus lalu rangkai komponen sesuai dengan gambar yang ada di modul

    3. Buka software STM32CubeIDE lalu lakukan konfigurasi pin pada STM untuk menentukan GPIO input dan GPIO output

    4. Masukan program ke dalam STM32

    5. Jalankan program

2. Hardware dan diagram blok [Kembali]

1. Push Button


2. Breadboard

3. STM 32 NUCLEO G474RE

 


4. Adaptor
5. LED 

                                                                


 6. Jumper


3. Rangkaian Simulasi dan Prinsip Kerja [Kembali]



Prinsip kerja sistem diawali oleh STM32 Master yang bertindak sebagai pusat pengendali permainan Dino pada layar OLED melalui komunikasi I2C. Master membaca input tombol menggunakan GPIO untuk mengatur karakter Dino agar dapat melompat, kemudian menghitung gerakan berdasarkan parameter kecepatan (velocity) dan gravitasi. Selanjutnya, Master mengendalikan pergerakan kaktus, memperbarui posisi karakter, serta menampilkan berbagai elemen permainan seperti Dino, rintangan, garis tanah, dan skor pada OLED secara berulang dan kontinu.

Selama permainan berlangsung, Master juga melakukan deteksi tabrakan (collision detection) antara karakter Dino dan kaktus. Apabila Dino berhasil melewati rintangan, skor akan bertambah. Namun jika terjadi tabrakan, sistem akan mengubah kondisi permainan menjadi game over dan menampilkan tulisan Game Over beserta nilai high score pada layar OLED. Seluruh logika permainan diproses oleh board Master sehingga board ini berfungsi sebagai pusat pengolahan dan pengendalian sistem.

Selain menjalankan permainan, Master turut mengirimkan data perintah ke STM32 Slave melalui komunikasi SPI menggunakan jalur MOSI, MISO, SCK, dan NSS. Data yang dikirim berupa kondisi permainan, seperti status game berjalan, game over, suara lompatan, dan suara tabrakan. Perintah tersebut diterima oleh Slave menggunakan fungsi HAL_SPI_Receive().

STM32 Slave bertugas mengendalikan perangkat output tambahan berupa LED hijau, LED merah, dan buzzer. Ketika permainan berjalan normal, LED hijau akan menyala, sedangkan saat permainan berakhir LED merah akan aktif. Buzzer juga menghasilkan bunyi singkat ketika Dino melompat dan bunyi tertentu saat tabrakan terjadi. Dengan pembagian fungsi antara Master dan Slave, sistem menjadi lebih terstruktur karena pemrosesan permainan dan pengendalian perangkat output dilakukan secara terpisah.








Listing Program

PROGRAM MASTER
main.c

#include "main.h"

#include "ssd1306.h"

#include <stdio.h>

/* ================= SPI ================= */
SPI_HandleTypeDef hspi1;

/* ================= OLED I2C ================= */
I2C_HandleTypeDef hi2c1;

/* ================= COMMAND ================= */
#define CMD_GAME_RUN     0x01
#define CMD_GAME_OVER    0x02
#define CMD_JUMP_SOUND   0x03
#define CMD_HIT_SOUND    0x04

/* ================= CS PIN ================= */
#define CS_PORT GPIOA
#define CS_PIN  GPIO_PIN_4

/* ================= GAME ================= */
int dinoY, velocityY, cactusX;

uint32_t score, highScore;
uint8_t isJumping, gameOver;

#define GRAVITY 2
#define FRAME_DELAY 30
#define GROUND_Y 48

#define DINO_HEIGHT 10

char buf[20];

/* ================= SEND SPI ================= */
void Send_To_Slave(uint8_t cmd)
{
    HAL_GPIO_WritePin(CS_PORT, CS_PIN, GPIO_PIN_RESET);

    HAL_SPI_Transmit(&hspi1, &cmd, 1, 100);

    HAL_GPIO_WritePin(CS_PORT, CS_PIN, GPIO_PIN_SET);

    HAL_Delay(1); // penting untuk sync slave
}

/* ================= MAIN ================= */
int main(void)
{
    HAL_Init();

    SystemClock_Config();

    MX_GPIO_Init();
    MX_SPI1_Init();
    MX_I2C1_Init();

    ssd1306_Init();

    HAL_GPIO_WritePin(GPIOA, CS_PIN, GPIO_PIN_SET);

    ResetGame();

    while (1)
    {
        if (!gameOver)
        {
            UpdateGame();

            DrawGame();

            Send_To_Slave(CMD_GAME_RUN);
        }
        else
        {
            DrawGameOver();

            if (score > highScore)
                highScore = score;

            Send_To_Slave(CMD_GAME_OVER);

            if (HAL_GPIO_ReadPin(JUMP_BTN_GPIO_Port, JUMP_BTN_Pin) ==
                GPIO_PIN_RESET)
            {
                ResetGame();

                HAL_Delay(300);
            }
        }

        HAL_Delay(FRAME_DELAY);
    }
}

/* ================= GAME LOGIC ================= */

void UpdateGame(void)
{
    if (HAL_GPIO_ReadPin(JUMP_BTN_GPIO_Port, JUMP_BTN_Pin) ==
        GPIO_PIN_RESET && !isJumping)
    {
        velocityY = -12;

        isJumping = 1;

        Send_To_Slave(CMD_JUMP_SOUND);
    }

    dinoY += velocityY;

    velocityY += GRAVITY;

    if (dinoY >= GROUND_Y)
    {
        dinoY = GROUND_Y;

        velocityY = 0;

        isJumping = 0;
    }

    cactusX -= (6 + score / 15);

    if (cactusX < -10)
    {
        cactusX = 128;

        score++;
    }

    if (cactusX < 25 && cactusX > 5 &&
        (dinoY + DINO_HEIGHT) > 48)
    {
        gameOver = 1;

        Send_To_Slave(CMD_HIT_SOUND);
    }
}

/* ================= DRAW ================= */

void DrawGame(void)
{
    ssd1306_Fill(Black);

    ssd1306_DrawRectangle(10, dinoY,
                          20, dinoY + DINO_HEIGHT,
                          White);

    ssd1306_FillRectangle(cactusX, 48,
                          cactusX + 8, 60,
                          White);

    ssd1306_Line(0, 61, 127, 61, White);

    sprintf(buf, "Sc:%lu", score);

    ssd1306_SetCursor(0, 0);

    ssd1306_WriteString(buf, Font_7x10, White);

    sprintf(buf, "Hsc:%lu", highScore);

    ssd1306_SetCursor(80, 0);

    ssd1306_WriteString(buf, Font_7x10, White);

    ssd1306_UpdateScreen();
}

void DrawGameOver(void)
{
    ssd1306_Fill(Black);
}
ssd1306_SetCursor(30, 15);

ssd1306_WriteString("GAME OVER", Font_7x10, White);

sprintf(buf, "HighScore:%lu", highScore);

ssd1306_SetCursor(25, 35);

ssd1306_WriteString(buf, Font_7x10, White);

ssd1306_UpdateScreen();

}

/* ================= RESET ================= */

void ResetGame(void)
{
    dinoY = GROUND_Y;

    velocityY = 0;

    cactusX = 128;

    score = 0;

    isJumping = 0;

    gameOver = 0;
}

/* ================= SPI INIT ================= */

void MX_SPI1_Init(void)
{
    hspi1.Instance = SPI1;

    hspi1.Init.Mode = SPI_MODE_MASTER;

    hspi1.Init.Direction = SPI_DIRECTION_2LINES;

    hspi1.Init.DataSize = SPI_DATASIZE_8BIT;

    hspi1.Init.CLKPolarity = SPI_POLARITY_LOW;

    hspi1.Init.CLKPhase = SPI_PHASE_1EDGE;

    hspi1.Init.NSS = SPI_NSS_SOFT;

    hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_16;

    hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB;

    HAL_SPI_Init(&hspi1);
}

/* ================= GPIO ================= */

void MX_GPIO_Init(void)
{
    __HAL_RCC_GPIOA_CLK_ENABLE();

    GPIO_InitTypeDef GPIO_InitStruct = {0};

    /* CS */
    GPIO_InitStruct.Pin = GPIO_PIN_4;

    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;

    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;

    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

    /* BUTTON */
    GPIO_InitStruct.Pin = JUMP_BTN_Pin;

    GPIO_InitStruct.Mode = GPIO_MODE_INPUT;

    GPIO_InitStruct.Pull = GPIO_PULLUP;

    HAL_GPIO_Init(JUMP_BTN_GPIO_Port, &GPIO_InitStruct);
}

main.h

#ifndef __MAIN_H
#define __MAIN_H

#ifdef __cplusplus
extern "C" {
#endif

#include "stm32g4xx_hal.h"

#include "ssd1306.h"

#include "ssd1306_fonts.h"

#include <stdio.h>

/* Definisi Pin Hardware */

#define JUMP_BTN_Pin GPIO_PIN_0

#define JUMP_BTN_GPIO_Port GPIOA

/* Konstanta Permainan */

#define GROUND_Y 44

#define DINO_WIDTH 15

#define DINO_HEIGHT 15

/* Prototipe Fungsi */
void SystemClock_Config(void);
 void MX_GPIO_Init(void); 
 void MX_I2C1_Init(void);
 void Error_Handler(void);
 #ifdef __cplusplus
 }
 #endif 
#endif /* __MAIN_H */  

PROGRAM SLAVE

 main.c

#include "main.h"

/* ================= SPI ================= */
SPI_HandleTypeDef hspi1;

/* ================= COMMAND ================= */
#define CMD_GAME_RUN      0x01
#define CMD_GAME_OVER     0x02
#define CMD_JUMP_SOUND    0x03
#define CMD_HIT_SOUND     0x04

/* ================= PROTOTYPE ================= */
void SystemClock_Config(void);
void MX_GPIO_Init(void);
void MX_SPI1_Init(void);
void Send(uint8_t data);

/* ================= MAIN ================= */
int main(void)
{
    HAL_Init();
    SystemClock_Config();

    MX_GPIO_Init();
    MX_SPI1_Init();

    while (1)
    {
        Send(CMD_GAME_RUN);
        HAL_Delay(500);

        Send(CMD_JUMP_SOUND);
        HAL_Delay(500);

        Send(CMD_GAME_OVER);
        HAL_Delay(1000);
    }
}

/* ================= SEND SPI ================= */
void Send(uint8_t data)
{
    HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET); // CS LOW
    HAL_SPI_Transmit(&hspi1, &data, 1, 100);
    HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_SET);   // CS HIGH
}

/* ================= SPI INIT ================= */
void MX_SPI1_Init(void)
{
    hspi1.Instance = SPI1;

    hspi1.Init.Mode = SPI_MODE_MASTER;
    hspi1.Init.Direction = SPI_DIRECTION_2LINES;
    hspi1.Init.DataSize = SPI_DATASIZE_8BIT;
    hspi1.Init.CLKPolarity = SPI_POLARITY_LOW;
    hspi1.Init.CLKPhase = SPI_PHASE_1EDGE;
    hspi1.Init.NSS = SPI_NSS_SOFT;
    hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_16;
    hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB;

    HAL_SPI_Init(&hspi1);
}

/* GPIO CS */
void MX_GPIO_Init(void)
{
    __HAL_RCC_GPIOA_CLK_ENABLE();

    GPIO_InitTypeDef GPIO_InitStruct = {0};

    GPIO_InitStruct.Pin = GPIO_PIN_4;
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;

    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

    HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_SET);
}

/* CLOCK (simple safe) */
void SystemClock_Config(void)
{
}

5. Video Demo [Kembali]


6. Analisa [Kembali]





7. Video Simulasi [Kembali]


                                             

8. Download File [Kembali]














 

Komentar

Postingan populer dari blog ini