1. Prosedur [Kembali]
- Pahami terlebih dahulu kondisi yang akan digunakan
- Buka software Proteus 8.17
- Persiapkan alat dan bahan
- Buat rangkaian sesuai dengan kondisi dan modul
- Buka software STM32Cube IDE
- Setelah membuka software, pilih perangkat STM32F103C8T6
- Sesuaikan konfigurasi pin sesuai dengan rangkaian proteus
- Buat kode program untuk mengoperasikan rangkaian tersebut sesuai dengan kondisi
- Konfigurasi kan program dengan software Proteus
- Jalankan simulasi rangkaian.
- Proses selesai
2. Hardware dan Diagram Blok [Kembali]
Hardware
STM32F103C8T6
Sensor Suhu Lm35
Kipas DC
Push Button
Motor Driver l298N
Breadboard
Adaptor
Resistor
Diagram Blok
3. Rangkaian Simulasi dan Prinsip Kerja [Kembali]
1. Pembacaan suhu — LM35 ke ADC
LM35 merupakan sensor suhu analog dengan karakteristik output sebesar 10 mV per °C. Pin output (VOUT) dari LM35 dihubungkan ke pin analog mikrokontroler (misalnya PA0) yang dikonfigurasi sebagai ADC channel.
Mikrokontroler membaca nilai digital dari ADC, kemudian mengubahnya menjadi tegangan dan suhu menggunakan persamaan:
voltage = (adcValue / 4095.0) × 3.3 → tegangan (Volt)
temperature = voltage × 100.0 → suhu (°C)
Nilai suhu inilah yang digunakan sebagai parameter untuk menentukan kondisi kipas.
2. Tombol ON — Input Digital
Tombol dihubungkan ke salah satu pin GPIO (misalnya PA1) dan dikonfigurasi sebagai input dengan pull-up. Ketika tombol ditekan, logika berubah dari HIGH menjadi LOW.
Program mendeteksi perubahan ini menggunakan pembacaan pin secara berkala (polling), lalu mengaktifkan kipas dengan logika:
if(button == PRESSED && last_button == RELEASED)
{
fan_status = 1;
}
Pendekatan ini memastikan bahwa:- Kipas hanya aktif sekali saat tombol ditekan
- Tidak terjadi pembacaan berulang saat tombol ditahan
3. Kontrol kipas — Driver Motor (L298)
Kipas DC dikendalikan menggunakan driver motor L298. Dua pin utama digunakan:- IN2 → menentukan kondisi berhenti
Kondisi dasar:- Kipas ON → IN1 = HIGH, IN2 = LOW
- Kipas OFF → IN1 = LOW, IN2 = LOW
Pada kondisi normal (kipas hidup), motor berputar penuh tanpa PWM hardware.
4. Logika kontrol sistem
Sistem memiliki dua kondisi utama:
| Kondisi | Aksi Kipas |
|---|
| Tombol ditekan sekali | Kipas menyala |
| Suhu ≤ 30°C | Kipas tetap menyala |
| Suhu > 30°C | Kipas mati perlahan (5 detik) |
Logika program:- Saat tombol ditekan → kipas aktif (
fan_status = 1)
- Selama suhu masih ≤ 30°C → kipas tetap hidup
- Ketika suhu melewati 30°C → sistem masuk proses slow stop
5. Proses berhenti perlahan (Soft Stop 5 detik)
Ketika suhu > 30°C, kipas tidak langsung dimatikan, melainkan diturunkan kecepatannya secara bertahap selama ±5 detik.
Metode yang digunakan adalah software PWM, dengan penurunan duty cycle:
duty: 100 → 0 (step -5)
Setiap nilai duty dipertahankan selama 250 ms:
Total waktu = 20 step × 250 ms = 5000 ms (5 detik)
PWM dibuat dengan mengatur pin ON dan OFF menggunakan delay:
ON time = duty / 5
OFF time = (100 - duty) / 5
Semakin kecil nilai duty:- Putaran kipas semakin lambat
Pada akhir proses:
Fan_OFF();
Kipas berhenti sepenuhnya.4. Flowchart dan Listing Program [Kembali]
Flowchart


#include "main.h"
/* ================= PRIVATE VARIABLES ================= */
ADC_HandleTypeDef hadc1;
TIM_HandleTypeDef htim2; // Timer untuk PWM dan non-blocking delay
/* ================= PRIVATE MACROS ================= */
#define TEMP_THRESHOLD 30.0f
#define ADC_MAX_VALUE 4095U
#define VREF 3.3f
#define LM35_SENSITIVITY 0.01f
#define DEBOUNCE_DELAY_MS 50U
#define PWM_PERIOD_MS 20U
#define PWM_RESOLUTION 100U
#define SLOW_STOP_STEP_MS 250U
#define MAIN_LOOP_DELAY_MS 100U
/* ================= STATE MACHINE ENUM ================= */
typedef enum {
FAN_STATE_OFF,
FAN_STATE_ON,
FAN_STATE_SLOW_STOP
} FanState_t;
/* ================= GLOBAL VARIABLES ================= */
static FanState_t fan_state = FAN_STATE_OFF;
static uint8_t button_last_state = GPIO_PIN_SET;
static uint32_t slow_stop_counter = 0;
static uint8_t pwm_duty = PWM_RESOLUTION;
/* ================= FUNCTION PROTOTYPES ================= */
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_ADC1_Init(void);
static void MX_TIM2_Init(void);
void Fan_Control(void);
uint32_t Read_ADC(void);
float Read_Temperature(void);
void Button_Process(void);
void Slow_Stop_Process(void);
void Error_Handler(void);
/* ================= MAIN ================= */
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_ADC1_Init();
MX_TIM2_Init();
HAL_TIM_Base_Start_IT(&htim2);
while (1)
{
float temperature = Read_Temperature();
Button_Process();
Fan_Control();
HAL_Delay(MAIN_LOOP_DELAY_MS);
}
}
/* ================= ADC FUNCTIONS ================= */
uint32_t Read_ADC(void)
{
uint32_t adc_value;
if (HAL_ADC_Start(&hadc1) == HAL_OK)
{
if (HAL_ADC_PollForConversion(&hadc1, 10) == HAL_OK)
{
adc_value = HAL_ADC_GetValue(&hadc1);
}
else
{
adc_value = 0;
}
HAL_ADC_Stop(&hadc1);
}
else
{
adc_value = 0;
}
return adc_value;
}
float Read_Temperature(void)
{
uint32_t adc_value = Read_ADC();
float voltage = (float)adc_value * VREF / ADC_MAX_VALUE;
return voltage / LM35_SENSITIVITY; // LM35: 10mV/°C
}
/* ================= BUTTON HANDLER ================= */
void Button_Process(void)
{
uint8_t button_current = HAL_GPIO_ReadPin(BUTTON_GPIO_Port, BUTTON_Pin);
// Edge detection: rising edge (button pressed)
if (button_current == GPIO_PIN_RESET && button_last_state == GPIO_PIN_SET)
{
HAL_Delay(DEBOUNCE_DELAY_MS);
if (HAL_GPIO_ReadPin(BUTTON_GPIO_Port, BUTTON_Pin) == GPIO_PIN_RESET)
{
if (fan_state == FAN_STATE_OFF)
{
fan_state = FAN_STATE_ON;
pwm_duty = PWM_RESOLUTION;
}
}
}
button_last_state = button_current;
}
/* ================= FAN CONTROL - STATE MACHINE ================= */
void Fan_Control(void)
{
float temperature = Read_Temperature();
switch (fan_state)
{
case FAN_STATE_OFF:
HAL_GPIO_WritePin(IN1_GPIO_Port, IN1_Pin, GPIO_PIN_RESET);
HAL_GPIO_WritePin(IN2_GPIO_Port, IN2_Pin, GPIO_PIN_RESET);
break;
case FAN_STATE_ON:
if (temperature > TEMP_THRESHOLD)
{
fan_state = FAN_STATE_SLOW_STOP;
slow_stop_counter = 0;
}
else
{
// Software PWM untuk kehalusan
static uint32_t pwm_counter = 0;
pwm_counter++;
if (pwm_counter >= PWM_PERIOD_MS)
{
pwm_counter = 0;
}
if (pwm_counter < pwm_duty)
{
HAL_GPIO_WritePin(IN1_GPIO_Port, IN1_Pin, GPIO_PIN_SET);
HAL_GPIO_WritePin(IN2_GPIO_Port, IN2_Pin, GPIO_PIN_RESET);
}
else
{
HAL_GPIO_WritePin(IN1_GPIO_Port, IN1_Pin, GPIO_PIN_RESET);
}
}
break;
case FAN_STATE_SLOW_STOP:
Slow_Stop_Process();
break;
}
}
/* ================= SOFT STOP IMPLEMENTATION ================= */
void Slow_Stop_Process(void)
{
static uint32_t last_tick = 0;
uint32_t current_tick = HAL_GetTick();
if (current_tick - last_tick >= SLOW_STOP_STEP_MS)
{
last_tick = current_tick;
if (pwm_duty > 0)
{
pwm_duty -= 5; // Kurangi 5% setiap 250ms
}
else
{
fan_state = FAN_STATE_OFF;
pwm_duty = PWM_RESOLUTION;
}
}
// PWM dengan duty cycle yang menurun
static uint32_t pwm_counter = 0;
pwm_counter++;
if (pwm_counter >= PWM_PERIOD_MS)
{
pwm_counter = 0;
}
if (pwm_counter < pwm_duty)
{
HAL_GPIO_WritePin(IN1_GPIO_Port, IN1_Pin, GPIO_PIN_SET);
HAL_GPIO_WritePin(IN2_GPIO_Port, IN2_Pin, GPIO_PIN_RESET);
}
else
{
HAL_GPIO_WritePin(IN1_GPIO_Port, IN1_Pin, GPIO_PIN_RESET);
}
}
/* ================= HARDWARE CONFIG ================= */
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};
__HAL_RCC_SYSCFG_CLK_ENABLE();
__HAL_RCC_PWR_CLK_ENABLE();
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_TIM2_Init(void)
{
TIM_ClockConfigTypeDef sClockSourceConfig = {0};
TIM_MasterConfigTypeDef sMasterConfig = {0};
htim2.Instance = TIM2;
htim2.Init.Prescaler = 7999; // 1ms tick dengan 8MHz HSI
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_Base_Init(&htim2) != HAL_OK)
{
Error_Handler();
}
sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
if (HAL_TIM_ConfigClockSource(&htim2, &sClockSourceConfig) != HAL_OK)
{
Error_Handler();
}
}
static void MX_ADC1_Init(void)
{
ADC_ChannelConfTypeDef sConfig = {0};
hadc1.Instance = ADC1;
hadc1.Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV1;
hadc1.Init.Resolution = ADC_RESOLUTION_12B;
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;
hadc1.Init.DMAContinuousRequests = DISABLE;
hadc1.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
if (HAL_ADC_Init(&hadc1) != HAL_OK)
{
Error_Handler();
}
sConfig.Channel = ADC_CHANNEL_0;
sConfig.Rank = ADC_REGULAR_RANK_1;
sConfig.SamplingTime = ADC_SAMPLETIME_239CYCLES_5;
if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
{
Error_Handler();
}
}
static void MX_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
__HAL_RCC_GPIOA_CLK_ENABLE();
/* OUTPUT: Fan control pins */
HAL_GPIO_WritePin(GPIOA, IN1_Pin | IN2_Pin, GPIO_PIN_RESET);
GPIO_InitStruct.Pin = IN1_Pin | IN2_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
/* INPUT: Button with pull-up */
GPIO_InitStruct.Pin = BUTTON_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_PULLUP;
HAL_GPIO_Init(BUTTON_GPIO_Port, &GPIO_InitStruct);
}
void Error_Handler(void)
{
__disable_irq();
while (1)
{
HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_5); // Debug LED blink
HAL_Delay(200);
}
}
#ifdef USE_FULL_ASSERT
void assert_failed(uint8_t *file, uint32_t line)
{
Error_Handler();
}
#endif
/* ================= PRIVATE VARIABLES ================= */
ADC_HandleTypeDef hadc1;
TIM_HandleTypeDef htim2; // Timer untuk PWM dan non-blocking delay
6. Kondisi [Kembali]
Buatlah rangkaian seperti percobaan 3 dengan kondisi ketika sensor tombol ditekan sekali maka kipas hidup dan ketika sensor suhu >30 C maka kipas mati secara perlahan selama 5 detik.
Komentar
Posting Komentar