MODUL II
PWM, ADC, INTERRUPT, & MILLIS
- Praktikkan telah membuat rangkaian tugas pendahuluan sebelum asistensi dilaksanakan
- Praktikkan melaksanakan asistensi sebelum praktikum dilaksanakan
- Praktikkan melaksanakan praktikum
- Memahami cara penggunaan PWM, ADC, Interrupt, dan Millis pada Development Board yang digunakan
- Memahami cara menggunakan komponen input dan output yang mengimplementasikan PWM, ADC, Interrupt, dan Millis pada Development Board yang digunakan
- Raspberry Pi Pico
- STM32F103C8
- LED
- Push Button
- LED RGB
- Touch Sensor
- Sensor Soil Moisture
- Potensiometer
- DHT22
- Motor DC (Dinamo DC, Motor Servo, dan Motor Stepper
- LDR dan Photodioda
- Breadboard
- Resistor
- Transistor
- Driver Motor Stepper ULN2003
4.1 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 Raspberry Pi Pico, terdapat blok
PWM yang terdiri dari 8 unit (slice), dan masing-masing slice dapat mengendalikan dua sinyal PWM atau
mengukur frekuensi serta duty cycle dari sinyal input. Dengan total 16 output
PWM yang dapat dikontrol, semua 30 pin GPIO bisa digunakan untuk PWM. Setiap
slice memiliki fitur utama seperti penghitung 16-bit, pembagi clock presisi,
dua output independen dengan duty cycle 0–100%, serta mode pengukuran frekuensi
dan duty cycle. PWM pada Raspberry Pi Pico juga mendukung pengaturan fase
secara presisi serta dapat diaktifkan atau dinonaktifkan secara bersamaan
melalui satu register kontrol global, sehingga memungkinkan sinkronisasi
beberapa output untuk aplikasi yang lebih kompleks.
4.2 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.
Raspberry Pi Pico memiliki empat ADC (Analog-to-Digital Converter)
12-bit dengan metode SAR, tetapi hanya tiga kanal yang
dapat digunakan secara eksternal, yaitu ADC0, ADC1, dan ADC2, yang terhubung ke
pin GP26, GP27, dan GP28. Kanal keempat (ADC4) digunakan secara
internal untuk membaca suhu dari sensor suhu bawaan. Konversi ADC dapat
dilakukan dalam tiga mode: polling, interrupt, dan FIFO dengan DMA. Kecepatan
konversi ADC adalah 2μs per sampel atau 500 ribu sampel per detik (500kS/s).
Mikrocontroller RP2040 berjalan pada frekuensi 48MHz yang berasal dari USB PLL,
dan setiap konversi ADC membutuhkan 96 siklus CPU, sehingga waktu samplingnya
adalah 2μs per sampel.
4.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 RP2040, setiap inti prosesor
dilengkapi dengan ARM Nested Vectored Interrupt Controller (NVIC) yang memiliki
32 jalur interrupt. Namun, hanya 26 jalur pertama yang digunakan, sedangkan
jalur IRQ 26 hingga 31 tidak aktif. Setiap NVIC menerima interrupt yang sama,
kecuali untuk GPIO, di mana setiap bank GPIO memiliki satu interrupt per inti.
Ini berarti, misalnya, core 0 dapat menerima interrupt dari GPIO 0 di bank 0,
sementara core 1 menerima interrupt dari GPIO 1 di bank yang sama secara
independen. Jika diperlukan, inti prosesor masih bisa dipaksa
masuk ke
interrupt handler dengan
menulis bit 26 hingga 31 pada register
NVIC ISPR.
4.4 MILLIS
Fungsi millis() pada mikrokontroler,
seperti pada platform Arduino dan STM32 (dengan HAL), digunakan untuk
menghitung waktu dalam milidetik sejak perangkat mulai berjalan. Berbeda dengan
delay(), yang menghentikan eksekusi program selama waktu tertentu, millis()
memungkinkan sistem untuk
menjalankan beberapa tugas secara bersamaan tanpa menghentikan proses
lainnya. Hal ini berguna dalam aplikasi yang memerlukan multitasking berbasis
waktu, seperti pengendalian sensor, komunikasi serial, atau implementasi sistem
real-time. Dalam STM32 dengan HAL, millis() dapat diimplementasikan menggunakan
HAL_GetTick(), yang mengandalkan interrupt timer internal untuk mencatat waktu
yang terus berjalan sejak mikrokontroler diaktifkan.
Sementara itu, pada platform seperti Raspberry Pi Pico yang
sering diprogram menggunakan MicroPython, fungsi utime.ticks_ms() menyediakan
fungsionalitas yang sepadan. Fungsi ini mengembalikan nilai penghitung milidetik yang bersifat monotonik (terus
bertambah) sejak sistem dimulai atau modul utime dimuat. Sama seperti millis()
dan HAL_GetTick(), nilai ticks_ms() juga akan mengalami wrap-around (kembali ke nol) setelah mencapai batasnya, sehingga
penggunaan fungsi utime.ticks_diff() menjadi penting untuk perhitungan selisih
waktu yang akurat dan aman terhadap overflow.
Dengan demikian, utime.ticks_ms() memungkinkan implementasi pola penjadwalan
dan delay non-blocking yang serupa
untuk menciptakan aplikasi yang responsif di lingkungan MicroPython.
4.5 Raspberry Pi Pico
Raspberry Pi Pico adalah papan rangkaian
elektronik yang di dalamnya terdapat komponen utama chip mikrokontroler RP2040,
yang dirancang dan diproduksi oleh Raspberry Pi Foundatio. Tidak seperti
komputer mini raspberry Pi lainnya
yang menjalankan sistem
operasi seperti Linux, Pico dirancang untuk tugas-tugas yang lebih sederhana
dan langsung (embedded
system), seperti membaca sensor, mengontrol perangkat, atau melakukan
pengolahan data pada tingkat hardware.
Adapun spesifikasi dari Raspberry Pi Pico adalah sebagai berikut:
Gambar 1. Arduino
Uno
Microcontroller RP2040 |
Operating Voltage 3.3 V |
Input Voltage (recommended) 5 V via USB |
Input Voltage (limit) 1.8–5.5 V |
Digital I/O
Pins 26 GPIO
pins |
PWM Digital I/O Pins 16 |
Analog Input
Pins 3 |
DC Current per I/O Pin 16 mA |
DC Current for 3.3V Pin 300 mA |
Flash Memory 2 MB on-board QSPI
Flash |
SRAM 264
KB |
Clock Speed Hingga 133 MHz |
4.6 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:
Gambar 3. STM32F103C8
Microcontroller 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. Raspberry Pi Pico
1. RAM (Random
Access Memory)
Raspberry Pi Pico dilengkapi dengan 264KB SRAM on-chip. Kapasitas RAM
yang lebih besar ini memungkinkan Pico menjalankan aplikasi yang lebih kompleks
dan menyimpan data lebih banyak.
2. Memori Flash Eksternal
Raspberry Pi Pico tidak memiliki
ROM tradisional. Sebagai
gantinya, ia menggunakan memori flash eksternal. Kapasitas memori flash ini dapat bervariasi, umumnya antara 2MB
hingga 16MB, tergantung pada konfigurasi. Memori flash ini digunakan untuk
menyimpan firmware dan program pengguna. Penggunaan memori flash eksternal pada
Pico memberikan fleksibilitas lebih besar dalam hal kapasitas penyimpanan program.
3. Crystal Oscillator
Raspberry Pi Pico menggunakan crystal oscillator untuk menghasilkan
sinyal clock yang stabil. Sinyal
clock ini penting
untuk mengatur kecepatan operasi mikrokontroler
dan komponen lainnya.
4. Regulator Tegangan
Untuk memastikan pasokan
tegangan yang stabil
ke mikrokontroler.
5. Pin GPIO (General Purpose
Input/Output):
Untuk menghubungkan Pico ke berbagai perangkat eksternal seperti
sensor, motor, dan LED.
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.
Led,
Buzzer, & LDR
§
Rangkaian
§ Listing Program
§
Flowchart
2.
Led RGB, Motor
Stepper, & Soil Moisture
§
Rangkaian
§
Listing Program
HAL_GPIO_WritePin(LED_PORT, LED_RED_PIN|LED_BLUE_PIN,
GPIO_PIN_RESET);
}
else { // Mode 3: Oscillate
current_mode = 2;
HAL_GPIO_WritePin(LED_PORT, LED_BLUE_PIN, GPIO_PIN_SET);
HAL_GPIO_WritePin(LED_PORT, LED_RED_PIN|LED_GREEN_PIN,
GPIO_PIN_RESET);
}
}
// Eksekusi
mode switch(current_mode) { case
0: // CW
RunStepper(STEP_SEQ_CW, 10);
break;
case 1:
// CCW RunStepper(STEP_SEQ_CCW, 10); break;
case 2: // Oscillate
if(direction == 0) {
RunStepper(STEP_SEQ_CW, 5);
if(STEPPER_PORT->ODR == (STEPPER_PORT->ODR &
0x00FF) | STEP_SEQ_CW[3])
direction = 1;
} else {
RunStepper(STEP_SEQ_CCW, 5);
if(STEPPER_PORT->ODR == (STEPPER_PORT->ODR &
0x00FF) | STEP_SEQ_CCW[3])
direction = 0;
}
break;
}
}
}
void RunStepper(const uint16_t *sequence, uint8_t speed) {
static uint8_t
step = 0;
STEPPER_PORT->ODR = (STEPPER_PORT->ODR & 0x00FF) | sequence[step];
step = (step + 1)
% 4;
HAL_Delay(speed);
}
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.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT; 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();
}
}
void MX_GPIO_Init(void) {
GPIO_InitTypeDef GPIO_InitStruct = {0};
HAL_RCC_GPIOB_CLK_ENABLE();
// Konfigurasi LED
§
Flowchart
3.
Motor DC (Dinamo DC),Push
Button, Buzzer, & LDR/Photodioda
§
Rangkaian
§
Listing Program
§
Flowchart
4.
Motor
Servo, Buzzer, & Potensiomter
§
Rangkaian
§
Listing Program
§
Flowchart
5.
Motor
Servo, Buzzer, Potensiomter, & DHT22
§
Rangkaian
§
Listing Program
§
Flowchart
6.
Motor Servo, LED RGB, & Potensiometer
§
Rangkaian
§
Listing Program
§
Flowchart
7.
Led RGB, Buzzer,
Soil Moisture, & Push Button
§
Rangkaian
§
Listing Program
update_leds_and_buzzer(HAL_ADC_GetValue(&hadc1), button_state);
}
}
if (button_state == GPIO_PIN_RESET && (HAL_ADC_GetValue(&hadc1)
< ADC_THRESH_MID)) {
if (HAL_GetTick() - last_sound_change > 1000) { last_sound_change = HAL_GetTick(); change_sound_pattern();
}
}
HAL_Delay(10);
}
}
void update_leds_and_buzzer(uint32_t adc_val, uint8_t
btn_state) { HAL_GPIO_WritePin(LED_PORT, LED_RED_PIN | LED_GREEN_PIN |
LED_BLUE_PIN, GPIO_PIN_RESET);
if (adc_val >= ADC_THRESH_HIGH) {
HAL_GPIO_WritePin(LED_PORT, LED_GREEN_PIN, GPIO_PIN_SET);
HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_3, 0);
}
else if (adc_val >= ADC_THRESH_MID) {
HAL_GPIO_WritePin(LED_PORT, LED_BLUE_PIN, GPIO_PIN_SET);
HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_3, 0);
}
else {
HAL_GPIO_WritePin(LED_PORT, LED_RED_PIN, GPIO_PIN_SET);
if (btn_state == GPIO_PIN_RESET) {
HAL_TIM_SET_AUTORELOAD(&htim2, pwm_periods[sound_pattern]);
HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_3,
pwm_periods[sound_pattern] / 2);
} else {
HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_3, 0);
}
}
}
void change_sound_pattern(void) { sound_pattern = (sound_pattern + 1) % 3;
if (HAL_ADC_GetValue(&hadc1) < ADC_THRESH_MID
&& HAL_GPIO_ReadPin(BUTTON_PORT, BUTTON_PIN) == GPIO_PIN_SET) {
HAL_TIM_SET_AUTORELOAD(&htim2, pwm_periods[sound_pattern]);
HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_3,
pwm_periods[sound_pattern] / 2);
}
}
void SystemClock_Config(void) { RCC_OscInitTypeDef
RCC_OscInitStruct = {0}; RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON; RCC_OscInitStruct.HSEPredivValue =
RCC_HSE_PREDIV_DIV1; RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON; RCC_OscInitStruct.PLL.PLLSource =
RCC_PLLSOURCE_HSE; RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;
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_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK) Error_Handler();
PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_ADC;
PeriphClkInit.AdcClockSelection = RCC_ADCPCLK2_DIV6;
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_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_GPIOA_CLK_ENABLE();
HAL_RCC_GPIOB_CLK_ENABLE();
GPIO_InitStruct.Pin = LED_RED_PIN | LED_GREEN_PIN | LED_BLUE_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull
= GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(LED_PORT, &GPIO_InitStruct);
GPIO_InitStruct.Pin
= BUTTON_PIN; GPIO_InitStruct.Mode = GPIO_MODE_INPUT; GPIO_InitStruct.Pull =
GPIO_PULLUP; HAL_GPIO_Init(BUTTON_PORT, &GPIO_InitStruct);
}
§
Flowchart
8.
Motor DC (Dinamo DC), Motor Stepper,
Touch Sensor, Potensiometer
§
Rangkaian
§
Listing Program
HAL_ADC_Start(&hadc1);
if (HAL_ADC_PollForConversion(&hadc1, 10) == HAL_OK)
{ uint16_t adc_val = HAL_ADC_GetValue(&hadc1); current_mode = (adc_val < 2048) ? 0 : 1; // 0 = CW, 1 = CCW
}
if (current_mode == 0) { RunStepper(STEP_SEQ_CW, 5);
} else {
RunStepper(STEP_SEQ_CCW, 5);
}
}
HAL_Delay(1);
}
}
void RunStepper(const uint8_t
*sequence, uint8_t speed) {
static uint8_t step = 0;
HAL_GPIO_WritePin(STEPPER_PORT, IN1_PIN, (sequence[step] & (1<<0)) ? GPIO_PIN_SET : GPIO_PIN_RESET);
HAL_GPIO_WritePin(STEPPER_PORT, IN2_PIN, (sequence[step] & (1<<1)) ? GPIO_PIN_SET : GPIO_PIN_RESET);
HAL_GPIO_WritePin(STEPPER_PORT, IN3_PIN, (sequence[step] & (1<<2)) ? GPIO_PIN_SET : GPIO_PIN_RESET);
HAL_GPIO_WritePin(STEPPER_PORT, IN4_PIN, (sequence[step] & (1<<3)) ? GPIO_PIN_SET : GPIO_PIN_RESET);
step = (step + 1) % 4;
HAL_Delay(speed);
}
void MX_GPIO_Init(void) { GPIO_InitTypeDef GPIO_InitStruct = {0};
HAL_RCC_GPIOB_CLK_ENABLE();
HAL_AFIO_REMAP_SWJ_NOJTAG(); // Optional: disable
JTAG to free PB3-PB4 if needed
// Konfigurasi Touch Sensor sebagai
input dengan EXTI (interrupt)
GPIO_InitStruct.Pin = TOUCH_SENSOR_PIN; GPIO_InitStruct.Mode =
GPIO_MODE_IT_RISING_FALLING; GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(TOUCH_SENSOR_PORT, &GPIO_InitStruct);
//
Aktifkan NVIC untuk EXTI0 HAL_NVIC_SetPriority(EXTI0_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(EXTI0_IRQn);
//
Konfigurasi Motor DC (PB7) GPIO_InitStruct.Pin
= MOTOR_DC_PIN;
GPIO_InitStruct.Mode
= GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; HAL_GPIO_Init(MOTOR_DC_PORT, &GPIO_InitStruct);
// Konfigurasi Stepper Motor (PB8-PB11)
GPIO_InitStruct.Pin = IN1_PIN | IN2_PIN | IN3_PIN | IN4_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed
= GPIO_SPEED_FREQ_LOW; HAL_GPIO_Init(STEPPER_PORT, &GPIO_InitStruct);
}
void MX_ADC1_Init(void) { ADC_ChannelConfTypeDef sConfig
= {0};
hadc1.Instance = ADC1;
hadc1.Init.ScanConvMode = ADC_SCAN_DISABLE;
hadc1.Init.ContinuousConvMode
= DISABLE; 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_71CYCLES_5;
if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK) { Error_Handler();
}
}
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.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT; 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)
{
§
Flowchart
0 Komentar