Laporan Akhir M3




1. Prosedur [Kembali]

      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]



Sistem ini terdiri dari dua board STM32 NUCLEO-G474RE yang saling terhubung melalui protokol SPI, dengan board master juga terhubung ke layar OLED melalui protokol I2C. Board master menjalankan logika permainan Dino Jump, di mana input berupa tombol push button pada pin PA0 dibaca setiap siklus loop. Ketika tombol ditekan, karakter dino pada layar OLED akan bergerak ke atas mengikuti simulasi fisika gravitasi, sementara kaktus bergerak dari kanan ke kiri secara otomatis dengan kecepatan yang meningkat seiring bertambahnya skor.

Setiap perubahan kondisi permainan pada master langsung dikomunikasikan ke board slave melalui jalur SPI. Master menarik pin NSS ke kondisi LOW, mengirimkan satu byte command via MOSI, lalu melepas NSS ke HIGH sebagai tanda akhir pengiriman. Board slave menunggu data secara blocking menggunakan HAL_SPI_Receive, kemudian memproses command yang diterima melalui mekanisme switch-case untuk menghasilkan respons output yang sesuai.

Terdapat empat command yang digunakan sebagai penghubung antara logika game di master dengan output fisik di slave. Selama game berjalan, master mengirim command 0x01 sehingga LED hijau slave menyala sebagai indikator permainan aktif. Saat tombol ditekan dan dino melompat, master mengirim command 0x03 sehingga buzzer slave berbunyi selama 80ms sebagai efek suara lompat. Ketika posisi kaktus bertabrakan dengan posisi dino, master menetapkan status game over, menampilkan layar "GAME OVER" beserta high score pada OLED, lalu mengirim command 0x02 untuk menyalakan LED merah dan command 0x04 untuk membunyikan buzzer dengan pola bib-bib-biiib. Menekan tombol kembali saat game over akan mereset semua variabel dan permainan dimulai dari awal.








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

TUGAS BESAR

Astable Multivibrator D kecil dari 50%

MODUL 1