1. Prosedur [kembali]
1. Buat dua project baru pada STM32CubeIDE menggunakan mikrokontroler STM32 NUCLEO G474RE.
•Project_Master
•Project_Slave
2. Konfigurasi Project Master
a. Aktifkan I2C1 dengan pengaturan:
Mode: I2C
•Clock Speed: 100 kHz (Standard Mode)
•Addressing Mode: 7-bit
•Pin yang digunakan:
•PB6 → SCL
•PB7 → SDA
b. Aktifkan SPI1 dengan pengaturan:
•Mode: Full Duplex Master
•Direction: 2 Lines
•Data Size: 8-bit
•Clock Polarity: Low
•Clock Phase: 1 Edge
•NSS: Software
•Baudrate Prescaler: 16
•First Bit: MSB First
Pin yang digunakan:
•PA5 → SCK
•PA6 → MISO
•PA7 → MOSI
3. Konfigurasi Project Slave
a. Aktifkan SPI1 dengan pengaturan:
•Mode: Full Duplex Slave
•Direction: 2 Lines
•Data Size: 8-bit
•Clock Polarity: Low
•Clock Phase: 1 Edge
•NSS: Hardware Input
•First Bit: MSB First
Pin yang digunakan:
•PA5 → SCK
•PA6 → MISO
•PA7 → MOSI
•PA4 → NSS
b. I2C tidak digunakan pada Slave
4. Setelah seluruh konfigurasi selesai, lakukan Generate Code untuk masing-masing project.
•STM NUCLEO G474RE (x2)
•OLED
•Push button
•LED Green
•LED Red
•Jumper
•Breadboard
3. Rangkaian Simulasi dan Prinsip Kerja [kembali] Rangkaian pada gambar menunjukkan sistem komunikasi antara dua board mikrokontroler STM32 yang dikonfigurasikan sebagai MASTER dan SLAVE. Prinsip kerjanya dimulai ketika board MASTER mengirimkan data atau perintah ke board SLAVE melalui jalur komunikasi antar mikrokontroler (kemungkinan menggunakan UART, I2C, atau SPI berdasarkan koneksi pin yang terhubung). OLED display yang terhubung pada MASTER digunakan untuk menampilkan informasi atau status komunikasi. Push button pada breadboard berfungsi sebagai input, misalnya untuk mengirim perintah tertentu dari SLAVE atau memicu proses komunikasi. Ketika tombol ditekan, sinyal input dibaca oleh mikrokontroler lalu diproses dan dikirim ke board lainnya. LED merah dan hijau digunakan sebagai indikator kondisi sistem, misalnya LED hijau menyala saat komunikasi berhasil dan LED merah menyala ketika terjadi kesalahan atau kondisi tertentu. Buzzer berfungsi sebagai indikator suara untuk menandakan adanya event, seperti data diterima atau tombol ditekan. Secara keseluruhan, rangkaian ini bekerja dengan prinsip pertukaran data antar mikrokontroler yang kemudian menghasilkan output berupa tampilan OLED, nyala LED, dan bunyi buzzer sesuai program yang dibuat.
4. Flowchart dan Listing Program [kembali]


#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 */
#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]
Download Laporan Akhir (klik disini)
Komentar
Posting Komentar