M2 - Laporan Akhir 1



Percobaan 7 

 Led RGB, Buzzer, Soil Moisture, & Push Button

1. Prosedur[Kembali]

    1. Rangkai rangkaian sesuai dengan rangkaian percobaan 7 pada modul 2.
    2. Setelah semua komponen (Buzzer, LED RGB, Push Button, dan Soil Moisture) dihubungkan, lalu hubungkan USB STM32 ke laptop.
    3. Inisaialisasi program menggunakan STM32CubeIDE 
    4. Setelah program selesai, simulasikan rangkaian.
    5. Selesai.


2. Hardware dan Diagram Blok[Kembali]

Hardware :

  • STM32

  • Push button


  • LED RGB

  • Resistor

  • Soil Moisture




  • Buzzer


  • Jumper Cable Wire
  • Beard board





Diagram Blok








3. Rangkaian Simulasi[Kembali]

Rangkailah seperti rangkaian percobaan 7 pada modul 





  • Prinsip Kerja 
      Diawali dengan inisialisasi sistem, yaitu fungsi HAL_Init() untuk menginisialisasi HAL Library, SystemClock_Config() untuk mengatur clock sistem, serta fungsi-fungsi inisialisasi periferal seperti MX_GPIO_Init() untuk konfigurasi pin input/output, MX_ADC1_Init() untuk konfigurasi ADC1, dan MX_TIM2_Init() untuk konfigurasi timer yang digunakan menghasilkan sinyal PWM bagi buzzer.

Setelah semua periferal diinisialisasi, program masuk ke dalam loop utama (while(1)), di mana sistem terus memantau dua hal utama: nilai tegangan dari ADC (yang merepresentasikan sensor) dan status tombol. ADC akan dibaca secara periodik setiap 200 milidetik. Jika ADC berhasil memberikan nilai, maka nilai tersebut digunakan untuk menentukan status output LED dan buzzer dengan memanggil fungsi update_leds_and_buzzer().

Fungsi update_leds_and_buzzer() menentukan output berdasarkan besar nilai ADC:

  • Jika nilai ADC tinggi (≥ 3000), maka LED hijau menyala dan buzzer mati.
  • Jika nilai ADC sedang (≥ 1500 tetapi < 3000), LED biru menyala dan buzzer tetap mati.
  • Jika nilai ADC rendah (< 1500), LED merah menyala. Jika tombol ditekan (btn_state == GPIO_PIN_RESET), buzzer akan menghasilkan suara PWM sesuai pola sound_pattern. Jika tombol tidak ditekan, buzzer akan mati.

Setiap 1 detik, jika tombol ditekan dan ADC < 1500, pola suara buzzer akan berubah ke pola berikutnya (dari array pwm_periods[]) melalui fungsi change_sound_pattern().

PWM untuk buzzer dikendalikan oleh TIM2 Channel 3. Nilai frekuensi ditentukan oleh variabel pwm_periods[], dan duty cycle-nya diatur pada nilai 50% dari periodenya.

Secara umum, alat ini bekerja sebagai indikator level sensor menggunakan LED dan suara. Level tinggi ditunjukkan dengan LED hijau, level sedang dengan biru, dan level rendah dengan merah ditambah buzzer jika tombol ditekan. Selain itu, buzzer dapat berubah frekuensi suaranya setiap kali tombol ditekan dalam kondisi sensor rendah.

 


4. Flowchart dan Listing Program[Kembali]

  • Flowchart








  • Listing Program

#include "stm32f1xx_hal.h"

ADC_HandleTypeDef hadc1;

TIM_HandleTypeDef htim2;

uint8_t sound_pattern = 0;

#define LED_RED_PIN    GPIO_PIN_12

#define LED_GREEN_PIN  GPIO_PIN_13

#define LED_BLUE_PIN   GPIO_PIN_14

#define LED_PORT       GPIOB

#define BUTTON_PIN     GPIO_PIN_0

#define BUTTON_PORT    GPIOB

#define BUZZER_PIN     GPIO_PIN_2

#define ADC_THRESH_HIGH  3000

#define ADC_THRESH_MID   1500

const uint32_t pwm_periods[] = {1000, 50000, 719999};

void SystemClock_Config(void);

static void MX_GPIO_Init(void);

static void MX_ADC1_Init(void);

static void MX_TIM2_Init(void);

void update_leds_and_buzzer(uint32_t adc_val, uint8_t btn_state);

void change_sound_pattern(void);

void Error_Handler(void);

int main(void) {

HAL_Init();

SystemClock_Config();

MX_GPIO_Init();

MX_ADC1_Init();

MX_TIM2_Init();

HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_3);

__HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_3, 0);

HAL_ADC_Start(&hadc1);

while (1) {

static uint32_t last_adc_tick = 0;

static uint32_t last_sound_change = 0;

uint8_t button_state = HAL_GPIO_ReadPin(BUTTON_PORT, BUTTON_PIN);

if (HAL_GetTick() - last_adc_tick > 200) {

last_adc_tick = HAL_GetTick();

HAL_ADC_Start(&hadc1);

if (HAL_ADC_PollForConversion(&hadc1, 10) == HAL_OK) {

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);

}

void Error_Handler(void) {

__disable_irq();

while (1) {}

}



5. Video Demo[Kembali]








6. Analisa[Kembali]

ANALISA MODUL 2: PWM, ADC, INTERRUPT, & MILLIS 

1. Analisa bagaimana perbedaan implementasi PWM antara STM32 dan Raspberry Pi Pico serta dampaknya terhadap kontrol motor dan Buzzer ?

STM32 menggunakan timer hardware yang dikonfigurasi melalui register prescaler dan auto-reload untuk mengatur frekuensi PWM, sedangkan duty cycle diatur melalui capture/compare register (CCR). Pendekatan ini memberikan resolusi tinggi (hingga 16-bit) dan presisi yang baik, sehingga cocok untuk aplikasi seperti kontrol motor yang membutuhkan respons halus atau buzzer yang memerlukan frekuensi stabil.

Raspberry Pi Pico menggunakan modul PWM terpisah yang tidak bergantung pada timer khusus. Frekuensi PWM diatur melalui pembagi integer, yang kurang presisi dibanding STM32. Resolusi defaultnya 8-bit (dapat ditingkatkan), sehingga lebih sederhana tetapi kurang akurat untuk aplikasi yang membutuhkan ketepatan tinggi. Akibatnya, kontrol motor mungkin kurang halus, dan frekuensi buzzer bisa memiliki variasi lebih besar.

2. Analisa bagaimana cara pembacaan nilai sensor analog menggunakan ADC pada STM32 dan Raspberry Pi Pico ?

Pada STM32, ADC bekerja dengan multi-channel dan dapat menggunakan DMA untuk pembacaan efisien tanpa intervensi CPU. Sampling rate diatur melalui konfigurasi clock dan sample time register, serta dilengkapi kalibrasi internal untuk meningkatkan akurasi. Pembacaan nilai ADC biasanya menggunakan fungsi HAL seperti HAL_ADC_Start() dan HAL_ADC_GetValue().

Raspberry Pi Pico memiliki ADC 12-bit dengan 4 channel (termasuk satu channel untuk sensor suhu internal). Pembacaannya lebih sederhana karena tidak memerlukan konfigurasi kompleks seperti STM32. Nilai ADC dapat dibaca langsung menggunakan fungsi read_u16() dari library ADC Pico. Namun, Pico tidak memiliki fitur kalibrasi otomatis, sehingga mungkin memerlukan kalibrasi manual jika dibutuhkan akurasi tinggi.

3. Analisa bagaimana penggunaan interrupt eksternal dalam mendeteksi input dari sensor pada STM32 dan Raspberry Pi Pico ?

Di STM32, interrupt eksternal dikonfigurasi melalui EXTI (External Interrupt) dan dihubungkan ke pin GPIO tertentu. Setiap perubahan tegangan (rising/falling edge) dapat memicu interrupt handler yang ditentukan, misalnya menggunakan HAL dengan callback seperti HAL_GPIO_EXTI_Callback(). Pendekatan ini efisien untuk respon cepat terhadap sensor seperti encoder atau limit switch.

Pada Raspberry Pi Pico, interrupt eksternal diatur melalui fungsi gpio_set_irq_enabled_with_callback(), yang memungkinkan penanganan interrupt berbasis event pada pin tertentu. Pico menggunakan mekanisme IRQ handler yang fleksibel tetapi memerlukan pengaturan manual untuk filter debouncing atau prioritas interrupt.

4. Analisa bagaimana cara kerja fungsi HAL_GetTick() pada STM32 dan utime.ticks_ms() pada Raspberry Pi Pico dalam menghitung waktu sejak sistem dinyalakan ?

HAL_GetTick() di STM32 mengembalikan nilai millisecond sejak sistem mulai, menggunakan SysTick timer yang di-update oleh interrupt berkala. Fungsi ini bergantung pada konfigurasi HAL dan biasanya memiliki resolusi 1ms.

Pada Raspberry Pi Pico, utime.ticks_ms() juga mengembalikan waktu dalam milidetik, tetapi menggunakan timer hardware internal Pico yang tidak tergantung pada interrupt. Pico menggunakan timer 64-bit yang terus bertambah, sehingga lebih stabil untuk penghitungan waktu jangka panjang tanpa overflow.

5. Analisa bagaimana perbedaan konfigurasi dan kontrol pin PWM serta pemanfaatan timer internal pada STM32 dan Raspberry Pi Pico dalam menghasilkan sinyal gelombang persegi ?

STM32 menghasilkan PWM menggunakan timer hardware (seperti TIM1, TIM2, dll.) yang dapat dikonfigurasi untuk frekuensi dan resolusi berbeda melalui register prescaler dan auto-reload. Setiap channel PWM dihubungkan ke capture/compare register (CCR) untuk mengatur duty cycle. Pendekatan ini memungkinkan multiple PWM dengan sinkronisasi ketat dan fase terkontrol.

Raspberry Pi Pico menggunakan modul PWM independen yang tidak terikat pada timer khusus. Frekuensi PWM diatur melalui pembagi integer dan penghitung wrap, sedangkan duty cycle dikontrol via level threshold. Meskipun lebih sederhana, Pico kurang fleksibel dalam sinkronisasi multiple PWM dibanding STM32. Namun, Pico mendukung lebih banyak pin PWM secara bersamaan tanpa konflik resource timer.

 



7. Download File[Kembali]

HTML [Download]
Listing Program [Download]
Video Demo [Download]  
Datasheet Mikrokontroler STM32F103C8 [Download]
Datasheet Soil Moisture  [Download]
Datasheet Push Button [Download]
Datasheet RGB LED [Download]
Datasheet Buzzer [Download]




Tidak ada komentar:

Posting Komentar

ELEKTRONIKA

 BAHAN PRESENTASI UNTUK MATA KULIAH  ELEKTRONIKA C Disusun Oleh : Abdul Hadi Aldoreza 2210952008 Dosen Pengampu : Dr. Darwison, M.T JURUSAN ...