Laporan Akhir 2 M2
2. Buat program untuk mikrokontroler STM32
Pada sistem ini STM32 pertama‐tama menginisialisasi semua periferal: kanal ADC untuk membaca tegangan dari potensiometer (atau LDR), timer PWM (TIMx) untuk mengendalikan kecepatan motor DC dan modulasi buzzer, serta GPIO input untuk tombol tekan. Setelah reset, mikrokontroler melakukan konversi ADC untuk mendapatkan nilai analog 0–100 % yang mewakili posisi potensiometer; nilai ini dibagi menjadi tiga rentang: rendah (< 33 %), sedang (33–66 %) dan tinggi (> 66 %). Jika ADC < 33 %, STM32 menetapkan duty cycle PWM motor pada 20 % sehingga motor berputar lambat dan mematikan buzzer. Untuk nilai 33–66 %, duty cycle diubah ke 60 % (kecepatan menengah) tetap tanpa suara buzzer. Saat nilai > 66 %, motor dipacu pada duty 100 % (kecepatan maksimal) dan STM32 selanjutnya membaca status tombol; jika tombol ditekan maka ia mengaktifkan PWM buzzer pada frekuensi tertentu untuk alarm, sementara jika tombol tidak ditekan maka buzzer tetap mati. Loop ini berjalan terus‐menerus sehingga motor dan buzzer secara otomatis merespons perubahan tegangan potensiometer dan input tombol
#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 = 1500; const uint16_t THRESH_MID = 3000; 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, 200); // Lambat } else if (adc_val < THRESH_MID) { __HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_1, 600); // 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 */
read_u16()
dalam Micropython, yang mengkonversi hasil ADC 12-bit menjadi nilai 16-bit untuk kemudahan. Walau mudah digunakan, kecepatan pembacaan ADC pada Pico lebih rendah dibanding STM32 dan bergantung pada beban prosesor, sehingga kurang cocok untuk aplikasi sensor analog yang memerlukan kecepatan sampling tinggi.irq()
pada objek pin dalam Micropython. Interrupt ini cukup mudah digunakan namun bekerja di level perangkat lunak, sehingga memiliki latensi yang lebih tinggi dan kurang cocok untuk aplikasi yang memerlukan respons instan.utime.ticks_ms()
pada Raspberry Pi Pico digunakan untuk menghitung waktu dalam milidetik sejak sistem dinyalakan. Fungsi ini bekerja dengan membaca nilai dari timer internal yang terus bertambah sejak sistem boot. Dengan memanfaatkan ticks_ms()
dan ticks_diff()
, pengguna dapat mengukur durasi waktu antar peristiwa tanpa khawatir terhadap overflow, karena sistem ini menangani wrap-around secara otomatis. Fungsi ini sangat berguna dalam membuat delay non-blocking, mengatur waktu polling sensor, atau memicu event berdasarkan waktu secara efisien dalam program Micropython.
Komentar
Posting Komentar