1. Prosedur [Kembali]
Siapkan alat dan bahan seperti, STM32 Bluepill, PIR Sensor, Sensor LDR, push button, LED, Fan, resistor, breadboard, dan jumper. Rangkai komponen sesuai gambar rangkaian pada modul serta hubungkan komunikasi SPI antara 2 Bluepill. Buka STM32CubeIDE lalu buat project. Lakukan konfigurasi GPIO dan SPI sesuai pengaturan pada modul kemudian Generate Code. Masukkan listing program transmitter pada project Bluepill dan listing program receiver pada project Bluepill sesuai modul. Hubungkan kedua board STM32 ke laptop menggunakan kabel USB. Build dan Run program pada STM32CubeIDE. Uji LDR Sensor dan button dan amati kondisi fan dan LED apakah bekerja sesuai program.
2. Hardware dan Diagram Blok [Kembali]
Hardware
STM32 NUCLEO G474RE
Sensor LDR
Push button
LED
Fan
Jumper
Breadboard
Blok Diagram
3. Rangkaian Simulasi dan Prinsip Kerja [Kembali]
Rangkaian Simulasi
Prinsip Kerja
Rangkaian pada gambar bekerja sebagai sistem pendeteksi objek berbasis mikrokontroler STM32 yang menggunakan dua sensor inframerah (IR), dua motor servo, dan OLED display sebagai penampil informasi. Kedua sensor IR berfungsi untuk mendeteksi keberadaan objek di depan sensor. Ketika objek terdeteksi, sensor akan mengirimkan sinyal input ke pin GPIO pada STM32. Data dari sensor kemudian diproses oleh mikrokontroler untuk menentukan aksi yang akan dilakukan oleh motor servo. Servo akan bergerak sesuai program yang telah ditanamkan, misalnya untuk membuka dan menutup penghalang atau menggerakkan mekanisme tertentu secara otomatis.
Selain itu, OLED display digunakan untuk menampilkan status sistem, seperti kondisi sensor, jumlah objek yang terdeteksi, atau informasi proses lainnya. Komunikasi OLED dengan STM32 dilakukan melalui jalur I2C sehingga hanya membutuhkan dua jalur data utama, yaitu SDA dan SCL. Breadboard pada rangkaian digunakan sebagai media distribusi tegangan dan penghubung antar komponen agar rangkaian lebih rapi. Seluruh sistem mendapatkan catu daya dari sumber tegangan yang terhubung ke rangkaian sehingga sensor, servo, OLED, dan STM32 dapat bekerja secara bersamaan sesuai fungsi yang telah diprogram.
4. Flowchart dan Listing Program [Kembali]
Flowchart
Listing Program
- Master
/* 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 <stdio.h>
#include <string.h>
/* 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);
ssd1306_SetCursor(2, 0);
ssd1306_WriteString("SISTEM PARKIR", Font_7x10, White);
ssd1306_SetCursor(2, 14);
sprintf(buf, "Slot: %d/%d", sisa_parkir, MAX_PARKIR);
ssd1306_WriteString(buf, Font_7x10, White);
ssd1306_SetCursor(2, 28);
if (sisa_parkir == 0) {
ssd1306_WriteString(">> PENUH <<", Font_7x10, White);
} else {
ssd1306_WriteString(">> TERSEDIA <<", Font_7x10, White);
}
ssd1306_UpdateScreen();
}
void Servo_Buka(void) {
htim2.Instance->CCR1 = 2000;
HAL_Delay(600);
}
void Servo_Tutup(void) {
htim2.Instance->CCR1 = 1000;
HAL_Delay(600);
}
// Terima dari slave via USART1 (PC5=RX)
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
if (huart->Instance == USART1)
{
if (uart_rx_buffer[0] == 'K')
{
if(sisa_parkir < MAX_PARKIR) sisa_parkir++;
printf(">> KENDARAAN KELUAR (SLAVE)\r\n");
printf(">> Sisa: %d/%d\r\n", sisa_parkir, MAX_PARKIR);
Update_Display();
}
HAL_UART_Receive_IT(&huart1, uart_rx_buffer, 1);
}
}
/* USER CODE END 4 */
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
HAL_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE1_BOOST);
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();
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();
}
static void MX_I2C1_Init(void)
{
hi2c1.Instance = I2C1;
hi2c1.Init.Timing = 0x40B285C2;
hi2c1.Init.OwnAddress1 = 0;
hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
hi2c1.Init.OwnAddress2 = 0;
hi2c1.Init.OwnAddress2Masks = I2C_OA2_NOMASK;
hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
if (HAL_I2C_Init(&hi2c1) != HAL_OK) Error_Handler();
if (HAL_I2CEx_ConfigAnalogFilter(&hi2c1, I2C_ANALOGFILTER_ENABLE) != HAL_OK) Error_Handler();
if (HAL_I2CEx_ConfigDigitalFilter(&hi2c1, 0) != HAL_OK) Error_Handler();
}
static void MX_TIM2_Init(void)
{
TIM_ClockConfigTypeDef sClockSourceConfig = {0};
TIM_MasterConfigTypeDef sMasterConfig = {0};
TIM_OC_InitTypeDef sConfigOC = {0};
htim2.Instance = TIM2;
htim2.Init.Prescaler = 169;
htim2.Init.CounterMode = TIM_COUNTERMODE_UP;
htim2.Init.Period = 19999;
htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
if (HAL_TIM_Base_Init(&htim2) != HAL_OK) Error_Handler();
sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
if (HAL_TIM_ConfigClockSource(&htim2, &sClockSourceConfig) != HAL_OK) Error_Handler();
if (HAL_TIM_PWM_Init(&htim2) != HAL_OK) Error_Handler();
sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
if (HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig) != HAL_OK) Error_Handler();
sConfigOC.OCMode = TIM_OCMODE_PWM1;
sConfigOC.Pulse = 1000;
sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
if (HAL_TIM_PWM_ConfigChannel(&htim2, &sConfigOC, TIM_CHANNEL_1) != HAL_OK) Error_Handler();
HAL_TIM_MspPostInit(&htim2);
}
static void MX_USART1_UART_Init(void)
{
// USART1 - komunikasi ke slave (PC4=TX, PC5=RX) 9600 baud
huart1.Instance = USART1;
huart1.Init.BaudRate = 9600;
huart1.Init.WordLength = UART_WORDLENGTH_8B;
huart1.Init.StopBits = UART_STOPBITS_1;
huart1.Init.Parity = UART_PARITY_NONE;
huart1.Init.Mode = UART_MODE_TX_RX;
huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
huart1.Init.OverSampling = UART_OVERSAMPLING_16;
huart1.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;
huart1.Init.ClockPrescaler = UART_PRESCALER_DIV1;
huart1.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
if (HAL_UART_Init(&huart1) != HAL_OK) Error_Handler();
if (HAL_UARTEx_SetTxFifoThreshold(&huart1, UART_TXFIFO_THRESHOLD_1_8) != HAL_OK) Error_Handler();
if (HAL_UARTEx_SetRxFifoThreshold(&huart1, UART_RXFIFO_THRESHOLD_1_8) != HAL_OK) Error_Handler();
if (HAL_UARTEx_DisableFifoMode(&huart1) != HAL_OK) Error_Handler();
}
static void MX_USART2_UART_Init(void)
{
// USART2 - serial monitor via BSP COM1 (PA2=TX, PA3=RX)
huart2.Instance = USART2;
huart2.Init.BaudRate = 115200;
huart2.Init.WordLength = UART_WORDLENGTH_8B;
huart2.Init.StopBits = UART_STOPBITS_1;
huart2.Init.Parity = UART_PARITY_NONE;
huart2.Init.Mode = UART_MODE_TX_RX;
huart2.Init.HwFlowCtl = UART_HWCONTROL_NONE;
huart2.Init.OverSampling = UART_OVERSAMPLING_16;
huart2.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;
huart2.Init.ClockPrescaler = UART_PRESCALER_DIV1;
huart2.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
if (HAL_UART_Init(&huart2) != HAL_OK) Error_Handler();
if (HAL_UARTEx_SetTxFifoThreshold(&huart2, UART_TXFIFO_THRESHOLD_1_8) != HAL_OK) Error_Handler();
if (HAL_UARTEx_SetRxFifoThreshold(&huart2, UART_RXFIFO_THRESHOLD_1_8) != HAL_OK) Error_Handler();
if (HAL_UARTEx_DisableFifoMode(&huart2) != HAL_OK) Error_Handler();
}
static void MX_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
__HAL_RCC_GPIOC_CLK_ENABLE();
__HAL_RCC_GPIOF_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
// IR sensor PA1 - aktif LOW → PULLUP
GPIO_InitStruct.Pin = MASTER_IR_SENSOR_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_PULLUP;
HAL_GPIO_Init(MASTER_IR_SENSOR_GPIO_Port, &GPIO_InitStruct);
// USART1 TX=PC4, RX=PC5 untuk komunikasi ke slave
GPIO_InitStruct.Pin = MASTER_TX_Pin | MASTER_RX_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
GPIO_InitStruct.Alternate = GPIO_AF7_USART1;
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
}
void Error_Handler(void)
{
__disable_irq();
while (1) {}
}
#ifdef USE_FULL_ASSERT
void assert_failed(uint8_t *file, uint32_t line) {}
#endif
5. Video Demo [Kembali]
VIDEO