1. Buat dua project baru menggunakan board STM32 NUCLEO-G474RE, yaitu Nucleo 1 dan Nucleo 2.
2. Pada
Nucleo 1, konfigurasi pin dan peripheral dengan mengaktifkan TIM2 CH1
pada PA0 sebagai PWM Generation CH1 menggunakan Internal Clock, aktifkan
I2C1 pada PA15 dan PB5, aktifkan USART1 mode Asynchronous pada PA9 dan
PA10, serta aktifkan pin PA1 dan PA4 sebagai GPIO Input.
3. Pada
Nucleo 2, konfigurasi TIM2 CH1 pada PA0 sebagai PWM Generation CH1,
aktifkan USART1 mode Asynchronous pada PA9 dan PA10, lalu aktifkan pin
PA1 dan PA4 sebagai GPIO Input.
4. Generate code untuk kedua project setelah seluruh konfigurasi selesai dilakukan.
5. Pada project Nucleo 1, buat file header baru pada folder Inc berupa main.h, ssd1306_conf.h, ssd1306_fonts.h, dan ssd1306.h.
6. Pada project Nucleo 1, buat file source baru pada folder Src berupa main.c, ssd1306_fonts.c, dan ssd1306.c.
Sistem
kontrol parkir otomatis dua pintu ini bekerja menggunakan dua buah
mikrokontroler STM32 Nucleo G474RE yang berfungsi sebagai pengendali
pintu masuk dan pintu keluar. Pada pintu masuk, sensor IR mendeteksi
keberadaan kendaraan yang datang, kemudian data dibaca oleh Nucleo 1
untuk memeriksa ketersediaan slot parkir. Jika slot masih tersedia,
servo akan membuka palang pintu masuk dan jumlah slot kosong pada OLED
akan diperbarui menjadi berkurang. Namun apabila slot parkir penuh, OLED
akan menampilkan informasi “parkir penuh” dan servo tetap dalam kondisi
tertutup sehingga kendaraan tidak dapat masuk.
Pada
pintu keluar, sensor IR kedua mendeteksi kendaraan yang keluar area
parkir dan sinyal diproses oleh Nucleo 2. Setelah kendaraan terdeteksi,
servo pintu keluar akan membuka palang agar kendaraan dapat keluar,
kemudian sistem menambahkan kembali jumlah slot kosong dan memperbarui
tampilan OLED. Kedua mikrokontroler saling berkomunikasi menggunakan
UART untuk sinkronisasi data jumlah slot parkir sehingga informasi
kapasitas parkir tetap sesuai kondisi aktual secara real-time.
/* USER CODE BEGIN Header */
/**
************************************************************
******************
* @file : main.c
* @brief : Master Parking System - STM32G474RE
************************************************************
******************
*/
/* USER CODE END Header */
/* Includes ------------------------------------------------
------------------*/
#include "main.h"
/* Private includes ----------------------------------------
------------------*/
/* USER CODE BEGIN Includes */
#define SSD1306_INCLUDE_FONT_7x10
#include "ssd1306.h"
#include "ssd1306_fonts.h"
#include
#include
/* USER CODE END Includes */
/* Private typedef -----------------------------------------
------------------*/
/* USER CODE BEGIN PTD */
/* USER CODE END PTD */
/* Private define ------------------------------------------
------------------*/
/* USER CODE BEGIN PD */
#define MAX_PARKIR 10
/* USER CODE END PD */
/* Private macro -------------------------------------------
------------------*/
/* USER CODE BEGIN PM */
/* USER CODE END PM */
/* Private variables ---------------------------------------
------------------*/
COM_InitTypeDef BspCOMInit;
I2C_HandleTypeDef hi2c1;
TIM_HandleTypeDef htim2;
UART_HandleTypeDef huart1; // komunikasi ke slave (PC4/PC5)
UART_HandleTypeDef huart2; // serial monitor via BSP COM1
(PA2/PA3)
/* USER CODE BEGIN PV */
uint8_t sisa_parkir = MAX_PARKIR;
uint8_t kendaraan_masuk = 0;
uint8_t uart_rx_buffer[1];
/* USER CODE END PV */
/* Private function prototypes -----------------------------
------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_I2C1_Init(void);
static void MX_TIM2_Init(void);
static void MX_USART1_UART_Init(void);
static void MX_USART2_UART_Init(void);
/* USER CODE BEGIN PFP */
void Update_Display(void);
void Servo_Buka(void);
void Servo_Tutup(void);
/* USER CODE END PFP */
/* USER CODE BEGIN 0 */
/* USER CODE END 0 */
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
MX_GPIO_Init();
MX_I2C1_Init();
MX_TIM2_Init();
MX_USART1_UART_Init();
MX_USART2_UART_Init();
/* USER CODE BEGIN 2 */
BSP_LED_Init(LED_GREEN);
BSP_PB_Init(BUTTON_USER, BUTTON_MODE_EXTI);
// Serial monitor via BSP COM1 (USART2 PA2/PA3)
BspCOMInit.BaudRate = 115200;
BspCOMInit.WordLength = COM_WORDLENGTH_8B;
BspCOMInit.StopBits = COM_STOPBITS_1;
BspCOMInit.Parity = COM_PARITY_NONE;
BspCOMInit.HwFlowCtl = COM_HWCONTROL_NONE;
if (BSP_COM_Init(COM1, &BspCOMInit) != BSP_ERROR_NONE) {
Error_Handler();
}
ssd1306_Init();
HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_1);
htim2.Instance->CCR1 = 1000;
// USART1 untuk komunikasi ke slave (PC4=TX, PC5=RX)
HAL_UART_Receive_IT(&huart1, uart_rx_buffer, 1);
printf("=== MASTER PARKING READY ===\r\n");
printf("Slot tersedia: %d/%d\r\n", sisa_parkir,
MAX_PARKIR);
Update_Display();
/* USER CODE END 2 */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
uint8_t ir =
!HAL_GPIO_ReadPin(MASTER_IR_SENSOR_GPIO_Port,
MASTER_IR_SENSOR_Pin);
printf("IR: %d | Sisa: %d\r\n", ir, sisa_parkir);
// DETEKSI MASUK
if (ir && sisa_parkir > 0 && !kendaraan_masuk) {
HAL_Delay(50);
ir = !HAL_GPIO_ReadPin(MASTER_IR_SENSOR_GPIO_Port,
MASTER_IR_SENSOR_Pin);
if (ir) {
Servo_Buka();
sisa_parkir--;
kendaraan_masuk = 1;
Update_Display();
printf(">> MASUK! Sisa: %d/%d\r\n", sisa_parkir,
MAX_PARKIR);
HAL_UART_Transmit(&huart1, (uint8_t*)"M", 1, 100);
}
}
// PARKIR PENUH
if (ir && sisa_parkir == 0 && !kendaraan_masuk) {
printf(">> PARKIR PENUH!\r\n");
BSP_LED_Toggle(LED_GREEN);
HAL_Delay(200);
}
// KENDARAAN SUDAH LEWAT
if (!ir && kendaraan_masuk) {
HAL_Delay(50);
ir = !HAL_GPIO_ReadPin(MASTER_IR_SENSOR_GPIO_Port,
MASTER_IR_SENSOR_Pin);
if (!ir) {
Servo_Tutup();
kendaraan_masuk = 0;
printf(">> Palang ditutup\r\n");
}
}
HAL_Delay(100);
}
/* USER CODE END 3 */
}
/* USER CODE BEGIN 4 */
void Update_Display(void) {
char buf[25];
ssd1306_Fill(Black);
/* USER CODE BEGIN Header */
/**
**************************************************************
****************
* @file : main.c
* @brief : Slave Parking System - STM32G474RE
(Pintu Keluar)
**************************************************************
****************
*/
/* USER CODE END Header */
/* Includes --------------------------------------------------
----------------*/
#include "main.h"
/* Private includes ------------------------------------------
----------------*/
/* USER CODE BEGIN Includes */
#include
#include
/* USER CODE END Includes */
/* Private typedef -------------------------------------------
----------------*/
/* USER CODE BEGIN PTD */
/* USER CODE END PTD */
/* Private define --------------------------------------------
----------------*/
/* USER CODE BEGIN PD */
/* USER CODE END PD */
/* Private macro ---------------------------------------------
----------------*/
/* USER CODE BEGIN PM */
/* USER CODE END PM */
/* Private variables -----------------------------------------
----------------*/
COM_InitTypeDef BspCOMInit;
TIM_HandleTypeDef htim2;
UART_HandleTypeDef huart1;
UART_HandleTypeDef huart2;
/* USER CODE BEGIN PV */
uint8_t kendaraan_keluar = 0;
uint8_t uart_rx_buffer[1];
/* USER CODE END PV */
/* Private function prototypes -------------------------------
----------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_TIM2_Init(void);
static void MX_USART1_UART_Init(void);
static void MX_USART2_UART_Init(void);
/* USER CODE BEGIN PFP */
void Servo_Buka(void);
void Servo_Tutup(void);
/* USER CODE END PFP */
/* USER CODE BEGIN 0 */
/* USER CODE END 0 */
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
MX_GPIO_Init();
MX_TIM2_Init();
MX_USART1_UART_Init();
MX_USART2_UART_Init();
/* USER CODE BEGIN 2 */
BSP_LED_Init(LED_GREEN);
BSP_PB_Init(BUTTON_USER, BUTTON_MODE_EXTI);
BspCOMInit.BaudRate = 115200;
BspCOMInit.WordLength = COM_WORDLENGTH_8B;
BspCOMInit.StopBits = COM_STOPBITS_1;
BspCOMInit.Parity = COM_PARITY_NONE;
BspCOMInit.HwFlowCtl = COM_HWCONTROL_NONE;
if (BSP_COM_Init(COM1, &BspCOMInit) != BSP_ERROR_NONE) {
Error_Handler();
}
HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_1);
htim2.Instance->CCR1 = 1000;
// USART2 RX interrupt - terima dari master
HAL_UART_Receive_IT(&huart1, uart_rx_buffer, 1);
HAL_GPIO_WritePin(LED_GREEN_GPIO_Port, LED_GREEN_Pin,
GPIO_PIN_RESET);
printf("=== SLAVE READY - Pintu Keluar ===\r\n");
/* USER CODE END 2 */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
uint8_t ir = !HAL_GPIO_ReadPin(SLAVE_IR_SENSOR_GPIO_Port,
SLAVE_IR_SENSOR_Pin);
printf("IR: %d\r\n", ir);
// === DETEKSI KENDARAAN KELUAR ===
if (ir && !kendaraan_keluar) {
HAL_Delay(50);
ir = !HAL_GPIO_ReadPin(SLAVE_IR_SENSOR_GPIO_Port,
SLAVE_IR_SENSOR_Pin);
if (ir) {
Servo_Buka();
// 1. buka palang
kendaraan_keluar = 1;
// 2. set flag
HAL_UART_Transmit(&huart1, (uint8_t*)"K", 1, 100); //
3. kirim ke master
HAL_GPIO_WritePin(LED_GREEN_GPIO_Port, LED_GREEN_Pin,
GPIO_PIN_SET);
printf(">> KELUAR! Kuota +1 dikirim ke master\r\n");
}
}
// === KENDARAAN SUDAH LEWAT ===
if (!ir && kendaraan_keluar) {
HAL_Delay(50);
ir = !HAL_GPIO_ReadPin(SLAVE_IR_SENSOR_GPIO_Port,
SLAVE_IR_SENSOR_Pin);
if (!ir) {
Servo_Tutup();
kendaraan_keluar = 0;
HAL_GPIO_WritePin(LED_GREEN_GPIO_Port, LED_GREEN_Pin,
GPIO_PIN_RESET);
printf(">> Palang ditutup, siap kendaraan
berikutnya\r\n");
}
}
HAL_Delay(100);
}
/* USER CODE END 3 */
}
/* USER CODE BEGIN 4 */
void Servo_Buka(void) {
htim2.Instance->CCR1 = 2000;
HAL_Delay(600);
}
void Servo_Tutup(void) {
htim2.Instance->CCR1 = 1000;
HAL_Delay(600);
}
// Terima info dari master via USART2
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
if (huart->Instance == USART1)
{
if (uart_rx_buffer[0] == 'M')
{
printf(">> INFO: KENDARAAN MASUK (MASTER)\r\n");
}
UART
(Universal Asynchronous Receiver-Transmitter) adalah bagian perangkat
keras komputer yang menerjemahkan antara bit-bit paralel data dan
bit-bit serial. UART biasanya berupa sirkuit terintegrasi yang digunakan
untuk komunikasi serial pada komputer atau port serial perangkat
periperal.
Cara Kerja Komunikasi UART
Gambar 1. Cara Kerja Komunikasi UART
4.2 I2C (Inter-Intergrated Circuit)
Inter
Integrated Circuit atau sering disebut I2C adalah standar komunikasi
serial dua arah menggunakan dua saluran yang didisain khusus untuk
mengirim maupun menerima data. Sistem I2C terdiri dari saluran SCL
(Serial Clock) dan SDA (Serial Data) yang membawa informasi data antara
I2C dengan pengontrolnya.
Cara Kerja Komunikasi I2C
Gambar 2. Cara Kerja Komunikasi I2C
Pada
I2C, data ditransfer dalam bentuk message yang terdiri dari kondisi
start, Address Frame, R/W bit, ACK/NACK bit, Data Frame 1, Data Frame 2,
dan kondisi Stop. Kondisi start dimana saat pada SDA beralih dari
logika high ke low sebelum SCL. Kondisi stop dimana saat pada SDA
beralih dari logika low ke high sebelum SCL.
R/W
bit berfungsi untuk menentukan apakah master mengirim data ke slave
atau meminta data dari slave. (logika 0 = mengirim data ke slave, logika
1 = meminta data dari slave) ACK/NACK bit berfungsi sebagai pemberi
kabar jika data frame ataupun address frame telah diterima receiver.
4.3 SPI (Series Peripheral Interface)
Serial
Peripheral Interface (SPI) merupakan salah satu mode komunikasi serial
synchronous berkecepatan tinggi yang dimiliki oleh STM32F407VGT6 dan
Raspberry Pi Pico. Komunikasi SPI membutuhkan 3 jalur utama yaitu MOSI,
MISO, dan SCK, serta jalur tambahan SS/CS. Melalui komunikasi ini, data
dapat saling dikirimkan baik antara mikrokontroler maupun antara
mikrokontroler dengan perangkat periferal lainnya.
• MOSI (Master Output Slave Input)
Jika dikonfigurasi sebagai master, maka pin MOSI berfungsi sebagai
output. Sebaliknya, jika dikonfigurasi sebagai slave, maka pin MOSI
berfungsi sebagai input.
• MISO (Master Input Slave Output)
Jika dikonfigurasi sebagai master, maka pin MISO berfungsi sebagai
input. Sebaliknya, jika dikonfigurasi sebagai slave, maka pin MISO
berfungsi sebagai output.
• SCLK (Serial Clock)
Jika dikonfigurasi sebagai master, maka pin SCLK bertindak sebagai
output untuk memberikan sinyal clock ke slave. Sebaliknya, jika
dikonfigurasi sebagai slave, maka pin SCLK berfungsi sebagai input untuk
menerima sinyal clock dari master.
• SS/CS (Slave Select/Chip Select)
Jalur ini digunakan oleh master untuk memilih slave yang akan
dikomunikasikan. Pin SS/CS harus dalam keadaan aktif (umumnya logika
rendah) agar komunikasi dengan slave dapat berlangsung.
Cara Kerja Komunikasi SPI
Gambar 3. Cara Kerja Komunikasi SPI
Sinyal clock dialirkan dari
master ke slave yang berfungsi untuk sinkronisasi. Master dapat memilih
slave mana yang akan dikirimkan data melalui slave select, kemudian data
dikirimkan dari master ke slave melalui MOSI. Jika master butuh respon
data maka slave akan mentransfer data ke master melalui MISO.
4.4 STM32 NUCLEO G474RE
STM32
NUCLEO-G474RE merupakan papan pengembangan (development board) berbasis
mikrokontroler STM32G474RET6 yang dikembangkan oleh STMicroelectronics.
Board ini dirancang untuk memudahkan proses pembelajaran, pengujian,
dan pengembangan aplikasi sistem tertanam (embedded system), baik untuk
pemula maupun tingkat lanjut. STM32 Nucleo-G474RE mengintegrasikan
antarmuka ST-LINK debugger/programmer secara onboard sehingga pengguna
dapat langsung melakukan pemrograman dan debugging tanpa perangkat
tambahan.
Adapun spesifikasi dari STM32 NUCLEO-G474RE adalah sebagai berikut:
Gambar 2. STM32 Nucleo G474RE
Gambar 3. PinOut STM32 Nucleo G474RE
4.5 STM32F103C8
STM32F103C8
adalah mikrokontroler berbasis ARM Cortex-M3 yang dikembangkan oleh
STMicroelectronics. Mikrokontroler ini sering digunakan dalam
pengembangan sistem tertanam karena kinerjanya yang baik, konsumsi daya
yang rendah, dan kompatibilitas dengan berbagai protokol komunikasi.
Pada praktikum ini, kita menggunakan STM32F103C8 yang dapat diprogram
menggunakan berbagai metode, termasuk komunikasi serial (USART), SWD
(Serial Wire Debug), atau JTAG untuk berhubungan dengan komputer maupun
perangkat lain. Adapun spesifikasi dari STM32F4 yang digunakan dalam
praktikum ini adalah sebagai berikut:
Gambar 4. STM32F103C8
Gambar 5. Pinout Stm32 F103C8T6
A. BAGIAN-BAGIAN PENDUKUNG
1.4.1 STM32 NUCLEOG474RE
RAM (Random Access Memory)
RAM (Random Access Memory) pada STM32 NUCLEO-G474RE digunakan sebagai
memori sementara untuk menyimpan data selama program berjalan.
Mikrokontroler STM32G474RET6 memiliki RAM sebesar 128 KB yang berfungsi
untuk menyimpan variabel, buffer data, stack, dan heap.
Memori Flash Eksternal STM32
NUCLEO-G474RE tidak menggunakan memori flash eksternal. Seluruh program
dan data permanen disimpan pada memori Flash internal mikrokontroler
STM32G474RET6 dengan kapasitas 512 KB. Memori flash ini bersifat
non-volatile, sehingga data dan program tetap tersimpan meskipun catu
daya dimatikan.
Crystal Oscillator
STM32 NUCLEO-G474RE menggunakan osilator internal (HSI – High Speed
Internal) sebagai sumber clock utama secara default. Penggunaan clock
internal ini membuat board dapat beroperasi tanpa memerlukan crystal
oscillator eksternal. Clock berfungsi sebagai sumber waktu untuk
mengatur kecepatan kerja CPU dan seluruh peripheral.
Regulator Tegangan
Untuk memastikan pasokan tegangan yang stabil ke mikrokontroler.
Pin GPIO (General Purpose Input/Output):
Pin GPIO pada STM32 NUCLEO-G474RE digunakan sebagai antarmuka input dan output digital yang fleksibel.
1.4.2 STM32 F103C8
RAM (Random Access Memory)
STM32F103C8 dilengkapi dengan 20KB SRAM on-chip. Kapasitas RAM ini
memungkinkan mikrokontroler menjalankan berbagai aplikasi serta
menyimpan data sementara selama eksekusi program.
Memori Flash Internal
STM32F103C8 memiliki memori flash internal sebesar 64KB atau 128KB, yang
digunakan untuk menyimpan firmware dan program pengguna. Memori ini
memungkinkan penyimpanan kode program secara permanen tanpa memerlukan
media penyimpanan eksternal.
Crystal Oscillator
STM32F103C8 menggunakan crystal oscillator eksternal (biasanya 8MHz)
yang bekerja dengan PLL untuk meningkatkan frekuensi clock hingga 72MHz.
Sinyal clock yang stabil ini penting untuk mengatur kecepatan operasi
mikrokontroler dan komponen lainnya.
Regulator Tegangan
STM32F103C8 memiliki sistem pengaturan tegangan internal yang memastikan
pasokan daya stabil ke mikrokontroler. Tegangan operasi yang didukung
berkisar antara 2.0V hingga 3.6V.
Pin GPIO (General Purpose Input/Output)
STM32F103C8 memiliki hingga 37 pin GPIO yang dapat digunakan untuk
menghubungkan berbagai perangkat eksternal seperti sensor, motor, LED,
serta komunikasi dengan antarmuka seperti UART, SPI, dan I²C.