lap akhir m3


[menuju akhir]

1. Prosedur [Kembali ke Atas]

Langkah-langkah percobaan :

  1. Pahami terlebih dahulu kondisi yang akan digunakan
  2. Persiapkan alat dan bahan
  3. Buat rangkaian sesuai dengan kondisi dan modul
  4. Buka software STM32Cube IDE 
  5. Setelah membuka software, pilih perangkat STMG474RE
  6. Sesuaikan konfigurasi pin sesuai dengan rangkaian modul
  7. Buat kode program untuk mengoperasikan rangkaian tersebut sesuai dengan kondisi 
  8. Konfigurasi kan program dengan software STM32Cube IDE 
  9. Jalankan simulasi rangkaian.  
  10. Proses selesai

2. Hardware dan Diagram Blok [Kembali ke Atas]

a. Hardware

STM32 NUCLEO-G474RE

OLED

LED

Push Button

Buzzer

Breadboard

b. Diagram Blok


3. Rangkaian Simulasi dan Prinsip Kerja [Kembali ke Atas]

Pada rangkaian permainan Geometry Jump ini digunakan dua mikrokontroler STM32 yang saling terhubung melalui komunikasi I2C dengan sistem master dan slave. STM32 master berperan sebagai pusat pengendali permainan, sedangkan STM32 slave berfungsi menerima data sekaligus mengatur perangkat keluaran seperti LED dan buzzer. Ketika sistem dinyalakan, kedua mikrokontroler terlebih dahulu melakukan inisialisasi GPIO, komunikasi I2C, serta perangkat input-output yang digunakan. Pada sisi master, OLED dimanfaatkan untuk menampilkan tampilan permainan sederhana, sementara push button digunakan sebagai kontrol untuk menjalankan aksi lompatan karakter. Jalur SDA dan SCL yang menghubungkan kedua STM32 memungkinkan proses pertukaran data berlangsung secara sinkron. Seluruh rangkaian juga menggunakan sumber daya yang sama agar komunikasi dan respons perangkat tetap stabil selama permainan berjalan.

Cara kerja permainan dimulai saat push button ditekan untuk memulai game. Master kemudian mengirimkan data “game run” ke slave melalui komunikasi I2C. Setelah data diterima, slave menyalakan LED hijau sebagai indikator bahwa permainan sedang berlangsung, sementara LED merah tetap mati. Ketika pemain menekan tombol untuk melompat, master membaca input tersebut lalu mengirimkan perintah “jump” ke slave. Setelah menerima data, slave mengaktifkan buzzer sebagai efek suara lompatan agar sesuai dengan gerakan karakter pada permainan. Selama game berlangsung, master terus menjalankan logika permainan seperti pergerakan karakter dan pendeteksian rintangan yang ditampilkan pada OLED. Pertukaran data antara kedua STM32 dilakukan secara terus-menerus sehingga kondisi permainan pada master dan indikator pada slave dapat tetap sinkron secara real-time.

Apabila karakter menabrak rintangan atau pemain gagal melakukan lompatan dengan benar, master akan mendeteksi kondisi game over dan mengirimkan informasi tersebut ke slave melalui jalur I2C. Setelah data diterima, slave mematikan LED hijau dan menyalakan LED merah sebagai tanda permainan berakhir, kemudian buzzer juga diaktifkan untuk memberikan notifikasi suara. Sebaliknya, jika tombol tidak ditekan selama permainan, master akan mengirimkan logika “0” sehingga slave tidak mengaktifkan buzzer dan permainan tetap berjalan normal. Flowchart pada sisi master menunjukkan bahwa seluruh proses utama seperti memulai permainan, aksi lompatan, hingga deteksi tabrakan diproses terlebih dahulu oleh master sebelum diteruskan ke slave. Sementara itu, flowchart slave hanya berfungsi sebagai penerima data dan pengendali output sesuai instruksi dari master. Dengan pembagian tugas tersebut, komunikasi I2C mampu membuat sistem permainan bekerja lebih teratur, responsif, dan sinkron antara pengolah data serta perangkat output.

4. Flowchart dan Listing Program [Kembali ke Atas]

a. Flowchart


b. 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 ke Atas]


6. Analisa [Kembali ke Atas]




7. Download File [Kembali ke Atas]


Komentar

Postingan Populer