2. Buat program untuk mikrokontroler STM32F103C8 di software STM32 CubeIDE.
3. Compile program dalam format hex, lalu upload ke dalam mikrokontroler.
4. Setelah program selesai di upload, jalankan simulasi rangkaian pada proteus.
2. Hardware dan Diagram Blok[Kembali]
A. Hardware
3. Rangkaian Simulasi[Kembali]
- Rangkaian sebelum di running
- Rangkaian setelah di running
- Prinsip Kerja
Sistem ini dirancang untuk membaca nilai potensiometer melalui ADC (Analog-to-Digital Converter) pada STM32, kemudian mengatur kecepatan motor DC dan status buzzer berdasarkan threshold yang ditentukan. Potensiometer menghasilkan sinyal analog yang diubah menjadi nilai digital 12-bit (rentang 0-4095) oleh ADC. Mikrokontroler secara kontinu memantau nilai ini dan membandingkannya dengan dua batasan: 1800 sebagai batas bawah dan 3200 sebagai batas atas.
Jika nilai ADC kurang dari 1800, sistem akan mengaktifkan motor DC dengan kecepatan sedang (duty cycle PWM 50%) dan mengaktifkan buzzer dengan frekuensi tinggi. Sebaliknya, jika nilai ADC melebihi 3200, motor akan berputar lebih cepat (duty cycle 70%) sementara buzzer dimatikan. Untuk nilai di antara kedua threshold tersebut, sistem mempertahankan kondisi sebelumnya hingga ada perubahan pembacaan.
Motor DC dikendalikan menggunakan sinyal PWM dari timer STM32. Duty cycle PWM diatur dengan mengubah nilai register compare yang terkait dengan channel timer. Misalnya, untuk menghasilkan duty cycle 50% pada frekuensi 1 kHz, periode timer diatur ke 1000 ticks dan pulse di-set ke 500. Buzzer yang memerlukan frekuensi tinggi (misalnya 4 kHz) diatur menggunakan channel timer terpisah dengan periode 250 ticks, dimana duty cycle 50% dicapai dengan pulse 125.
Implementasi hardware memerlukan driver eksternal seperti L298N atau MOSFET untuk motor DC karena keterbatasan kemampuan arus GPIO STM32. Buzzer yang digunakan harus bertipe passive agar bisa dikontrol dengan PWM. Pada sisi software, pembacaan ADC dilakukan dalam mode continuous conversion untuk memastikan pembaruan nilai yang real-time, dengan tambahan filter software seperti moving average untuk mengurangi noise.
Kode program utama terdiri dari inisialisasi peripheral (ADC, timer PWM) dan loop tak terbatas yang membaca nilai ADC, kemudian menyesuaikan PWM sesuai kondisi threshold. Library HAL STM32 digunakan untuk menyederhanakan konfigurasi register hardware. Delay kecil ditambahkan antara setiap iterasi untuk memberikan waktu stabilisasi sistem dan menghindari fluktuasi respons yang terlalu cepat.
Faktor penting yang perlu diperhatikan meliputi pemilihan sumber daya yang memadai untuk mensuplai motor, isolasi rangkaian daya digital dan analog untuk mengurangi noise, serta penyesuaian pin dan timer sesuai dengan mapping pin pada board STM32 yang digunakan. Jika menggunakan buzzer aktif, strategi kontrol perlu diubah menjadi sinyal ON/OFF sederhana karena buzzer jenis ini tidak responsif terhadap PWM.
4. Flowchart dan Listing Program[Kembali]
#include "main.h"
ADC_HandleTypeDef hadc1;
TIM_HandleTypeDef htim1;
TIM_HandleTypeDef htim2;
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_ADC1_Init(void);
static void MX_TIM1_Init(void);
static void MX_TIM2_Init(void);
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_ADC1_Init();
MX_TIM1_Init();
MX_TIM2_Init();
HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1); // Motor PWM
HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_3); // Buzzer PWM
HAL_ADC_Start(&hadc1);
uint8_t buzzer_enabled = 1;
uint32_t last_buzzer_change = 0;
uint8_t buzzer_freq_index = 0;
const uint32_t buzzer_periods[] = {143999, 71999, 47999}; // Frekuensi berbeda
// Threshold (dari rendah → sedang → tinggi)
const uint16_t THRESH_LOW = 1800;
const uint16_t THRESH_MID = 3200;
while (1)
{
HAL_ADC_Start(&hadc1);
HAL_ADC_PollForConversion(&hadc1, 10);
uint32_t adc_val = HAL_ADC_GetValue(&hadc1);
// --- Motor Control ---
if (adc_val < THRESH_LOW)
{
__HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_1, 32767); // Lambat
}
else if (adc_val < THRESH_MID)
{
__HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_1, 45874); // Sedang
}
else
{
__HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_1, 1000); // Cepat
}
// --- Buzzer Logic ---
if (adc_val < THRESH_LOW && buzzer_enabled)
{
// Ubah frekuensi buzzer setiap 500ms
if (HAL_GetTick() - last_buzzer_change >= 500)
{
last_buzzer_change = HAL_GetTick();
buzzer_freq_index = (buzzer_freq_index + 1) % 3;
uint32_t period = buzzer_periods[buzzer_freq_index];
__HAL_TIM_SET_AUTORELOAD(&htim2, period);
__HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_3, period / 2); // 50% duty
}
}
else
{
}
__HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_3, 0); // Matikan buzzer
// --- Button Logic (PB0 ditekan = nonaktifkan buzzer) ---
if (HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_0) == GPIO_PIN_SET)
{
buzzer_enabled = 0;
__HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_3, 0); // Paksa matikan buzzer
}
HAL_Delay(10);
}
}
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
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_HSI;
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_0) != HAL_OK)
{
Error_Handler();
}
PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_ADC;
PeriphClkInit.AdcClockSelection = RCC_ADCPCLK2_DIV2;
if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
{
Error_Handler();
}
}
static void MX_ADC1_Init(void)
{
ADC_ChannelConfTypeDef sConfig = {0};
hadc1.Instance = ADC1;
hadc1.Init.ScanConvMode = ADC_SCAN_DISABLE;
hadc1.Init.ContinuousConvMode = DISABLE;
hadc1.Init.DiscontinuousConvMode = DISABLE;
hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;
hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
hadc1.Init.NbrOfConversion = 1;
if (HAL_ADC_Init(&hadc1) != HAL_OK)
{
Error_Handler();
}
sConfig.Channel = ADC_CHANNEL_0;
sConfig.Rank = ADC_REGULAR_RANK_1;
sConfig.SamplingTime = ADC_SAMPLETIME_1CYCLE_5;
if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
{
Error_Handler();
}
}
static void MX_TIM1_Init(void)
{
TIM_MasterConfigTypeDef sMasterConfig = {0};
TIM_OC_InitTypeDef sConfigOC = {0};
TIM_BreakDeadTimeConfigTypeDef sBreakDeadTimeConfig = {0};
htim1.Instance = TIM1;
htim1.Init.Prescaler = 0;
htim1.Init.CounterMode = TIM_COUNTERMODE_UP;
htim1.Init.Period = 65535;
htim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
htim1.Init.RepetitionCounter = 0;
htim1.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
if (HAL_TIM_PWM_Init(&htim1) != HAL_OK)
{
Error_Handler();
}
sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
if (HAL_TIMEx_MasterConfigSynchronization(&htim1, &sMasterConfig) !=
HAL_OK)
{
Error_Handler();
}
sConfigOC.OCMode = TIM_OCMODE_PWM1;
sConfigOC.Pulse = 0;
sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
sConfigOC.OCNPolarity = TIM_OCNPOLARITY_HIGH;
sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
sConfigOC.OCIdleState = TIM_OCIDLESTATE_RESET;
sConfigOC.OCNIdleState = TIM_OCNIDLESTATE_RESET;
if (HAL_TIM_PWM_ConfigChannel(&htim1, &sConfigOC, TIM_CHANNEL_1) !=
HAL_OK)
{
Error_Handler();
}
sBreakDeadTimeConfig.OffStateRunMode = TIM_OSSR_DISABLE;
sBreakDeadTimeConfig.OffStateIDLEMode = TIM_OSSI_DISABLE;
sBreakDeadTimeConfig.LockLevel = TIM_LOCKLEVEL_OFF;
sBreakDeadTimeConfig.DeadTime = 0;
sBreakDeadTimeConfig.BreakState = TIM_BREAK_DISABLE;
sBreakDeadTimeConfig.BreakPolarity = TIM_BREAKPOLARITY_HIGH;
sBreakDeadTimeConfig.AutomaticOutput = TIM_AUTOMATICOUTPUT_DISABLE;
if (HAL_TIMEx_ConfigBreakDeadTime(&htim1, &sBreakDeadTimeConfig) !=
HAL_OK)
{
Error_Handler();
}
HAL_TIM_MspPostInit(&htim1);
}
static void MX_TIM2_Init(void)
{
TIM_MasterConfigTypeDef sMasterConfig = {0};
TIM_OC_InitTypeDef sConfigOC = {0};
htim2.Instance = TIM2;
htim2.Init.Prescaler = 0;
htim2.Init.CounterMode = TIM_COUNTERMODE_UP;
htim2.Init.Period = 65535;
htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
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 = 0;
sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
if (HAL_TIM_PWM_ConfigChannel(&htim2, &sConfigOC, TIM_CHANNEL_3) !=
HAL_OK)
{
Error_Handler();
}
HAL_TIM_MspPostInit(&htim2);
}
static void MX_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
__HAL_RCC_GPIOD_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
/*Configure GPIO pin : PB0 */
GPIO_InitStruct.Pin = GPIO_PIN_0;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_PULLUP;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
}
void Error_Handler(void)
{
__disable_irq();
while (1)
{
}
}
#ifdef USE_FULL_ASSERT
void assert_failed(uint8_t *file, uint32_t line)
{
}
#endif /* USE_FULL_ASSERT */
Tidak ada komentar:
Posting Komentar