Sistem lampu jalan otomatis ini dirancang untuk mengoptimalkan efisiensi energi dengan memadukan tiga komponen utama yaitu sensor cahaya LDR, sensor gerak PIR, dan tombol pengaman manual. Ketiganya bekerja secara hierarkis — mikrokontroler memproses input dari masing-masing komponen secara berurutan sesuai prioritasnya.
Prioritas tertinggi dipegang oleh tombol manual pada PB1 yang bekerja melalui mekanisme interrupt. Ketika tombol ini ditekan, sistem langsung masuk ke mode darurat yang memaksa lampu mati total dan menonaktifkan seluruh pembacaan sensor, sehingga kondisi ini tidak dapat ditembus oleh logika otomatis manapun.
Pada kondisi normal tanpa mode darurat, sistem terlebih dahulu membaca nilai ADC dari sensor LDR pada PA0. Jika nilai yang terbaca di bawah threshold 2000 yang menandakan kondisi siang hari, lampu dipastikan tetap mati tanpa perlu memeriksa sensor lainnya. Sebaliknya, ketika nilai ADC melampaui threshold yang menandakan kondisi malam hari, barulah mikrokontroler mengaktifkan pemantauan sensor PIR pada PA1.
Pada fase malam ini, lampu LED pada PA6 akan menyala dengan kecerahan penuh hanya ketika PIR mendeteksi adanya gerakan. Mikrokontroler kemudian mencatat waktu terakhir gerakan terdeteksi menggunakan HAL_GetTick(), dan lampu baru akan diredupkan secara otomatis setelah tidak ada gerakan selama 5 detik. Pendekatan bertingkat ini memastikan lampu hanya menyala ketika benar-benar dibutuhkan, sehingga konsumsi energi dapat ditekan secara signifikan.
2. main.c
#include "main.h"
/* ================= HANDLE ================= */
ADC_HandleTypeDef hadc1;
TIM_HandleTypeDef htim3;
/* ================= VARIABLE ================= */
volatile uint8_t emergency_mode = 0;
uint32_t last_motion_time = 0;
/* fallback button */
uint8_t last_button_state = 1;
/* ================= PARAMETER ================= */
#define LDR_THRESHOLD 2000
#define MOTION_TIMEOUT 5000
#define LED_OFF 0
#define LED_DIM 100
#define LED_FULL 1000
/* ===================================================== */
/* ================= SYSTEM CLOCK ======================= */
/* ===================================================== */
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
HAL_RCC_OscConfig(&RCC_OscInitStruct);
RCC_ClkInitStruct.ClockType =
RCC_CLOCKTYPE_HCLK |
RCC_CLOCKTYPE_SYSCLK;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSI;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0);
}
/* ===================================================== */
/* ================= GPIO INIT ========================== */
/* ===================================================== */
void MX_GPIO_Init(void)
{
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
GPIO_InitTypeDef GPIO_InitStruct = {0};
/* ===== PIR (INPUT) ===== */
GPIO_InitStruct.Pin = PIR_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(PIR_PORT, &GPIO_InitStruct);
/* ===== BUTTON (INTERRUPT FALLING) ===== */
GPIO_InitStruct.Pin = BUTTON_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING;
GPIO_InitStruct.Pull = GPIO_PULLUP;
HAL_GPIO_Init(BUTTON_PORT, &GPIO_InitStruct);
/* ===== LED PWM (AF) ===== */
GPIO_InitStruct.Pin = LED_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
GPIO_InitStruct.Alternate = GPIO_AF1_TIM3;
HAL_GPIO_Init(LED_PORT, &GPIO_InitStruct);
/* ===== INTERRUPT ENABLE ===== */
HAL_NVIC_SetPriority(EXTI0_1_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(EXTI0_1_IRQn);
}
/* ===================================================== */
/* ================= ADC INIT =========================== */
/* ===================================================== */
void MX_ADC1_Init(void)
{
__HAL_RCC_ADC_CLK_ENABLE();
hadc1.Instance = ADC1;
hadc1.Init.Resolution = ADC_RESOLUTION_12B;
hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
hadc1.Init.ScanConvMode = ADC_SCAN_DISABLE;
hadc1.Init.ContinuousConvMode = DISABLE;
HAL_ADC_Init(&hadc1);
ADC_ChannelConfTypeDef sConfig = {0};
sConfig.Channel = ADC_CHANNEL_0;
sConfig.Rank = ADC_REGULAR_RANK_1;
HAL_ADC_ConfigChannel(&hadc1, &sConfig);
}
/* ===================================================== */
/* ================= PWM INIT =========================== */
/* ===================================================== */
void MX_TIM3_Init(void)
{
__HAL_RCC_TIM3_CLK_ENABLE();
htim3.Instance = TIM3;
htim3.Init.Prescaler = 64;
htim3.Init.Period = 1000;
htim3.Init.CounterMode = TIM_COUNTERMODE_UP;
HAL_TIM_PWM_Init(&htim3);
TIM_OC_InitTypeDef sConfigOC = {0};
sConfigOC.OCMode = TIM_OCMODE_PWM1;
sConfigOC.Pulse = 0;
HAL_TIM_PWM_ConfigChannel(&htim3, &sConfigOC, TIM_CHANNEL_1);
}
/* ===================================================== */
/* ================= INTERRUPT ========================== */
/* ===================================================== */
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
if (GPIO_Pin == BUTTON_PIN)
{
emergency_mode = !emergency_mode;
}
}
/* ===================================================== */
/* ================= HELPER FUNCTION ==================== */
/* ===================================================== */
uint16_t read_LDR(void)
{
HAL_ADC_Start(&hadc1);
HAL_ADC_PollForConversion(&hadc1, HAL_MAX_DELAY);
return HAL_ADC_GetValue(&hadc1);
}
void set_LED(uint16_t value)
{
__HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_1, value);
}
/* ===================================================== */
/* ================= MAIN PROGRAM ======================= */
/* ===================================================== */
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_ADC1_Init();
MX_TIM3_Init();
HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_1);
while (1)
{
/* ===== FALLBACK BUTTON (ANTI ERROR INTERRUPT) ===== */
uint8_t current_button = HAL_GPIO_ReadPin(BUTTON_PORT, BUTTON_PIN);
if (last_button_state == 1 && current_button == 0)
{
emergency_mode = !emergency_mode;
HAL_Delay(50); // debounce
}
last_button_state = current_button;
/* ===== MODE DARURAT ===== */
if (emergency_mode)
{
set_LED(LED_OFF);
continue;
}
uint16_t ldr = read_LDR();
uint8_t pir = HAL_GPIO_ReadPin(PIR_PORT, PIR_PIN);
/* ===== SIANG ===== */
if (ldr < LDR_THRESHOLD)
{
set_LED(LED_OFF);
}
else
{
/* ===== MALAM ===== */
if (pir == GPIO_PIN_SET)
{
last_motion_time = HAL_GetTick();
}
if ((HAL_GetTick() - last_motion_time) < MOTION_TIMEOUT)
{
set_LED(LED_FULL);
}
else
{
set_LED(LED_DIM);
}
}
HAL_Delay(100);
}
}
Komentar
Posting Komentar