Laporan Akhir Modul 3




Laporan Akhir Modul 3

1. Prosedur[Kembali]

  1.  Siapkan alat dan bahan yang digunakan
  2. Buat project master dan slave pada STM32CubeIDE
  3. Hubungkan rangkaian komunikasi SPI antara Master dan Slave
  4. Hubungkan OLED SSD1306 ke board Master menggunakan komunikasi I2C
  5. Hubungkan push button ke pin input GPIO pada board Master sebagai kontrol permainan.
  6. Lakukan konfigurasi pada STM32CubeMX untuk Project Master
  7. Lakukan konfigurasi pada STM32CubeMX untuk Project Slave
  8. Generate code untuk masing-masing project.
  9. Tambahkan library SSD1306 pada Project Master untuk menampilkan game pada OLED.
  10. Buat program permainan Geometry Jump pada Master
  11. Buat program komunikasi SPI
  12. Compile program dan upload kode ke masing-masing board STM32.
  13. Nyalakan sistem dan amati tampilan game pada OLED.
  14. Tekan push button untuk memainkan karakter agar melompati obstacle.
  15. Amati proses komunikasi data SPI antara Master dan Slave selama permainan berlangsung.

2. Hardware dan Diagram Blok[Kembali]

  • Hardware
STM NUCLEO G474RE 
Mengupload: 661264 dari 661264 byte diupload.

OLED


Push button

 


LED

 Jumper

Breadboard


  •  Diagram Blog
 

3. Rangkaian Simulasi[Kembali]


Prinsip Kerja

Percobaan Game Geometry Jump menggunakan dua buah mikrokontroler STM32 yang berkomunikasi menggunakan protokol SPI dan tampilan OLED yang menggunakan komunikasi I2C. Sistem terdiri dari STM32 Master sebagai pengendali utama permainan dan STM32 Slave sebagai penerima data komunikasi.

Saat sistem dinyalakan, STM32 Master akan melakukan inisialisasi GPIO, SPI, dan I2C. OLED SSD1306 diinisialisasi menggunakan komunikasi I2C untuk menampilkan tampilan permainan. Push button digunakan sebagai input pemain untuk mengontrol karakter agar dapat melompat.

Pada kondisi awal, karakter game tampil pada layar OLED bersama obstacle yang bergerak dari kanan ke kiri layar. Ketika push button ditekan, STM32 Master membaca input tersebut lalu mengubah posisi karakter menjadi melompat. Jika tombol tidak ditekan, karakter kembali turun akibat simulasi gravitasi sederhana.

Selama permainan berlangsung, STM32 Master terus memperbarui tampilan OLED melalui komunikasi I2C sehingga animasi game dapat terlihat bergerak secara real-time. Master juga melakukan pengecekan collision antara karakter dan obstacle. Jika karakter mengenai obstacle, permainan dinyatakan game over.

Selain mengontrol tampilan game, STM32 Master juga mengirimkan data tertentu ke STM32 Slave menggunakan komunikasi SPI. Data yang dikirim dapat berupa status permainan, score, atau kondisi game over. Dalam komunikasi SPI, Master bertindak sebagai pengendali clock dan pengirim data, sedangkan Slave hanya menerima data dari Master.

STM32 Slave menerima data SPI melalui pin MOSI dan memproses data yang diterima sesuai program yang dibuat. Dengan demikian, komunikasi SPI dan I2C dapat bekerja bersamaan dalam satu sistem permainan Geometry Jump.


4. Flowchart dan Listing Program[Kembali]

  • Flowchart
Logika Game 

Master


Slave


  • Listing Program

#include "main.h"
#include "stm32g4xx_hal_i2c.h"
/* Private variables ---------------------------------------------------------*/
I2C_HandleTypeDef hi2c1;
#define SSD1306_I2C_PORT hi2c1
/* Variabel Game */
int dinoY = GROUND_Y;
int velocityY = 0;
const int gravity = 2;
uint8_t isJumping = 0;
int cactusX = 128;
uint32_t score = 0;
char scoreBuf[10];
uint8_t gameOver = 0;
uint32_t highScore = 0;

/* Private function prototypes -----------------------------------------------*/
void ResetGame(void);

int main(void)
{
  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();
  SystemClock_Config();

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_I2C1_Init();

  /* USER CODE BEGIN 2 */
  ssd1306_Init();
  ssd1306_Fill(Black);
  ssd1306_UpdateScreen();
  /* USER CODE END 2 */

  while (1)
  {
    if (!gameOver)
    {
      /* 1. Input Handling (Pull-up: LOW = Pressed) */
      if (HAL_GPIO_ReadPin(JUMP_BTN_GPIO_Port, JUMP_BTN_Pin) == GPIO_PIN_RESET && !isJumping)
      {
        velocityY = -12;
        isJumping = 1;
      }

      /* 2. Physics Update */
      dinoY += velocityY;
      velocityY += gravity;

      if (dinoY >= GROUND_Y)
      {
        dinoY = GROUND_Y;
        isJumping = 0;
        velocityY = 0;
      }

      /* 3. Obstacle Update */
      cactusX -= 6;
      if (cactusX < -10)
      {
        cactusX = 128;
        score++;
      }

      /* 4. Collision Detection */
      // Hitbox sederhana: Jika kaktus berada di area Dino dan Dino tidak cukup tinggi
      if (cactusX < 25 && cactusX > 5 && (dinoY + DINO_HEIGHT) > 48)
      {
        gameOver = 1;
      }

      /* 5. Rendering */
      ssd1306_Fill(Black);

      // Menggambar Dino (Kotak)
      ssd1306_DrawRectangle(10, dinoY, 10 + DINO_WIDTH, dinoY + DINO_HEIGHT, White);

      // Menggambar Kaktus (Isi penuh)
      ssd1306_FillRectangle(cactusX, 48, cactusX + 8, 60, White);

      // Garis Tanah
      ssd1306_Line(0, 61, 127, 61, White);

      // Menampilkan Score
      sprintf(scoreBuf, "Score: %lu", score);
      ssd1306_SetCursor(0, 0);
      ssd1306_WriteString(scoreBuf, Font_7x10, White);

      ssd1306_UpdateScreen();
    }
    else
    {
        char hsBuf[20];

        ssd1306_Fill(Black);

        ssd1306_SetCursor(35, 25);
        ssd1306_WriteString("GAME OVER", Font_7x10, White);

        ssd1306_SetCursor(20, 10);
        sprintf(hsBuf, "HighScore: %lu", highScore);
        ssd1306_WriteString(hsBuf, Font_7x10, White);

        ssd1306_UpdateScreen();

        // Update high score
        if (score > highScore)
        {
            highScore = score;
        }

        // restart
        if (HAL_GPIO_ReadPin(JUMP_BTN_GPIO_Port, JUMP_BTN_Pin) == GPIO_PIN_RESET)
        {
            ResetGame();
            HAL_Delay(300);
        }
    }

  }
}
void ResetGame(void)
{
  dinoY = GROUND_Y;
  velocityY = 0;
  isJumping = 0;
  cactusX = 128;
  score = 0;
  gameOver = 0;
}



void MX_I2C1_Init(void)
{
  hi2c1.Instance = I2C1;
  hi2c1.Init.Timing = 0x00303D5D;
  hi2c1.Init.OwnAddress1 = 0;
  hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
  hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLED;
  hi2c1.Init.OwnAddress2 = 0;
  hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLED;
  hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLED;

  if (HAL_I2C_Init(&hi2c1) != HAL_OK)
  {
    Error_Handler();
  }
}

void MX_GPIO_Init(void)
{
  GPIO_InitTypeDef GPIO_InitStruct = {0};

  __HAL_RCC_GPIOA_CLK_ENABLE();

  /* Konfigurasi PA0 sebagai Input Pull-up */
  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);
}

void Error_Handler(void)
{
  __disable_irq();
  while (1) {}
}
void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

  /** Configure the main internal regulator output voltage
  */
  HAL_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE1);

  /** Initializes the RCC Oscillators
  */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI;
  RCC_OscInitStruct.PLL.PLLM = RCC_PLLM_DIV4;
  RCC_OscInitStruct.PLL.PLLN = 85;
  RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
  RCC_OscInitStruct.PLL.PLLQ = RCC_PLLQ_DIV2;
  RCC_OscInitStruct.PLL.PLLR = RCC_PLLR_DIV2;

  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }

  /** Initializes the CPU, AHB and APB buses clocks
  */
  RCC_ClkInitStruct.ClockType =
      RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK|
      RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;

  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_4) != HAL_OK)
  {
    Error_Handler();
  }
}

5. Video Demo[Kembali]


Komentar

Postingan populer dari blog ini