PRATIKUM UC&UP
MODUL 1
a) Asistensi dilakukan 1x
b) Praktikum dilakukan 1x
a) Memahami cara penggunaan PWM, ADC, dan Interrupt pada Development Board yang digunakan
b) Memahami cara menggunakan komponen input dan output yang mengimplementasikan PWM, ADC, dan Interrupt pada Development Board yang digunakan
ADC
ADC atau Analog to Digital Converter
merupakan salah satu perangkat elektronika yang digunakan sebagai penghubung dalam
pemrosesan sinyal analog oleh sistem digital. Fungsi utama
dari fitur ini adalah mengubah sinyal masukan yang masih dalam bentuk sinyal
analog menjadi sinyal digital dengan bentuk kode-kode digital.
Pada mikrokontroler STM32, terdapat dua
ADC (Analog-to-Digital Converter) 12-bit yang masing-masing memiliki hingga 16
kanal eksternal. ADC ini dapat beroperasi dalam mode single-shot atau scan
mode. Pada scan mode, konversi dilakukan secara otomatis
pada sekelompok input analog yang dipilih. Selain itu, ADC ini memiliki
fitur tambahan seperti
simultaneous sample and hold,
interleaved sample and hold, serta single shunt. ADC juga dapat dihubungkan
dengan DMA untuk meningkatkan efisiensi transfer data. Mikrokontroler ini
dilengkapi dengan fitur analog watchdog yang
memungkinkan pemantauan tegangan hasil konversi dengan akurasi tinggi,
serta dapat menghasilkan interupsi jika tegangan berada di luar ambang batas yang telah diprogram. Selain itu, ADC dapat disinkronkan dengan timer internal
(TIMx dan TIM1) untuk memulai konversi, pemicu injeksi, serta pemicu
DMA, sehingga memungkinkan aplikasi untuk melakukan konversi ADC secara terkoordinasi dengan timer.
Pada STM32 Nucleo G474RE, terdapat blok
ADC (Analog-to-Digital Converter) yang digunakan untuk mengubah sinyal analog
menjadi data digital. STM32 G474RE memiliki beberapa unit ADC (seperti ADC1,
ADC2, ADC3, dan ADC4) yang memungkinkan proses konversi dilakukan secara
paralel untuk meningkatkan kecepatan akuisisi data. Setiap ADC mendukung
resolusi hingga 12-bit, dengan fitur tambahan seperti oversampling untuk
meningkatkan akurasi dan mengurangi noise pada sinyal.
Setiap unit ADC dapat mengakses banyak channel input yang
terhubung ke berbagai pin GPIO, sehingga memungkinkan pembacaan berbagai sensor
secara fleksibel. ADC pada STM32 G474RE juga dilengkapi dengan fitur scan mode
untuk membaca beberapa channel secara berurutan, serta mode continuous
conversion yang memungkinkan pembacaan data secara terus-menerus tanpa
intervensi CPU. Selain itu, terdapat injected channel yang berfungsi sebagai
channel prioritas untuk kebutuhan real-time.
ADC ini juga mendukung berbagai sumber trigger, seperti
timer (TIM) atau sinyal eksternal, sehingga dapat disinkronkan dengan modul
lain seperti PWM untuk aplikasi kontrol tertutup (closed-loop). Proses konversi
dilakukan melalui tahap sampling dan quantization, dengan hasil akhir disimpan
pada register data ADC. Dengan fitur-fitur tersebut, ADC pada STM32 G474RE
sangat cocok digunakan dalam aplikasi seperti pembacaan sensor, monitoring
tegangan, serta sistem kendali berbasis sinyal analog yang membutuhkan kecepatan
dan presisi tinggi.
2
PWM
PWM (Pulse
Width Modulation) adalah salah satu teknik modulasi dengan mengubah lebar
pulsa (duty cylce) dengan nilai amplitudo dan frekuensi yang tetap. Satu siklus pulsa merupakan kondisi
high kemudian berada di zona transisi
ke kondisi low. Lebar pulsa PWM berbanding lurus dengan
amplitudo sinyal asli yang belum termodulasi.
Duty Cycle adalah perbandingan antara waktu ON (lebar pulsa
High) dengan perioda. Duty Cycle biasanya dinyatakan dalam bentuk persen (%).
Gambar 1. Duty Cycle
Duty Cycle =
tON / ttotal
Ton = Waktu
ON atau Waktu dimana tegangan
keluaran berada pada posisi tinggi (high atau 1)
Toff = Waktu
OFF atau Waktu dimana tegangan
keluaran berada pada posisi rendah (low atau 0)
Ttotal = Waktu satu siklus
atau penjumlahan antara
Ton dengan Toff atau disebut juga dengan “periode
satu gelombang”
PWM pada STM32 dihasilkan menggunakan
timer internal yang berfungsi sebagai penghitung waktu dengan berbagai mode
operasi. Mikrokontroler ini memiliki empat timer 16-bit (TIM1–TIM4), yang dapat
dikonfigurasi untuk menghasilkan sinyal dengan frekuensi dan duty cycle
tertentu. Timer bekerja dengan menghitung hingga nilai tertentu
berdasarkan frekuensi clock, lalu mengubah status register
untuk menghasilkan gelombang persegi.
STM32 memiliki 15 pin yang mendukung
PWM, beberapa di antaranya berasal dari timer tingkat lanjut seperti TIM1, yang
memiliki fitur tambahan seperti complementary output. Selain menghasilkan
sinyal PWM, timer juga bisa digunakan untuk mengukur sinyal eksternal (input
capture), menghasilkan sinyal berbasis waktu (output
compare), dan membuat
satu pulsa berdasarkan trigger
(one pulse mode). PWM sering digunakan untuk mengontrol
kecepatan motor, mengatur kecerahan LED, dan berbagai aplikasi berbasis waktu
lainnya.
Pada STM32 Nucleo G474RE, PWM dihasilkan
melalui blok timer (TIM) yang terdiri dari beberapa jenis, seperti
advanced-control timer (TIM1, TIM8), general-purpose timer (TIM2–TIM5), dan
basic timer. Setiap timer memiliki beberapa channel yang dapat digunakan untuk
menghasilkan sinyal PWM, sehingga memungkinkan banyak output PWM dikendalikan
secara bersamaan pada berbagai pin GPIO. Timer pada STM32 G474RE umumnya
memiliki resolusi hingga 16-bit atau lebih (tergantung jenis timer), dilengkapi
dengan prescaler untuk pengaturan frekuensi yang presisi, serta register
pembanding (CCR) untuk mengatur duty cycle dari 0–100%.
Selain itu, setiap channel PWM dapat
dikonfigurasi secara independen, baik dalam mode edge-aligned maupun
center-aligned, sehingga cocok untuk aplikasi seperti kontrol motor dan
konversi daya. STM32 G474RE juga mendukung fitur lanjutan seperti complementary
output, dead-time insertion, break input, dan sinkronisasi antar timer, yang
sangat penting dalam sistem power electronics dan inverter. Pengaturan PWM dapat dilakukan secara
fleksibel melalui register
timer atau menggunakan library
seperti HAL/LL, serta dapat diaktifkan atau dihentikan secara terpusat, memungkinkan sinkronisasi beberapa sinyal
PWM untuk aplikasi yang lebih
kompleks dan presisi tinggi.
3 INTERRUPT
Interrupt adalah mekanisme yang
memungkinkan suatu instruksi atau perangkat I/O untuk menghentikan sementara eksekusi normal prosesor agar dapat
diproses lebih dulu seperti memiliki prioritas tertinggi. Misalnya, saat
prosesor menjalankan tugas utama,
ia juga dapat terus memantau
apakah ada kejadian atau
sinyal dari sensor yang memicu interrupt. Ketika terjadi interrupt eksternal,
prosesor akan menghentikan sementara tugas utamanya untuk menangani interrupt terlebih
dahulu, kemudian melanjutkan eksekusi normal setelah selesai
menangani interrupt tersebut. Fungsi yang menangani
interrupt disebut Interrupt Service Routine (ISR), yang dieksekusi secara
otomatis setiap kali interrupt terjadi.
Pada STM32F103C8, semua pin GPIO dapat digunakan
sebagai pin interrupt, berbeda
dengan Arduino Uno yang hanya memiliki pin tertentu
(misalnya pin 2 dan 3). Untuk mengaktifkan interrupt di STM32 menggunakan Arduino IDE, digunakan fungsi attachInterrupt(digitalPinToInterrupt(pin), ISR, mode). Parameter pin menentukan pin mana yang digunakan
untuk interrupt, ISR adalah fungsi
yang dijalankan saat interrupt terjadi,
dan mode menentukan jenis perubahan sinyal yang memicu interrupt. Mode yang tersedia
adalah RISING (dari LOW ke HIGH), FALLING
(dari HIGH ke LOW), dan CHANGE (baik
dari LOW ke HIGH
maupun HIGH ke LOW). Saat menggunakan lebih dari satu interrupt
secara bersamaan, terkadang
perlu memperhatikan batasan
tertentu dalam pemrograman.
Pada STM32 Nucleo G474RE, sistem
interrupt merupakan mekanisme yang
memungkinkan mikrokontroler merespons suatu kejadian (event) secara langsung
tanpa harus terus-menerus melakukan polling. Dengan interrupt, CPU dapat
menghentikan sementara proses utama untuk menjalankan fungsi khusus yang
disebut Interrupt Service Routine (ISR), sehingga meningkatkan efisiensi dan
respons sistem secara real-time.
STM32 G474RE menggunakan NVIC (Nested
Vectored Interrupt Controller) untuk mengatur berbagai sumber interrupt,
seperti dari timer (TIM), ADC, UART, GPIO (external interrupt), dan periferal
lainnya. Setiap sumber interrupt memiliki prioritas tertentu yang dapat diatur,
sehingga memungkinkan penanganan beberapa interrupt secara bersamaan (nested
interrupt). Selain itu, sistem ini mendukung preemption dan subpriority untuk
pengelolaan interrupt yang lebih kompleks.
Interrupt dapat dipicu oleh berbagai kondisi, seperti perubahan
logika pada
pin GPIO (EXTI), selesainya konversi ADC, overflow pada
timer, atau penerimaan data komunikasi. Ketika interrupt terjadi, program akan
lompat ke ISR yang sesuai, kemudian setelah selesai, eksekusi akan kembali ke
program utama. STM32 G474RE juga menyediakan fitur enable/disable interrupt
secara fleksibel melalui register maupun library seperti HAL.
Dengan adanya interrupt, STM32 G474RE
sangat cocok untuk aplikasi real-time
seperti sistem kendali, monitoring sensor, komunikasi data, dan otomasi, karena
mampu merespons kejadian penting dengan cepat tanpa membebani CPU secara
terus-menerus.
4 STM32 NUCLEO G474RE
STM32 NUCLEO-G474RE merupakan papan
pengembangan (development board) berbasis mikrokontroler STM32G474RET6 yang
dikembangkan oleh STMicroelectronics. Board ini dirancang untuk memudahkan
proses pembelajaran, pengujian, dan pengembangan aplikasi sistem tertanam
(embedded system), baik untuk pemula maupun tingkat lanjut. STM32 Nucleo-G474RE
mengintegrasikan antarmuka ST-LINK debugger/programmer secara onboard sehingga
pengguna dapat langsung
melakukan pemrograman dan debugging tanpa perangkat tambahan.
Adapun spesifikasi dari STM32 NUCLEO-G474RE adalah sebagai berikut:
|
Microcontroller/Mikroprosesor |
STM32G474RE/ARM Cortex-M4F |
|
Operating Voltage |
3.3 V |
|
Input Voltage
(recommended) |
5 V via USB (ST-LINK) atau
7–12 V via VIN |
|
Input Voltage
(limit) |
4.5 – 15 V (VIN board
Nucleo) |
|
Digital I/O
Pins |
±51 GPIO
pins (tergantung konfigurasi fungsi) |
|
PWM Digital I/O Pins |
Hingga
24 channel PWM (advanced, general-purpose,
dan high-resolution timers) |
|
Analog Input
Pins |
Hingga 24 channel ADC
(12-bit / 16-bit dengan oversampling) |
|
DC Current per I/O Pin |
Maks. 20 mA per
pin (disarankan ≤ 8
mA) |
|
DC Current for 3.3V Pin |
Hingga ±500 mA (tergantung regulator & sumber daya) |
|
Flash Memory |
512 KB internal Flash |
|
SRAM |
128 KB SRAM (termasuk CCM RAM) |
|
Clock Speed |
Hingga 170 MHz |
5
STM32F103C8
STM32F103C8 adalah mikrokontroler berbasis ARM Cortex-M3
yang dikembangkan oleh STMicroelectronics. Mikrokontroler ini sering digunakan
dalam pengembangan sistem tertanam karena kinerjanya yang
baik, konsumsi daya yang rendah, dan kompatibilitas dengan berbagai protokol
komunikasi. Pada praktikum ini, kita
menggunakan STM32F103C8 yang dapat diprogram menggunakan berbagai metode,
termasuk komunikasi serial (USART), SWD (Serial Wire Debug), atau JTAG untuk
berhubungan dengan komputer maupun perangkat lain. Adapun spesifikasi dari STM32F4
yang digunakan dalam praktikum ini adalah sebagai berikut:
|
|
Microcontroller/Mikroprosesor |
Stm32 F103C8T6/ARM Cortex-M3 |
|
|
|
Operating Voltage |
3.3 V |
|||
|
Input Voltage
(recommended) |
5 V |
|||
|
Input Voltage
(limit) |
2 – 3.6 V |
|||
|
Digital I/O Pins |
37 |
|||
|
PWM Digital I/O Pins |
15 |
|||
|
Analog Input Pins |
10 (dengan resolusi 12-bit ADC) |
|||
|
DC Current
per I/O Pin |
25 mA |
|||
|
DC Current
for 3.3V Pin |
150 mA |
|||
|
Flash Memory |
64 KB |
|||
|
SRAM |
20 KB |
|||
|
EEPROM |
Emulasi dalam
Flash |
|||
|
Clock Speed |
72 MHz |
|||
BAGIAN-BAGIAN PENDUKUNG
1.
STM32 NUCLEO
G474RE
1. RAM (Random
Access Memory)
RAM (Random Access Memory) pada STM32 NUCLEO-G474RE
digunakan sebagai memori
sementara untuk menyimpan
data selama program berjalan. Mikrokontroler
STM32G474RET6 memiliki RAM sebesar 128 KB yang berfungsi untuk menyimpan
variabel, buffer data, stack, dan heap.
2. Memori Flash
Eksternal
STM32 NUCLEO-G474RE tidak menggunakan memori flash
eksternal. Seluruh program dan data permanen disimpan pada memori Flash
internal mikrokontroler STM32G474RET6 dengan kapasitas 512 KB. Memori flash ini bersifat
non-volatile, sehingga data dan program
tetap tersimpan meskipun catu daya dimatikan.
3. Crystal Oscillator
STM32 NUCLEO-G474RE menggunakan osilator internal (HSI –
High Speed Internal) sebagai sumber clock utama secara default. Penggunaan clock internal ini membuat board dapat
beroperasi tanpa memerlukan crystal oscillator eksternal. Clock berfungsi
sebagai sumber waktu untuk mengatur kecepatan kerja CPU dan seluruh peripheral.
4. Regulator Tegangan
Untuk memastikan pasokan
tegangan yang stabil
ke mikrokontroler.
5. Pin GPIO (General Purpose
Input/Output):
Pin GPIO pada STM32 NUCLEO-G474RE digunakan sebagai antarmuka input dan output digital yang
fleksibel
2. STM32
1. RAM (Random
Access Memory)
STM32F103C8 dilengkapi
dengan 20KB SRAM on-chip. Kapasitas
RAM ini memungkinkan
mikrokontroler menjalankan berbagai aplikasi serta menyimpan data sementara
selama eksekusi program.
2. Memori Flash Internal
STM32F103C8 memiliki memori flash internal sebesar 64KB
atau 128KB, yang digunakan untuk menyimpan firmware
dan program pengguna. Memori ini memungkinkan
penyimpanan kode program secara permanen tanpa memerlukan media penyimpanan
eksternal.
3. Crystal Oscillator
STM32F103C8 menggunakan crystal oscillator eksternal
(biasanya 8MHz) yang bekerja
dengan PLL untuk
meningkatkan frekuensi clock
hingga 72MHz. Sinyal clock yang stabil ini penting untuk mengatur
kecepatan operasi mikrokontroler dan komponen lainnya.
4. Regulator Tegangan
STM32F103C8 memiliki sistem pengaturan tegangan internal
yang memastikan pasokan daya stabil ke mikrokontroler. Tegangan operasi yang
didukung berkisar antara 2.0V hingga 3.6V.
5. Pin GPIO (General Purpose
Input/Output)
STM32F103C8 memiliki hingga 37 pin GPIO yang dapat
digunakan untuk menghubungkan berbagai perangkat eksternal seperti sensor,
motor, LED, serta komunikasi dengan antarmuka seperti UART, SPI, dan I²C.
1.1 Prosedur Percobaan
1. Heart Rate Indikator
a. Alat dan Bahan
· STM32F103C8T6
· HeartBeat Sensor
· Push Button
· LED
· Buzzer
· Resistor
· Breadboard
b. Rangkaian
c. Flowchart
d. Listing Program
#include "stm32f1xx_hal.h"
/* ================= HANDLE
================= */
ADC_HandleTypeDef hadc1;
/* ================= VARIABLE
================= */
uint32_t
adcValue = 0; uint32_t filteredValue = 0;
uint8_t beatDetected = 0; uint32_t BPM =
0;
uint32_t lastBeatTime = 0; uint32_t
interval = 0;
uint8_t buzzerOff = 0;
/* ================= FILTER
================= */
#define
FILTER_SIZE 10 uint16_t buffer[FILTER_SIZE];
uint8_t indexBuf = 0;
uint16_t moving_average(uint16_t val)
{
buffer[indexBuf++]
= val;
if(indexBuf
>= FILTER_SIZE) indexBuf
= 0;
uint32_t sum = 0;
for(int i=0;i<FILTER_SIZE;i++) sum += buffer[i];
return sum / FILTER_SIZE;
}
/* ================= LED ================= */
void LED_Hijau() {
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_SET);
}
void LED_Kuning() {
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_1, GPIO_PIN_SET);
|
|
}
void LED_Merah() { HAL_GPIO_WritePin(GPIOB, GPIO_PIN_10, GPIO_PIN_SET); }
void LED_Mati() { HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_10, GPIO_PIN_RESET); }
/* ================= BUZZER ================= */ void Buzzer_On() { HAL_GPIO_WritePin(GPIOB, GPIO_PIN_11, GPIO_PIN_SET); } void Buzzer_Off() { HAL_GPIO_WritePin(GPIOB, GPIO_PIN_11, GPIO_PIN_RESET); }
/* ================= INTERRUPT ================= */ void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) { if(GPIO_Pin == GPIO_PIN_1) // PA1 { buzzerOff
= !buzzerOff; } }
/* ================= PROTOTYPE ================= */ void SystemClock_Config(void); void
MX_GPIO_Init(void); void MX_ADC1_Init(void);
/* ================= MAIN ================= */ int main(void) { HAL_Init(); SystemClock_Config(); MX_GPIO_Init();
MX_ADC1_Init();
uint32_t baseline = 0;
while (1) { |
|
|
| ||
|
|
/* ==== BACA ADC ==== */ HAL_ADC_Start(&hadc1); HAL_ADC_PollForConversion(&hadc1, 10); adcValue =
HAL_ADC_GetValue(&hadc1);
/* ==== FILTER ====
*/ filteredValue = moving_average(adcValue);
/* ==== BASELINE (ADAPTIF) ==== */ baseline = (baseline * 9 + filteredValue) / 10;
uint32_t threshold = baseline + 50;
/* ==== DETEKSI DETAK
+ INTERVAL ====
*/ if(filteredValue > threshold && beatDetected == 0) { beatDetected = 1; uint32_t now
= HAL_GetTick();
if(lastBeatTime != 0) { interval = now - lastBeatTime; BPM = 60000 / interval; }
lastBeatTime = now; }
if(filteredValue <
threshold) { beatDetected = 0; }
/* ==== TIMEOUT (TIDAK
ADA DETAK) ====
*/ if(HAL_GetTick() - lastBeatTime >
2000) { BPM = 0; }
/* ==== OUTPUT
==== */ |
|
|
|
if(BPM > 0) { if(BPM >30 && BPM < 60) { LED_Kuning(); Buzzer_Off(); buzzerOff = 0; } else if(BPM <=
80) { LED_Hijau(); Buzzer_Off(); buzzerOff = 0; } else { LED_Merah(); if(!buzzerOff) Buzzer_On(); else Buzzer_Off(); } } else { LED_Mati(); Buzzer_Off(); }
HAL_Delay(5); } }
/* ================= 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; RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE; |
|
|
|
HAL_RCC_OscConfig(&RCC_OscInitStruct);
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;
HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0); }
/* ================= ADC ================= */ void MX_ADC1_Init(void) { ADC_ChannelConfTypeDef sConfig
= {0};
HAL_RCC_ADC1_CLK_ENABLE();
hadc1.Instance
= ADC1; hadc1.Init.ScanConvMode = ADC_SCAN_DISABLE;
hadc1.Init.ContinuousConvMode = DISABLE; hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;
hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT; hadc1.Init.NbrOfConversion = 1;
HAL_ADC_Init(&hadc1);
sConfig.Channel
= ADC_CHANNEL_0; sConfig.Rank = ADC_REGULAR_RANK_1; sConfig.SamplingTime = ADC_SAMPLETIME_71CYCLES_5;
HAL_ADC_ConfigChannel(&hadc1, &sConfig); }
/* ================= GPIO ================= */ void MX_GPIO_Init(void) { HAL_RCC_GPIOA_CLK_ENABLE(); |
|
|
|
HAL_RCC_GPIOB_CLK_ENABLE();
GPIO_InitTypeDef GPIO_InitStruct = {0};
/*
PA0 = ADC */ GPIO_InitStruct.Pin = GPIO_PIN_0; GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
/* PA1 = BUTTON */ GPIO_InitStruct.Pin
= GPIO_PIN_1; GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING;
GPIO_InitStruct.Pull = GPIO_PULLUP; HAL_GPIO_Init(GPIOA,
&GPIO_InitStruct);
HAL_NVIC_SetPriority(EXTI1_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(EXTI1_IRQn);
/* LED + BUZZER
*/ GPIO_InitStruct.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_10 | GPIO_PIN_11; GPIO_InitStruct.Mode
= GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Speed
= GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_10 | GPIO_PIN_11,
GPIO_PIN_RESET); } |
|
c. Flowchart
d.
Listing Program
#include "main.h"
// HANDLE
ADC_HandleTypeDef hadc1; TIM_HandleTypeDef htim3;
// VARIABLE
uint8_t manual_mode = 0; uint8_t posisi_servo = 0; uint8_t
last_button = 1;
// THRESHOLD
#define LDR_THRESHOLD 2000
// ================= 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 =================
void MX_GPIO_Init(void)
{
HAL_RCC_GPIOA_CLK_ENABLE();
HAL_RCC_GPIOB_CLK_ENABLE();
GPIO_InitTypeDef GPIO_InitStruct = {0};
// LDR PA0
GPIO_InitStruct.Pin = GPIO_PIN_0;
GPIO_InitStruct.Mode = GPIO_MODE_ANALOG; HAL_GPIO_Init(GPIOA,
&GPIO_InitStruct);
// BUTTON
PB1
GPIO_InitStruct.Pin = GPIO_PIN_1;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT; GPIO_InitStruct.Pull =
GPIO_PULLUP; HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
|
|
// SERVO PA6 GPIO_InitStruct.Pin =
GPIO_PIN_6; GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; GPIO_InitStruct.Pull =
GPIO_NOPULL; GPIO_InitStruct.Alternate = GPIO_AF1_TIM3; HAL_GPIO_Init(GPIOA,
&GPIO_InitStruct); }
// ================= ADC ================= 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;
HAL_ADC_Init(&hadc1); } // ================= PWM (FIX SERVO)
================= void MX_TIM3_Init(void) { HAL_RCC_TIM3_CLK_ENABLE(); htim3.Instance = TIM3;
// FIX: 1us tick (assume
48MHz clock) htim3.Init.Prescaler = 48 - 1; htim3.Init.CounterMode = TIM_COUNTERMODE_UP; htim3.Init.Period = 20000 - 1; // 20ms = 50Hz (servo
standard) HAL_TIM_PWM_Init(&htim3); TIM_OC_InitTypeDef
sConfigOC = {0}; sConfigOC.OCMode = TIM_OCMODE_PWM1; sConfigOC.Pulse = 1500; // posisi tengah
awal sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
HAL_TIM_PWM_ConfigChannel(&htim3, &sConfigOC, TIM_CHANNEL_1); }
// ================= SERVO CONTROL ================= void set_servo(uint8_t state) { if (state == 0) { HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_1, 1000); // masuk
atap } else { |
|
||
|
|
HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_1, 2000); // keluar atap } }
// ================= ADC READ ================= uint16_t read_LDR(void) { ADC_ChannelConfTypeDef sConfig
= {0};
sConfig.Channel =
ADC_CHANNEL_0; sConfig.Rank = ADC_REGULAR_RANK_1;
HAL_ADC_ConfigChannel(&hadc1, &sConfig);
HAL_ADC_Start(&hadc1);
HAL_ADC_PollForConversion(&hadc1, HAL_MAX_DELAY);
return HAL_ADC_GetValue(&hadc1); }
// ================= MAIN
================= 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) { // =====
BUTTON TOGGLE ===== uint8_t button = HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_1);
if (last_button == 1 && button == 0) { manual_mode =
!manual_mode; posisi_servo = !posisi_servo; set_servo(posisi_servo); HAL_Delay(50); }
last_button = button;
// ===== MODE OTOMATIS ===== if (!manual_mode) { uint16_t ldr = read_LDR(); |
|
||
|
|
if (ldr
< LDR_THRESHOLD) { posisi_servo = 0; // mendung → masuk } else { posisi_servo = 1; // terang
→ keluar }
set_servo(posisi_servo); } HAL_Delay(100); } } |
|
||
#define LDR_PORT GPIOA
#define BUTTON_PIN GPIO_PIN_1 #define BUTTON_PORT GPIOB
#define SERVO_PIN GPIO_PIN_6
#define SERVO_PORT GPIOA
// FUNCTION
void SystemClock_Config(void);
void MX_GPIO_Init(void);
void MX_ADC1_Init(void);
void MX_TIM3_Init(void);
#endif
· STM32F103C8T6
· Sensor Suhu Lm35
· Kipas DC
· Push Button
·
Motor Driver l298N
· Breadboard
· Adaptor
· Resistor
b. Rangkaian
d. Listing Program
#include "main.h"
ADC_HandleTypeDef hadc1; TIM_HandleTypeDef htim1;
void SystemClock_Config(void); static void MX_GPIO_Init(void);
static void MX_ADC1_Init(void); static void MX_TIM1_Init(void);
uint32_t adcValue = 0;
float voltage = 0; float temperature = 0;
uint8_t system_on = 1;
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_ADC1_Init(); MX_TIM1_Init();
HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1); while (1)
{
HAL_ADC_Start(&hadc1);
HAL_ADC_PollForConversion(&hadc1, HAL_MAX_DELAY); adcValue =
HAL_ADC_GetValue(&hadc1);
voltage = ( adcValue / 4095.0) * 3.3;
temperature = ( voltage * 100);
if(system_on)
{
if(temperature >= 27.0)
{
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_2, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_3, GPIO_PIN_RESET);
float
duty; if(temperature >= 35.0)
{
duty = 0.5;
}
else
|
|
{ duty = 1.0 - ((temperature - 27.0) / 8.0) *
0.5; } HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_1, duty * 65535); } else { HAL_GPIO_WritePin(GPIOA, GPIO_PIN_2, GPIO_PIN_RESET); HAL_GPIO_WritePin(GPIOA, GPIO_PIN_3, GPIO_PIN_RESET); HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_1, 0); } } else { HAL_GPIO_WritePin(GPIOA, GPIO_PIN_2, GPIO_PIN_RESET); HAL_GPIO_WritePin(GPIOA, GPIO_PIN_3, GPIO_PIN_RESET); HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_1, 0); } HAL_Delay(200); } } 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.PLL.PLLState =
RCC_PLL_NONE; HAL_RCC_OscConfig(&RCC_OscInitStruct); RCC_ClkInitStruct.ClockType
= RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2; RCC_ClkInitStruct.SYSCLKSource
= RCC_SYSCLKSOURCE_HSI; HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0); PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_ADC;
PeriphClkInit.AdcClockSelection = RCC_ADCPCLK2_DIV2; HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit); } 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.ExternalTrigConv = ADC_SOFTWARE_START;
hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT; hadc1.Init.NbrOfConversion = 1; HAL_ADC_Init(&hadc1); sConfig.Channel
= ADC_CHANNEL_0; sConfig.Rank = ADC_REGULAR_RANK_1; sConfig.SamplingTime = ADC_SAMPLETIME_71CYCLES_5; HAL_ADC_ConfigChannel(&hadc1, &sConfig); } static void MX_TIM1_Init(void) { TIM_OC_InitTypeDef sConfigOC = {0}; htim1.Instance = TIM1;
htim1.Init.Prescaler = 0; htim1.Init.CounterMode = TIM_COUNTERMODE_UP;
htim1.Init.Period = 65535; HAL_TIM_PWM_Init(&htim1); sConfigOC.OCMode = TIM_OCMODE_PWM1;
sConfigOC.Pulse = 0; sConfigOC.OCPolarity
= TIM_OCPOLARITY_HIGH; HAL_TIM_PWM_ConfigChannel(&htim1, &sConfigOC, TIM_CHANNEL_1); HAL_TIM_MspPostInit(&htim1); } static void MX_GPIO_Init(void) { GPIO_InitTypeDef GPIO_InitStruct = {0}; HAL_RCC_GPIOA_CLK_ENABLE(); GPIO_InitStruct.Pin = GPIO_PIN_2 | GPIO_PIN_3;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Speed =
GPIO_SPEED_FREQ_LOW; HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); GPIO_InitStruct.Pin =
GPIO_PIN_4; GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING;
GPIO_InitStruct.Pull = GPIO_PULLUP; HAL_GPIO_Init(GPIOA,
&GPIO_InitStruct); HAL_NVIC_SetPriority(EXTI4_IRQn, 0,
0); |
|
||
|
|
HAL_NVIC_EnableIRQ(EXTI4_IRQn); } void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) { if(GPIO_Pin == GPIO_PIN_4) { system_on = !system_on; } } void Error_Handler(void) { disable_irq(); while (1)
{} } |
|
||
4. Sistem Lampu Jalan Otomatis
a. Alat dan Bahan
·
STM32 Nucleo G474RE
· LED
· LDR Sensor
· PIR Sensor
· Push Button
·
Breadboard
· Jumper
· Resistor
b. Rangkaian
c. Flowchart
d. Listing Program
#include "main.h"
// HANDLE
ADC_HandleTypeDef hadc1; TIM_HandleTypeDef htim3;
// VARIABLE
volatile uint8_t
emergency_mode = 0; uint32_t last_motion_time = 0;
// fallback tombol
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
// ================= 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 =================
void MX_GPIO_Init(void)
{
HAL_RCC_GPIOA_CLK_ENABLE();
HAL_RCC_GPIOB_CLK_ENABLE();
GPIO_InitTypeDef GPIO_InitStruct = {0};
// PIR → PA1
|
|
GPIO_InitStruct.Pin
= GPIO_PIN_1; GPIO_InitStruct.Mode = GPIO_MODE_INPUT; GPIO_InitStruct.Pull =
GPIO_NOPULL; HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
// BUTTON → PB1 (PULL-UP + INTERRUPT) GPIO_InitStruct.Pin
= GPIO_PIN_1; GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING;
GPIO_InitStruct.Pull = GPIO_PULLUP; HAL_GPIO_Init(GPIOB,
&GPIO_InitStruct);
// LED PWM → PA6 GPIO_InitStruct.Pin
= GPIO_PIN_6; 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(GPIOA,
&GPIO_InitStruct);
//
IRQ untuk PB1 (EXTI0_1) HAL_NVIC_SetPriority(EXTI0_1_IRQn, 0,
0); HAL_NVIC_EnableIRQ(EXTI0_1_IRQn); }
// ================= ADC ================= 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
================= 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 == GPIO_PIN_1) { emergency_mode = !emergency_mode; } }
// ================= HELPER
================= 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 ================= 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
===== uint8_t current_button = HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_1);
if (last_button_state == 1 && current_button == 0) { emergency_mode = !emergency_mode;
HAL_Delay(50); }
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(GPIOA, GPIO_PIN_1);
// 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); } |
|
||
|
|
} |
|
||
Tidak ada komentar:
Posting Komentar