Input/Output Dasar dengan MicroPython di ESP32
Pada pertemuan kali ini akan membahas dasar-dasar input/output (I/O) menggunakan MicroPython pada ESP32. Mahasiswa akan mempelajari penggunaan GPIO, digital input (button), digital output (LED/buzzer), konsep pull-up/pull-down, PWM dasar, dan cara menggabungkan input dan output dalam satu aplikasi interaktif.
Alat dan Bahan
Hardware:
- ESP32 Development Board yang sudah terinstal MicroPython
- LED (3-5 buah, berbagai warna)
- Resistor 220Ω atau 330Ω (untuk LED)
- Push button atau tactile switch (2-3 buah)
- Resistor 10KΩ (untuk pull-down jika diperlukan)
- Buzzer aktif 3.3V atau 5V
- Breadboard
- Kabel jumper male-to-male
- Kabel jumper male-to-female
Software:
- MicroPython firmware sudah terinstal di ESP32
- Visual Studio Code dengan extension Pymakr
- Serial terminal (PuTTY/Screen) untuk REPL
- Multimeter (opsional, untuk troubleshooting)
Bagian 1: Pengenalan GPIO ESP32
1.1 Konsep GPIO (General Purpose Input/Output)
GPIO adalah pin yang dapat dikonfigurasi sebagai input atau output untuk berinteraksi dengan komponen elektronik eksternal. ESP32 memiliki banyak pin GPIO yang dapat digunakan untuk berbagai keperluan.
Karakteristik GPIO ESP32:
- Voltage Level: 3.3V (toleran hingga 3.6V)
- Current per Pin: Maksimal 12mA per pin
- Total Current: Maksimal 40mA untuk semua pin
- Input Modes: Digital input, analog input (ADC)
- Output Modes: Digital output, PWM, DAC
- Internal Pull: Pull-up dan pull-down internal tersedia
1.2 Pin Layout dan Mapping ESP32
Setiap board ESP32 memiliki pin layout yang sedikit berbeda, namun GPIO numbering tetap sama. Pin GPIO ditandai dengan nomor seperti GPIO2, GPIO4, GPIO18, dan seterusnya.
Praktikum 1.1: Identifikasi Pin GPIO
Langkah 1: Periksa Pin Layout Board
Identifikasi pin-pin penting pada board ESP32 Anda: - Power pins: 3V3, GND, VIN (5V) - GPIO pins: GPIO2, GPIO4, GPIO5, GPIO18, GPIO19, GPIO21, GPIO22, GPIO23 - ADC pins: GPIO32, GPIO33, GPIO34, GPIO35, GPIO36, GPIO39 - Touch pins: GPIO4, GPIO0, GPIO2, GPIO15, GPIO13, GPIO12, GPIO14, GPIO27
Langkah 2: Pin yang Perlu Dihindari
Beberapa pin memiliki fungsi khusus dan sebaiknya dihindari: - GPIO0: Boot mode pin - GPIO2: Built-in LED (pada beberapa board) - GPIO6-11: Terhubung ke flash memory - GPIO34-39: Input only (tidak bisa output)
Langkah 3: Test GPIO dengan REPL
>>> import machine
>>> # Cek pin yang tersedia
>>> dir(machine)
# Akan muncul Pin di daftar
>>> pin2 = machine.Pin(2, machine.Pin.OUT)
>>> pin2.on() # Nyalakan (jika ada LED built-in)
>>> pin2.off() # Matikan
1.3 Konfigurasi GPIO Dasar
GPIO dapat dikonfigurasi dalam berbagai mode sesuai kebutuhan. Mode utama adalah input dan output dengan berbagai opsi tambahan.
Praktikum 1.2: Konfigurasi GPIO Dasar
Langkah 1: Import Module yang Diperlukan
Langkah 2: Konfigurasi Pin Output
>>> # Pin output untuk LED
>>> led_pin = machine.Pin(2, machine.Pin.OUT)
>>>
>>> # Test output
>>> led_pin.on() # Nyalakan
>>> utime.sleep(1)
>>> led_pin.off() # Matikan
Langkah 3: Konfigurasi Pin Input
>>> # Pin input untuk button
>>> button_pin = machine.Pin(4, machine.Pin.IN)
>>>
>>> # Baca status pin
>>> status = button_pin.value()
>>> print(f"Status pin: {status}")
Langkah 4: Konfigurasi dengan Pull Resistor
>>> # Input dengan pull-up internal
>>> button_pullup = machine.Pin(4, machine.Pin.IN, machine.Pin.PULL_UP)
>>>
>>> # Input dengan pull-down internal
>>> button_pulldown = machine.Pin(5, machine.Pin.IN, machine.Pin.PULL_DOWN)
Bagian 2: Digital Output - LED Control
2.1 Dasar-dasar LED Control
LED (Light Emitting Diode) adalah komponen output digital yang paling sederhana. LED memerlukan arus yang dibatasi oleh resistor untuk mencegah kerusakan.
Teori LED:
- Forward Voltage: ~1.8-3.3V (tergantung warna)
- Forward Current: Umumnya 10-20mA
- Resistor Calculation: R = (Vcc - Vf) / If
- Untuk ESP32: R = (3.3V - 2.0V) / 0.015A = 87Ω (gunakan 220Ω atau 330Ω)
2.2 Rangkaian LED dengan ESP32
Ada dua cara memasang LED: current sourcing dan current sinking. Untuk ESP32, current sinking lebih direkomendasikan.
Praktikum 2.1: Rangkaian LED Dasar
Langkah 1: Siapkan Komponen
Komponen yang diperlukan: - LED (warna bebas) - Resistor 220Ω atau 330Ω - Kabel jumper - Breadboard
Langkah 2: Buat Rangkaian
Rangkaian Current Sinking (direkomendasikan):
Atau rangkaian Current Sourcing:
Langkah 3: Test LED dengan REPL
>>> import machine
>>> import utime
>>>
>>> # Inisialisasi pin untuk LED
>>> led = machine.Pin(18, machine.Pin.OUT)
>>>
>>> # Test LED
>>> led.on()
>>> utime.sleep(1)
>>> led.off()
2.3 Program LED Sederhana
Setelah rangkaian bekerja, kita akan membuat berbagai program untuk mengontrol LED dengan pola yang berbeda.
Praktikum 2.2: Program LED Blinking
Langkah 1: Buat File led_basic.py
# led_basic.py - Program LED dasar
import machine
import utime
class LEDController:
"""Class untuk mengontrol LED"""
def __init__(self, pin_number):
"""Inisialisasi LED controller"""
self.led = machine.Pin(pin_number, machine.Pin.OUT)
self.state = False
print(f"LED controller initialized on GPIO{pin_number}")
def on(self):
"""Nyalakan LED"""
self.led.on()
self.state = True
print("LED ON")
def off(self):
"""Matikan LED"""
self.led.off()
self.state = False
print("LED OFF")
def toggle(self):
"""Toggle LED state"""
if self.state:
self.off()
else:
self.on()
def blink(self, times=5, delay=0.5):
"""Blink LED beberapa kali"""
print(f"Blinking LED {times} times")
for i in range(times):
self.on()
utime.sleep(delay)
self.off()
utime.sleep(delay)
print("Blinking complete")
# Test LED controller
if __name__ == "__main__":
# Inisialisasi LED pada GPIO18
led_controller = LEDController(18)
# Test basic operations
print("=== LED Test Started ===")
# Test on/off
led_controller.on()
utime.sleep(2)
led_controller.off()
utime.sleep(1)
# Test toggle
for i in range(4):
led_controller.toggle()
utime.sleep(0.5)
# Test blink
led_controller.blink(3, 0.3)
print("=== LED Test Complete ===")
Langkah 2: Upload dan Test
- Upload file ke ESP32 menggunakan VSCode
- Jalankan dengan:
exec(open('led_basic.py').read())
2.4 Multiple LED Control
Mengontrol beberapa LED sekaligus untuk membuat pola yang lebih menarik.
Praktikum 2.3: Multiple LED Pattern
Langkah 1: Siapkan Hardware
- Pasang 3 LED pada GPIO18, GPIO19, GPIO21
- Masing-masing dengan resistor 220Ω
- Hubungkan ke breadboard dengan rapi
Langkah 2: Buat File multi_led.py
# multi_led.py - Kontrol multiple LED
import machine
import utime
class MultiLEDController:
"""Controller untuk multiple LED"""
def __init__(self, pin_list):
"""Inisialisasi dengan list pin GPIO"""
self.leds = []
self.pin_numbers = pin_list
# Inisialisasi setiap LED
for pin in pin_list:
led = machine.Pin(pin, machine.Pin.OUT)
led.off() # Pastikan LED mati di awal
self.leds.append(led)
print(f"Multi LED controller initialized with pins: {pin_list}")
def all_on(self):
"""Nyalakan semua LED"""
for led in self.leds:
led.on()
print("All LEDs ON")
def all_off(self):
"""Matikan semua LED"""
for led in self.leds:
led.off()
print("All LEDs OFF")
def set_pattern(self, pattern):
"""Set pola LED berdasarkan list boolean"""
if len(pattern) != len(self.leds):
print("Error: Pattern length mismatch")
return
for i, state in enumerate(pattern):
if state:
self.leds[i].on()
else:
self.leds[i].off()
def running_light(self, cycles=3, delay=0.2):
"""Efek running light"""
print(f"Running light effect - {cycles} cycles")
for cycle in range(cycles):
# Maju
for i in range(len(self.leds)):
self.all_off()
self.leds[i].on()
utime.sleep(delay)
# Mundur
for i in range(len(self.leds)-2, 0, -1):
self.all_off()
self.leds[i].on()
utime.sleep(delay)
self.all_off()
def wave_effect(self, cycles=2, delay=0.15):
"""Efek gelombang"""
print(f"Wave effect - {cycles} cycles")
patterns = [
[True, False, False],
[True, True, False],
[False, True, True],
[False, False, True],
[False, True, False],
]
for cycle in range(cycles):
for pattern in patterns:
self.set_pattern(pattern)
utime.sleep(delay)
self.all_off()
def blink_all(self, times=5, delay=0.3):
"""Blink semua LED bersamaan"""
print(f"Blinking all LEDs {times} times")
for i in range(times):
self.all_on()
utime.sleep(delay)
self.all_off()
utime.sleep(delay)
# Test multiple LED
if __name__ == "__main__":
# Inisialisasi 3 LED
led_pins = [18, 19, 21]
multi_led = MultiLEDController(led_pins)
print("=== Multiple LED Test Started ===")
# Test basic operations
multi_led.all_on()
utime.sleep(1)
multi_led.all_off()
utime.sleep(1)
# Test patterns
patterns = [
[True, False, False],
[False, True, False],
[False, False, True],
[True, True, False],
[True, False, True],
[False, True, True],
[True, True, True]
]
for pattern in patterns:
multi_led.set_pattern(pattern)
utime.sleep(0.5)
multi_led.all_off()
utime.sleep(1)
# Test effects
multi_led.running_light(2, 0.15)
utime.sleep(1)
multi_led.wave_effect(2, 0.1)
utime.sleep(1)
multi_led.blink_all(3, 0.2)
print("=== Multiple LED Test Complete ===")
Bagian 3: Digital Input - Button Control
3.1 Dasar-dasar Digital Input
Digital input digunakan untuk membaca sinyal digital dari sensor, switch, atau button. ESP32 dapat membaca level HIGH (3.3V) atau LOW (0V).
Konsep Pull-up dan Pull-down:
- Pull-up: Resistor menghubungkan pin ke VCC (3.3V)
- Pull-down: Resistor menghubungkan pin ke GND (0V)
- Internal Pull: ESP32 memiliki pull-up/down internal yang dapat diaktifkan
- Floating Input: Input tanpa pull resistor, tidak stabil
3.2 Rangkaian Button dengan ESP32
Button dapat dihubungkan dengan dua metode: active HIGH atau active LOW. Active LOW lebih umum digunakan.
Praktikum 3.1: Rangkaian Button Dasar
Langkah 1: Siapkan Komponen
- Push button atau tactile switch
- Resistor 10KΩ (untuk external pull-down, opsional)
- Kabel jumper
- Breadboard
Langkah 2: Rangkaian Active LOW (dengan internal pull-up)
Button: satu kaki ke GPIO, kaki lainnya ke GND
ESP32: GPIO pin dikonfigurasi dengan PULL_UP internal
Langkah 3: Test Button dengan REPL
>>> import machine
>>> import utime
>>>
>>> # Button dengan pull-up internal (active LOW)
>>> button = machine.Pin(4, machine.Pin.IN, machine.Pin.PULL_UP)
>>>
>>> # Test button
>>> while True:
... if button.value() == 0: # Button ditekan
... print("Button pressed!")
... utime.sleep_ms(100)
...
# Tekan Ctrl+C untuk keluar
3.3 Program Button Input
Membuat program untuk membaca input button dengan proper debouncing dan event handling.
Praktikum 3.2: Button Input dengan Debouncing
Langkah 1: Buat File button_input.py
# button_input.py - Program button input dengan debouncing
import machine
import utime
class ButtonInput:
"""Class untuk handling button input"""
def __init__(self, pin_number, pull_up=True, debounce_ms=50):
"""Inisialisasi button input"""
self.pin_number = pin_number
self.debounce_ms = debounce_ms
self.last_state = 1 if pull_up else 0
self.last_time = 0
self.pull_up = pull_up
# Konfigurasi pin
if pull_up:
self.button = machine.Pin(pin_number, machine.Pin.IN, machine.Pin.PULL_UP)
else:
self.button = machine.Pin(pin_number, machine.Pin.IN, machine.Pin.PULL_DOWN)
print(f"Button initialized on GPIO{pin_number} ({'pull-up' if pull_up else 'pull-down'})")
def read_raw(self):
"""Baca nilai raw button"""
return self.button.value()
def is_pressed(self):
"""Cek apakah button ditekan (dengan debouncing)"""
current_time = utime.ticks_ms()
current_state = self.button.value()
# Tentukan nilai pressed berdasarkan pull configuration
pressed_value = 0 if self.pull_up else 1
# Debouncing logic
if current_state != self.last_state:
if utime.ticks_diff(current_time, self.last_time) > self.debounce_ms:
self.last_state = current_state
self.last_time = current_time
return current_state == pressed_value
return False
def wait_for_press(self, timeout_ms=None):
"""Tunggu button ditekan"""
start_time = utime.ticks_ms()
print("Waiting for button press...")
while True:
if self.is_pressed():
print("Button pressed!")
return True
# Cek timeout
if timeout_ms and utime.ticks_diff(utime.ticks_ms(), start_time) > timeout_ms:
print("Timeout waiting for button press")
return False
utime.sleep_ms(10)
def count_presses(self, duration_ms=10000):
"""Hitung jumlah penekanan button dalam durasi tertentu"""
start_time = utime.ticks_ms()
count = 0
print(f"Counting button presses for {duration_ms}ms...")
while utime.ticks_diff(utime.ticks_ms(), start_time) < duration_ms:
if self.is_pressed():
count += 1
print(f"Press count: {count}")
# Tunggu button dilepas
while self.read_raw() == (0 if self.pull_up else 1):
utime.sleep_ms(10)
utime.sleep_ms(10)
print(f"Total presses: {count}")
return count
# Test button input
if __name__ == "__main__":
# Inisialisasi button pada GPIO4 dengan pull-up
button = ButtonInput(4, pull_up=True)
print("=== Button Input Test Started ===")
# Test 1: Simple press detection
print("\nTest 1: Press the button 3 times")
for i in range(3):
button.wait_for_press()
print(f"Press {i+1}/3 detected!")
utime.sleep(0.5)
# Test 2: Count presses
print("\nTest 2: Press the button as many times as you can in 5 seconds")
total_presses = button.count_presses(5000)
print(f"You pressed the button {total_presses} times!")
print("=== Button Input Test Complete ===")
3.4 Multiple Button Input
Mengelola multiple button input untuk membuat interface yang lebih kompleks.
Praktikum 3.3: Multiple Button dengan Menu
Langkah 1: Siapkan Hardware
- Pasang 3 button pada GPIO4, GPIO5, GPIO23
- Hubungkan satu kaki ke GPIO, kaki lainnya ke GND
- Akan menggunakan pull-up internal
Langkah 2: Buat File multi_button.py
# multi_button.py - Multiple button input dengan menu
import machine
import utime
class MultiButtonMenu:
"""Class untuk menu dengan multiple button"""
def __init__(self, button_pins):
"""Inisialisasi multiple button"""
self.buttons = []
self.button_names = ['Button 1', 'Button 2', 'Button 3']
# Inisialisasi setiap button
for pin in button_pins:
button = machine.Pin(pin, machine.Pin.IN, machine.Pin.PULL_UP)
self.buttons.append(button)
# State tracking untuk debouncing
self.last_states = [1] * len(self.buttons)
self.last_times = [0] * len(self.buttons)
self.debounce_ms = 50
print(f"Multi-button menu initialized with {len(self.buttons)} buttons")
def get_button_press(self):
"""Mendapatkan button yang ditekan (dengan debouncing)"""
current_time = utime.ticks_ms()
for i, button in enumerate(self.buttons):
current_state = button.value()
# Deteksi perubahan state (dari 1 ke 0 untuk active LOW)
if current_state == 0 and self.last_states[i] == 1:
if utime.ticks_diff(current_time, self.last_times[i]) > self.debounce_ms:
self.last_states[i] = current_state
self.last_times[i] = current_time
return i # Return index button yang ditekan
# Update state
if current_state != self.last_states[i]:
if utime.ticks_diff(current_time, self.last_times[i]) > self.debounce_ms:
self.last_states[i] = current_state
self.last_times[i] = current_time
return None
def show_menu(self):
"""Tampilkan menu"""
print("\n" + "="*40)
print(" BUTTON MENU")
print("="*40)
print("Button 1 (GPIO4): Option A")
print("Button 2 (GPIO5): Option B")
print("Button 3 (GPIO23): Exit")
print("="*40)
print("Press any button to select...")
def handle_menu_selection(self, button_index):
"""Handle pemilihan menu"""
if button_index == 0:
print("\n>>> Option A Selected!")
print("Executing Option A...")
# Simulasi task Option A
for i in range(3):
print(f"Option A task {i+1}/3")
utime.sleep(0.5)
print("Option A complete!")
elif button_index == 1:
print("\n>>> Option B Selected!")
print("Executing Option B...")
# Simulasi task Option B
for i in range(5):
print(f"Option B progress: {(i+1)*20}%")
utime.sleep(0.3)
print("Option B complete!")
elif button_index == 2:
print("\n>>> Exit Selected!")
return False # Signal untuk keluar
return True # Continue menu
def run_menu(self):
"""Jalankan menu interaktif"""
running = True
self.show_menu()
while running:
button_pressed = self.get_button_press()
if button_pressed is not None:
print(f"\n{self.button_names[button_pressed]} pressed!")
running = self.handle_menu_selection(button_pressed)
if running:
print("\nPress any button for next action...")
utime.sleep(0.5) # Delay untuk clarity
utime.sleep_ms(10) # Polling delay
print("Menu exited. Goodbye!")
def button_test(self):
"""Test semua button"""
print("\n=== Button Test Mode ===")
print("Press each button to test. Press all buttons together to exit.")
while True:
button_pressed = self.get_button_press()
if button_pressed is not None:
print(f"{self.button_names[button_pressed]} works!")
# Cek apakah semua button ditekan bersamaan
all_pressed = all(button.value() == 0 for button in self.buttons)
if all_pressed:
print("All buttons pressed! Exiting test mode...")
break
utime.sleep_ms(10)
# Test multi-button menu
if __name__ == "__main__":
# Inisialisasi menu dengan 3 button
button_pins = [4, 5, 23]
menu = MultiButtonMenu(button_pins)
print("=== Multi-Button Menu Test ===")
# Test individual buttons first
menu.button_test()
utime.sleep(1)
# Run interactive menu
menu.run_menu()
Bagian 4: Kombinasi Input/Output - Interactive Applications
4.1 LED Control dengan Button
Menggabungkan button input dengan LED output untuk membuat aplikasi interaktif sederhana.
Praktikum 4.1: Button Controlled LED
Langkah 1: Siapkan Hardware
- 1 LED dengan resistor pada GPIO18
- 1 Button pada GPIO4 (pull-up internal)
- Hubungkan semuanya ke breadboard
Langkah 2: Buat File button_led.py
# button_led.py - LED control dengan button
import machine
import utime
class ButtonLEDController:
"""Controller untuk LED yang dikontrol button"""
def __init__(self, led_pin, button_pin):
"""Inisialisasi LED dan button"""
# Setup LED
self.led = machine.Pin(led_pin, machine.Pin.OUT)
self.led.off()
self.led_state = False
# Setup button dengan pull-up internal
self.button = machine.Pin(button_pin, machine.Pin.IN, machine.Pin.PULL_UP)
# Debouncing variables
self.last_button_state = 1
self.last_debounce_time = 0
self.debounce_delay = 50
print(f"Button-LED controller initialized")
print(f"LED: GPIO{led_pin}, Button: GPIO{button_pin}")
def read_button_debounced(self):
"""Baca button dengan debouncing"""
current_state = self.button.value()
current_time = utime.ticks_ms()
# Deteksi perubahan state
if current_state != self.last_button_state:
if utime.ticks_diff(current_time, self.last_debounce_time) > self.debounce_delay:
self.last_button_state = current_state
self.last_debounce_time = current_time
# Return True jika button baru ditekan (1 -> 0 transition)
return current_state == 0
return False
def toggle_led(self):
"""Toggle LED state"""
self.led_state = not self.led_state
if self.led_state:
self.led.on()
print("LED ON")
else:
self.led.off()
print("LED OFF")
def mode_toggle(self):
"""Mode: Toggle LED setiap kali button ditekan"""
print("=== Toggle Mode ===")
print("Press button to toggle LED. Press and hold for 3 seconds to exit.")
hold_start_time = None
while True:
# Cek button press untuk toggle
if self.read_button_debounced():
self.toggle_led()
hold_start_time = None # Reset hold timer
# Cek button hold untuk exit
if self.button.value() == 0: # Button sedang ditekan
if hold_start_time is None:
hold_start_time = utime.ticks_ms()
elif utime.ticks_diff(utime.ticks_ms(), hold_start_time) > 3000:
print("Exiting toggle mode...")
break
else:
hold_start_time = None
utime.sleep_ms(10)
def mode_momentary(self):
"""Mode: LED nyala selama button ditekan"""
print("=== Momentary Mode ===")
print("LED will be on while button is pressed.")
print("Press and hold for 3 seconds to exit.")
hold_start_time = None
exit_mode = False
while not exit_mode:
button_state = self.button.value()
if button_state == 0: # Button ditekan
if not self.led_state:
self.led.on()
self.led_state = True
print("LED ON (momentary)")
# Cek untuk exit
if hold_start_time is None:
hold_start_time = utime.ticks_ms()
elif utime.ticks_diff(utime.ticks_ms(), hold_start_time) > 3000:
print("Exiting momentary mode...")
exit_mode = True
else: # Button tidak ditekan
if self.led_state:
self.led.off()
self.led_state = False
print("LED OFF (momentary)")
hold_start_time = None
utime.sleep_ms(10)
def mode_blink_on_press(self, blink_count=3):
"""Mode: LED blink beberapa kali setiap button ditekan"""
print("=== Blink on Press Mode ===")
print(f"LED will blink {blink_count} times when button is pressed.")
print("Press and hold for 3 seconds to exit.")
hold_start_time = None
while True:
if self.read_button_debounced():
print(f"Button pressed! Blinking LED {blink_count} times...")
# Blink LED
for i in range(blink_count):
self.led.on()
utime.sleep(0.2)
self.led.off()
utime.sleep(0.2)
print("Blink complete!")
hold_start_time = None
# Cek button hold untuk exit
if self.button.value() == 0:
if hold_start_time is None:
hold_start_time = utime.ticks_ms()
elif utime.ticks_diff(utime.ticks_ms(), hold_start_time) > 3000:
print("Exiting blink mode...")
break
else:
hold_start_time = None
utime.sleep_ms(10)
# Pastikan LED mati saat keluar
self.led.off()
self.led_state = False
# Test button-LED controller
if __name__ == "__main__":
# Inisialisasi controller
controller = ButtonLEDController(led_pin=18, button_pin=4)
print("=== Button-LED Controller Test ===")
print("Testing different modes...")
# Test mode toggle
controller.mode_toggle()
utime.sleep(1)
# Test mode momentary
controller.mode_momentary()
utime.sleep(1)
# Test mode blink
controller.mode_blink_on_press(3)
print("=== All tests complete ===")
4.2 Multi-Button LED Pattern Controller
Membuat controller yang lebih kompleks dengan multiple button untuk mengontrol pattern LED.
Praktikum 4.2: Advanced LED Pattern Controller
Langkah 1: Siapkan Hardware
- 3 LED pada GPIO18, GPIO19, GPIO21
- 3 Button pada GPIO4, GPIO5, GPIO23
- Resistor untuk LED (220Ω each)
Langkah 2: Buat File advanced_controller.py
# advanced_controller.py - Advanced LED pattern controller
import machine
import utime
import _thread
class AdvancedLEDController:
"""Advanced controller untuk LED patterns dengan multiple buttons"""
def __init__(self, led_pins, button_pins):
"""Inisialisasi LEDs dan buttons"""
# Setup LEDs
self.leds = []
for pin in led_pins:
led = machine.Pin(pin, machine.Pin.OUT)
led.off()
self.leds.append(led)
# Setup buttons
self.buttons = []
for pin in button_pins:
button = machine.Pin(pin, machine.Pin.IN, machine.Pin.PULL_UP)
self.buttons.append(button)
# State variables
self.current_pattern = 0
self.pattern_running = False
self.pattern_thread = None
self.button_states = [1] * len(button_pins)
self.last_button_times = [0] * len(button_pins)
self.debounce_ms = 50
# Pattern definitions
self.patterns = [
self.pattern_off,
self.pattern_all_blink,
self.pattern_running_light,
self.pattern_wave,
self.pattern_random,
]
self.pattern_names = [
"All OFF",
"All Blink",
"Running Light",
"Wave Effect",
"Random Pattern"
]
print(f"Advanced LED Controller initialized")
print(f"LEDs: {led_pins}")
print(f"Buttons: {button_pins}")
def get_button_press(self):
"""Deteksi button press dengan debouncing"""
current_time = utime.ticks_ms()
for i, button in enumerate(self.buttons):
current_state = button.value()
# Deteksi falling edge (button press)
if current_state == 0 and self.button_states[i] == 1:
if utime.ticks_diff(current_time, self.last_button_times[i]) > self.debounce_ms:
self.button_states[i] = current_state
self.last_button_times[i] = current_time
return i
# Update state tracking
if current_state != self.button_states[i]:
if utime.ticks_diff(current_time, self.last_button_times[i]) > self.debounce_ms:
self.button_states[i] = current_state
self.last_button_times[i] = current_time
return None
def set_led_pattern(self, pattern):
"""Set pola LED berdasarkan list boolean"""
for i, state in enumerate(pattern):
if i < len(self.leds):
if state:
self.leds[i].on()
else:
self.leds[i].off()
def all_leds_off(self):
"""Matikan semua LED"""
for led in self.leds:
led.off()
# Pattern functions
def pattern_off(self):
"""Pattern: Semua LED mati"""
self.all_leds_off()
def pattern_all_blink(self):
"""Pattern: Semua LED blink bersamaan"""
while self.pattern_running and self.current_pattern == 1:
self.set_led_pattern([True, True, True])
utime.sleep(0.5)
if not self.pattern_running or self.current_pattern != 1:
break
self.set_led_pattern([False, False, False])
utime.sleep(0.5)
def pattern_running_light(self):
"""Pattern: Running light effect"""
while self.pattern_running and self.current_pattern == 2:
for i in range(len(self.leds)):
if not self.pattern_running or self.current_pattern != 2:
break
pattern = [False] * len(self.leds)
pattern[i] = True
self.set_led_pattern(pattern)
utime.sleep(0.3)
def pattern_wave(self):
"""Pattern: Wave effect"""
wave_patterns = [
[True, False, False],
[True, True, False],
[False, True, True],
[False, False, True],
[False, True, False],
]
while self.pattern_running and self.current_pattern == 3:
for pattern in wave_patterns:
if not self.pattern_running or self.current_pattern != 3:
break
self.set_led_pattern(pattern)
utime.sleep(0.2)
def pattern_random(self):
"""Pattern: Random LED states"""
import urandom
while self.pattern_running and self.current_pattern == 4:
pattern = []
for i in range(len(self.leds)):
pattern.append(urandom.randint(0, 1) == 1)
self.set_led_pattern(pattern)
utime.sleep(0.3)
if not self.pattern_running or self.current_pattern != 4:
break
def start_pattern(self, pattern_index):
"""Mulai pattern tertentu"""
if pattern_index >= len(self.patterns):
return
# Stop pattern yang sedang berjalan
self.stop_pattern()
self.current_pattern = pattern_index
print(f"Starting pattern: {self.pattern_names[pattern_index]}")
if pattern_index == 0:
# Pattern OFF tidak perlu thread
self.patterns[0]()
else:
# Pattern lain berjalan di thread terpisah
self.pattern_running = True
try:
_thread.start_new_thread(self.patterns[pattern_index], ())
except:
# Fallback jika threading tidak tersedia
print("Threading not available, running pattern in main loop")
self.patterns[pattern_index]()
def stop_pattern(self):
"""Stop pattern yang sedang berjalan"""
self.pattern_running = False
utime.sleep(0.1) # Beri waktu thread untuk berhenti
self.all_leds_off()
def show_status(self):
"""Tampilkan status saat ini"""
print(f"\nCurrent Pattern: {self.pattern_names[self.current_pattern]}")
print(f"Pattern Running: {self.pattern_running}")
print("Button mapping:")
print("- Button 1 (GPIO4): Next pattern")
print("- Button 2 (GPIO5): Previous pattern")
print("- Button 3 (GPIO23): Stop/Start toggle")
def run_controller(self):
"""Main loop controller"""
print("=== Advanced LED Controller Started ===")
self.show_status()
try:
while True:
button_pressed = self.get_button_press()
if button_pressed == 0: # Button 1: Next pattern
next_pattern = (self.current_pattern + 1) % len(self.patterns)
self.start_pattern(next_pattern)
self.show_status()
elif button_pressed == 1: # Button 2: Previous pattern
prev_pattern = (self.current_pattern - 1) % len(self.patterns)
self.start_pattern(prev_pattern)
self.show_status()
elif button_pressed == 2: # Button 3: Stop/Start toggle
if self.pattern_running:
print("Stopping pattern...")
self.stop_pattern()
else:
print("Restarting pattern...")
self.start_pattern(self.current_pattern)
self.show_status()
utime.sleep_ms(10)
except KeyboardInterrupt:
print("\nController stopped by user")
finally:
self.stop_pattern()
print("All patterns stopped")
# Test advanced controller
if __name__ == "__main__":
# Inisialisasi controller
led_pins = [18, 19, 21]
button_pins = [4, 5, 23]
controller = AdvancedLEDController(led_pins, button_pins)
# Jalankan controller
controller.run_controller()
Bagian 5: PWM (Pulse Width Modulation) Dasar
5.1 Pengenalan PWM
PWM adalah teknik untuk mengontrol daya dengan mengubah lebar pulsa sinyal digital. ESP32 memiliki hardware PWM yang dapat digunakan untuk mengontrol kecerahan LED, kecepatan motor, atau menghasilkan sinyal analog.
Karakteristik PWM ESP32:
- Channels: 16 channel PWM independen
- Resolution: 1-16 bit (umumnya 8-bit untuk LED)
- Frequency: 1 Hz - 40 MHz
- Duty Cycle: 0-100% (0-1023 untuk 10-bit)
5.2 LED Brightness Control dengan PWM
Menggunakan PWM untuk mengontrol kecerahan LED secara smooth.
Praktikum 5.1: PWM LED Brightness Control
Langkah 1: Siapkan Hardware
- 1 LED dengan resistor 220Ω pada GPIO18
- 2 Button pada GPIO4 dan GPIO5
Langkah 2: Buat File pwm_led.py
# pwm_led.py - PWM LED brightness control
import machine
import utime
class PWMLEDController:
"""Controller untuk mengontrol brightness LED dengan PWM"""
def __init__(self, led_pin, button_up_pin, button_down_pin):
"""Inisialisasi PWM LED controller"""
# Setup PWM untuk LED
self.pwm_led = machine.PWM(machine.Pin(led_pin))
self.pwm_led.freq(1000) # 1kHz frequency
self.pwm_led.duty(0) # Start dengan brightness 0
# Setup buttons
self.btn_up = machine.Pin(button_up_pin, machine.Pin.IN, machine.Pin.PULL_UP)
self.btn_down = machine.Pin(button_down_pin, machine.Pin.IN, machine.Pin.PULL_UP)
# State variables
self.brightness = 0 # Current brightness (0-1023)
self.max_brightness = 1023
self.min_brightness = 0
self.step_size = 50
# Debouncing
self.last_up_state = 1
self.last_down_state = 1
self.last_up_time = 0
self.last_down_time = 0
self.debounce_ms = 100
print(f"PWM LED Controller initialized on GPIO{led_pin}")
print(f"Up button: GPIO{button_up_pin}, Down button: GPIO{button_down_pin}")
def set_brightness(self, brightness):
"""Set brightness LED (0-1023)"""
# Clamp brightness ke range yang valid
brightness = max(self.min_brightness, min(self.max_brightness, brightness))
self.brightness = brightness
self.pwm_led.duty(brightness)
# Hitung persentase untuk display
percentage = int((brightness / self.max_brightness) * 100)
print(f"Brightness: {brightness}/1023 ({percentage}%)")
def increase_brightness(self):
"""Naikkan brightness"""
new_brightness = self.brightness + self.step_size
self.set_brightness(new_brightness)
def decrease_brightness(self):
"""Turunkan brightness"""
new_brightness = self.brightness - self.step_size
self.set_brightness(new_brightness)
def check_button_up(self):
"""Cek button up dengan debouncing"""
current_state = self.btn_up.value()
current_time = utime.ticks_ms()
if current_state == 0 and self.last_up_state == 1:
if utime.ticks_diff(current_time, self.last_up_time) > self.debounce_ms:
self.last_up_state = current_state
self.last_up_time = current_time
return True
if current_state != self.last_up_state:
if utime.ticks_diff(current_time, self.last_up_time) > self.debounce_ms:
self.last_up_state = current_state
self.last_up_time = current_time
return False
def check_button_down(self):
"""Cek button down dengan debouncing"""
current_state = self.btn_down.value()
current_time = utime.ticks_ms()
if current_state == 0 and self.last_down_state == 1:
if utime.ticks_diff(current_time, self.last_down_time) > self.debounce_ms:
self.last_down_state = current_state
self.last_down_time = current_time
return True
if current_state != self.last_down_state:
if utime.ticks_diff(current_time, self.last_down_time) > self.debounce_ms:
self.last_down_state = current_state
self.last_down_time = current_time
return False
def auto_fade(self, duration_ms=3000):
"""Auto fade in dan fade out"""
print("Starting auto fade effect...")
steps = 50
delay_ms = duration_ms // (steps * 2) # *2 untuk fade in + fade out
brightness_step = self.max_brightness // steps
# Fade in
print("Fading in...")
for i in range(steps + 1):
brightness = i * brightness_step
self.set_brightness(brightness)
utime.sleep_ms(delay_ms)
# Fade out
print("Fading out...")
for i in range(steps, -1, -1):
brightness = i * brightness_step
self.set_brightness(brightness)
utime.sleep_ms(delay_ms)
print("Auto fade complete!")
def breathing_effect(self, cycles=3):
"""Efek breathing (fade in-out berulang)"""
print(f"Starting breathing effect - {cycles} cycles...")
for cycle in range(cycles):
print(f"Breathing cycle {cycle + 1}/{cycles}")
# Fade in
for brightness in range(0, self.max_brightness, 20):
self.set_brightness(brightness)
utime.sleep_ms(20)
# Fade out
for brightness in range(self.max_brightness, 0, -20):
self.set_brightness(brightness)
utime.sleep_ms(20)
self.set_brightness(0)
print("Breathing effect complete!")
def manual_control_mode(self):
"""Mode kontrol manual dengan buttons"""
print("=== Manual Control Mode ===")
print("Up button: Increase brightness")
print("Down button: Decrease brightness")
print("Press both buttons together to exit")
while True:
# Cek button presses
if self.check_button_up():
self.increase_brightness()
if self.check_button_down():
self.decrease_brightness()
# Exit condition: kedua button ditekan bersamaan
if self.btn_up.value() == 0 and self.btn_down.value() == 0:
print("Both buttons pressed. Exiting manual control...")
break
utime.sleep_ms(10)
def demo_mode(self):
"""Demo berbagai efek PWM"""
print("=== PWM LED Demo ===")
# Set ke brightness minimum
self.set_brightness(0)
utime.sleep(1)
# Demo 1: Step brightness
print("\nDemo 1: Step brightness increases")
for brightness in range(0, self.max_brightness + 1, 100):
self.set_brightness(brightness)
utime.sleep(0.5)
utime.sleep(1)
# Demo 2: Auto fade
print("\nDemo 2: Auto fade effect")
self.auto_fade(2000)
utime.sleep(1)
# Demo 3: Breathing effect
print("\nDemo 3: Breathing effect")
self.breathing_effect(2)
print("\nDemo complete!")
def cleanup(self):
"""Cleanup PWM resources"""
self.pwm_led.deinit()
print("PWM resources cleaned up")
# Test PWM LED controller
if __name__ == "__main__":
# Inisialisasi controller
controller = PWMLEDController(led_pin=18, button_up_pin=4, button_down_pin=5)
try:
print("=== PWM LED Controller Test ===")
# Demo mode
controller.demo_mode()
utime.sleep(2)
# Manual control mode
controller.manual_control_mode()
except KeyboardInterrupt:
print("\nTest stopped by user")
finally:
controller.cleanup()
print("Test complete!")
5.3 Buzzer Control dengan PWM
Menggunakan PWM untuk mengontrol buzzer dan menghasilkan nada yang berbeda.
Praktikum 5.2: PWM Buzzer Musical Notes
Langkah 1: Siapkan Hardware
- 1 Buzzer aktif pada GPIO22
- 2 Button pada GPIO4 dan GPIO5
Langkah 2: Buat File pwm_buzzer.py
# pwm_buzzer.py - PWM buzzer untuk musical notes
import machine
import utime
class PWMBuzzerController:
"""Controller untuk buzzer dengan PWM"""
def __init__(self, buzzer_pin, button1_pin, button2_pin):
"""Inisialisasi PWM buzzer controller"""
# Setup PWM untuk buzzer
self.buzzer = machine.PWM(machine.Pin(buzzer_pin))
self.buzzer.duty(0) # Start silent
# Setup buttons
self.btn1 = machine.Pin(button1_pin, machine.Pin.IN, machine.Pin.PULL_UP)
self.btn2 = machine.Pin(button2_pin, machine.Pin.IN, machine.Pin.PULL_UP)
# Musical notes frequencies (in Hz)
self.notes = {
'C4': 262, 'C#4': 277, 'D4': 294, 'D#4': 311,
'E4': 330, 'F4': 349, 'F#4': 370, 'G4': 392,
'G#4': 415, 'A4': 440, 'A#4': 466, 'B4': 494,
'C5': 523, 'C#5': 554, 'D5': 587, 'D#5': 622,
'E5': 659, 'F5': 698, 'F#5': 740, 'G5': 784,
'G#5': 831, 'A5': 880, 'A#5': 932, 'B5': 988
}
# Simple melodies
self.melodies = {
'scale': ['C4', 'D4', 'E4', 'F4', 'G4', 'A4', 'B4', 'C5'],
'twinkle': ['C4', 'C4', 'G4', 'G4', 'A4', 'A4', 'G4',
'F4', 'F4', 'E4', 'E4', 'D4', 'D4', 'C4'],
'happy_birthday': ['C4', 'C4', 'D4', 'C4', 'F4', 'E4']
}
# Button debouncing
self.btn1_last_state = 1
self.btn2_last_state = 1
self.btn1_last_time = 0
self.btn2_last_time = 0
self.debounce_ms = 200
print(f"PWM Buzzer Controller initialized on GPIO{buzzer_pin}")
def play_tone(self, frequency, duration_ms=500, duty=512):
"""Mainkan nada dengan frekuensi tertentu"""
if frequency > 0:
self.buzzer.freq(frequency)
self.buzzer.duty(duty)
print(f"Playing tone: {frequency} Hz for {duration_ms} ms")
else:
self.buzzer.duty(0) # Silent
print(f"Silent for {duration_ms} ms")
utime.sleep_ms(duration_ms)
self.buzzer.duty(0) # Stop sound
def play_note(self, note, duration_ms=500):
"""Mainkan note musical"""
if note in self.notes:
frequency = self.notes[note]
self.play_tone(frequency, duration_ms)
print(f"Played note: {note}")
else:
print(f"Unknown note: {note}")
def play_melody(self, melody_name, note_duration=400):
"""Mainkan melody"""
if melody_name in self.melodies:
melody = self.melodies[melody_name]
print(f"Playing melody: {melody_name}")
for note in melody:
self.play_note(note, note_duration)
utime.sleep_ms(50) # Gap between notes
print(f"Melody {melody_name} complete!")
else:
print(f"Unknown melody: {melody_name}")
def play_scale(self, start_note='C4', octaves=1):
"""Mainkan scale naik turun"""
scale_notes = ['C', 'D', 'E', 'F', 'G', 'A', 'B']
octave = int(start_note[-1])
print(f"Playing scale from {start_note}, {octaves} octave(s)")
# Scale naik
for oct in range(octaves):
for note in scale_notes:
note_name = f"{note}{octave + oct}"
if note_name in self.notes:
self.play_note(note_name, 300)
# Scale turun
for oct in range(octaves - 1, -1, -1):
for note in reversed(scale_notes):
note_name = f"{note}{octave + oct}"
if note_name in self.notes:
self.play_note(note_name, 300)
def check_button1(self):
"""Cek button 1 press"""
current_state = self.btn1.value()
current_time = utime.ticks_ms()
if current_state == 0 and self.btn1_last_state == 1:
if utime.ticks_diff(current_time, self.btn1_last_time) > self.debounce_ms:
self.btn1_last_state = current_state
self.btn1_last_time = current_time
return True
if current_state != self.btn1_last_state:
if utime.ticks_diff(current_time, self.btn1_last_time) > self.debounce_ms:
self.btn1_last_state = current_state
self.btn1_last_time = current_time
return False
def check_button2(self):
"""Cek button 2 press"""
current_state = self.btn2.value()
current_time = utime.ticks_ms()
if current_state == 0 and self.btn2_last_state == 1:
if utime.ticks_diff(current_time, self.btn2_last_time) > self.debounce_ms:
self.btn2_last_state = current_state
self.btn2_last_time = current_time
return True
if current_state != self.btn2_last_state:
if utime.ticks_diff(current_time, self.btn2_last_time) > self.debounce_ms:
self.btn2_last_state = current_state
self.btn2_last_time = current_time
return False
def interactive_mode(self):
"""Mode interaktif dengan buttons"""
print("=== Interactive Buzzer Mode ===")
print("Button 1: Play random melody")
print("Button 2: Play scale")
print("Press both buttons to exit")
melodies = list(self.melodies.keys())
melody_index = 0
while True:
if self.check_button1():
# Play melody
melody_name = melodies[melody_index]
self.play_melody(melody_name)
melody_index = (melody_index + 1) % len(melodies)
if self.check_button2():
# Play scale
self.play_scale('C4', 1)
# Exit condition
if self.btn1.value() == 0 and self.btn2.value() == 0:
print("Both buttons pressed. Exiting...")
break
utime.sleep_ms(10)
def demo_sounds(self):
"""Demo berbagai suara"""
print("=== Buzzer Demo ===")
# Demo 1: Individual tones
print("\nDemo 1: Individual tones")
test_frequencies = [262, 330, 392, 523, 659, 784]
for freq in test_frequencies:
self.play_tone(freq, 400)
utime.sleep_ms(100)
utime.sleep(1)
# Demo 2: Scale
print("\nDemo 2: Musical scale")
self.play_scale('C4', 1)
utime.sleep(1)
# Demo 3: Melody
print("\nDemo 3: Twinkle Twinkle Little Star")
self.play_melody('twinkle')
print("\nDemo complete!")
def cleanup(self):
"""Cleanup PWM resources"""
self.buzzer.duty(0)
self.buzzer.deinit()
print("Buzzer PWM cleaned up")
# Test PWM buzzer controller
if __name__ == "__main__":
# Inisialisasi controller
controller = PWMBuzzerController(buzzer_pin=22, button1_pin=4, button2_pin=5)
try:
print("=== PWM Buzzer Controller Test ===")
# Demo sounds
controller.demo_sounds()
utime.sleep(2)
# Interactive mode
controller.interactive_mode()
except KeyboardInterrupt:
print("\nTest stopped by user")
finally:
controller.cleanup()
print("Test complete!")
Bagian 6: Project Integration - Simple IoT Device Simulator
6.1 Project: Smart LED Controller
Menggabungkan semua konsep yang telah dipelajari untuk membuat smart LED controller yang simulate perangkat IoT sederhana.
Praktikum 6.1: Complete Smart Controller
Langkah 1: Siapkan Hardware Lengkap
- 3 LED (Red, Green, Blue) pada GPIO18, GPIO19, GPIO21
- 1 Buzzer pada GPIO22
- 3 Button pada GPIO4, GPIO5, GPIO23
- 1 LED status pada GPIO2 (built-in jika tersedia)
Langkah 2: Buat File smart_controller.py
# smart_controller.py - Complete smart LED controller
import machine
import utime
import urandom
class SmartLEDController:
"""Smart LED Controller dengan multiple modes dan features"""
def __init__(self):
"""Inisialisasi smart controller"""
# LED Setup (RGB)
self.led_red = machine.PWM(machine.Pin(18))
self.led_green = machine.PWM(machine.Pin(19))
self.led_blue = machine.PWM(machine.Pin(21))
self.status_led = machine.Pin(2, machine.Pin.OUT)
# Set PWM frequency
self.led_red.freq(1000)
self.led_green.freq(1000)
self.led_blue.freq(1000)
# Buzzer setup
self.buzzer = machine.PWM(machine.Pin(22))
self.buzzer.duty(0)
# Button setup
self.btn_mode = machine.Pin(4, machine.Pin.IN, machine.Pin.PULL_UP)
self.btn_action = machine.Pin(5, machine.Pin.IN, machine.Pin.PULL_UP)
self.btn_power = machine.Pin(23, machine.Pin.IN, machine.Pin.PULL_UP)
# State variables
self.current_mode = 0
self.power_on = True
self.brightness = 512 # 50% brightness
self.color_index = 0
# Mode definitions
self.modes = [
"Manual Color",
"Auto Rainbow",
"Breathing Effect",
"Party Mode",
"Alarm Mode"
]
# Colors (R, G, B) dalam duty cycle 0-1023
self.colors = [
(1023, 0, 0), # Red
(0, 1023, 0), # Green
(0, 0, 1023), # Blue
(1023, 1023, 0), # Yellow
(1023, 0, 1023), # Magenta
(0, 1023, 1023), # Cyan
(1023, 512, 0), # Orange
(1023, 1023, 1023) # White
]
self.color_names = [
"Red", "Green", "Blue", "Yellow",
"Magenta", "Cyan", "Orange", "White"
]
# Debouncing
self.button_states = [1, 1, 1]
self.last_button_times = [0, 0, 0]
self.debounce_ms = 200
# Sound frequencies
self.beep_freq = 1000
self.alarm_freq = 800
print("Smart LED Controller initialized!")
self.show_status()
def play_beep(self, duration_ms=100):
"""Mainkan beep pendek"""
self.buzzer.freq(self.beep_freq)
self.buzzer.duty(256)
utime.sleep_ms(duration_ms)
self.buzzer.duty(0)
def play_alarm(self, duration_ms=2000):
"""Mainkan alarm sound"""
alarm_duration = duration_ms // 200 # 200ms per cycle
for i in range(alarm_duration):
# High tone
self.buzzer.freq(self.alarm_freq)
self.buzzer.duty(256)
utime.sleep_ms(100)
# Low tone
self.buzzer.freq(self.alarm_freq // 2)
self.buzzer.duty(256)
utime.sleep_ms(100)
self.buzzer.duty(0)
def set_rgb_color(self, red, green, blue):
"""Set warna RGB LED"""
if not self.power_on:
red = green = blue = 0
# Apply brightness scaling
brightness_factor = self.brightness / 1023.0
self.led_red.duty(int(red * brightness_factor))
self.led_green.duty(int(green * brightness_factor))
self.led_blue.duty(int(blue * brightness_factor))
def set_color_by_index(self, index):
"""Set warna berdasarkan index"""
if 0 <= index < len(self.colors):
r, g, b = self.colors[index]
self.set_rgb_color(r, g, b)
return self.color_names[index]
return "Unknown"
def all_leds_off(self):
"""Matikan semua LED"""
self.set_rgb_color(0, 0, 0)
def check_buttons(self):
"""Check semua button dengan debouncing"""
current_time = utime.ticks_ms()
buttons = [self.btn_mode, self.btn_action, self.btn_power]
pressed_buttons = []
for i, button in enumerate(buttons):
current_state = button.value()
# Detect button press (falling edge)
if current_state == 0 and self.button_states[i] == 1:
if utime.ticks_diff(current_time, self.last_button_times[i]) > self.debounce_ms:
self.button_states[i] = current_state
self.last_button_times[i] = current_time
pressed_buttons.append(i)
# Update state
if current_state != self.button_states[i]:
if utime.ticks_diff(current_time, self.last_button_times[i]) > self.debounce_ms:
self.button_states[i] = current_state
self.last_button_times[i] = current_time
return pressed_buttons
def show_status(self):
"""Tampilkan status saat ini"""
print(f"\n=== Smart LED Controller Status ===")
print(f"Power: {'ON' if self.power_on else 'OFF'}")
print(f"Mode: {self.modes[self.current_mode]}")
print(f"Brightness: {int((self.brightness/1023)*100)}%")
if self.current_mode == 0:
print(f"Current Color: {self.color_names[self.color_index]}")
print("Buttons: [Mode] [Action] [Power]")
print("="*38)
def mode_manual_color(self):
"""Mode: Manual color selection"""
color_name = self.set_color_by_index(self.color_index)
print(f"Manual Mode - Color: {color_name}")
def mode_auto_rainbow(self):
"""Mode: Auto rainbow cycle"""
print("Auto Rainbow Mode - Cycling colors...")
for i in range(len(self.colors)):
if not self.power_on:
break
color_name = self.set_color_by_index(i)
print(f"Rainbow: {color_name}")
# Check for button press during animation
for _ in range(50): # 500ms total, check every 10ms
if self.check_buttons():
return # Exit if button pressed
utime.sleep_ms(10)
def mode_breathing_effect(self):
"""Mode: Breathing effect dengan warna saat ini"""
print("Breathing Effect Mode")
base_color = self.colors[self.color_index]
# Breathing cycle
for brightness in list(range(0, 1023, 50)) + list(range(1023, 0, -50)):
if not self.power_on:
break
# Scale color berdasarkan breathing brightness
factor = brightness / 1023.0
r = int(base_color[0] * factor)
g = int(base_color[1] * factor)
b = int(base_color[2] * factor)
self.set_rgb_color(r, g, b)
# Check for button press
if self.check_buttons():
return
utime.sleep_ms(30)
def mode_party_mode(self):
"""Mode: Party mode dengan random colors dan sounds"""
print("Party Mode - Random colors and sounds!")
# Random color
random_r = urandom.randint(0, 1023)
random_g = urandom.randint(0, 1023)
random_b = urandom.randint(0, 1023)
self.set_rgb_color(random_r, random_g, random_b)
# Random beep
if urandom.randint(0, 3) == 0: # 25% chance untuk beep
beep_freq = urandom.randint(500, 2000)
self.buzzer.freq(beep_freq)
self.buzzer.duty(128)
utime.sleep_ms(50)
self.buzzer.duty(0)
utime.sleep_ms(200)
def mode_alarm_mode(self):
"""Mode: Alarm dengan LED merah berkedip dan suara"""
print("ALARM MODE ACTIVATED!")
# Flash red LED
if utime.ticks_ms() % 500 < 250:
self.set_rgb_color(1023, 0, 0) # Red
else:
self.set_rgb_color(0, 0, 0) # Off
# Alarm sound setiap 2 detik
if utime.ticks_ms() % 2000 < 100:
self.buzzer.freq(self.alarm_freq)
self.buzzer.duty(256)
else:
self.buzzer.duty(0)
def handle_mode_button(self):
"""Handle mode button press"""
self.current_mode = (self.current_mode + 1) % len(self.modes)
self.play_beep()
print(f"Mode changed to: {self.modes[self.current_mode]}")
self.show_status()
def handle_action_button(self):
"""Handle action button press"""
self.play_beep()
if self.current_mode == 0: # Manual color mode
self.color_index = (self.color_index + 1) % len(self.colors)
color_name = self.color_names[self.color_index]
print(f"Color changed to: {color_name}")
elif self.current_mode == 1: # Auto rainbow
print("Rainbow speed increased!")
elif self.current_mode == 2: # Breathing
self.color_index = (self.color_index + 1) % len(self.colors)
color_name = self.color_names[self.color_index]
print(f"Breathing color changed to: {color_name}")
elif self.current_mode == 3: # Party mode
print("Party intensity increased!")
elif self.current_mode == 4: # Alarm mode
print("Alarm acknowledged!")
def handle_power_button(self):
"""Handle power button press"""
self.power_on = not self.power_on
self.status_led.value(1 if self.power_on else 0)
if self.power_on:
self.play_beep()
print("System POWERED ON")
else:
self.play_beep(200)
self.all_leds_off()
self.buzzer.duty(0)
print("System POWERED OFF")
self.show_status()
def run_current_mode(self):
"""Jalankan mode yang sedang aktif"""
if not self.power_on:
self.all_leds_off()
return
if self.current_mode == 0:
self.mode_manual_color()
elif self.current_mode == 1:
self.mode_auto_rainbow()
elif self.current_mode == 2:
self.mode_breathing_effect()
elif self.current_mode == 3:
self.mode_party_mode()
elif self.current_mode == 4:
self.mode_alarm_mode()
def run_controller(self):
"""Main control loop"""
print("=== Smart LED Controller Started ===")
self.status_led.on() # Power indicator
self.play_beep()
try:
while True:
# Check button presses
pressed_buttons = self.check_buttons()
for button_index in pressed_buttons:
if button_index == 0: # Mode button
self.handle_mode_button()
elif button_index == 1: # Action button
self.handle_action_button()
elif button_index == 2: # Power button
self.handle_power_button()
# Run current mode
self.run_current_mode()
utime.sleep_ms(10)
except KeyboardInterrupt:
print("\nController stopped by user")
finally:
self.cleanup()
def cleanup(self):
"""Cleanup semua resources"""
self.all_leds_off()
self.buzzer.duty(0)
self.status_led.off()
# Deinitialize PWM
self.led_red.deinit()
self.led_green.deinit()
self.led_blue.deinit()
self.buzzer.deinit()
print("Smart Controller cleaned up!")
# Test smart controller
if __name__ == "__main__":
controller = SmartLEDController()
controller.run_controller()
Langkah 3: Upload dan Test
- Upload file ke ESP32
- Pastikan semua hardware terhubung dengan benar
- Jalankan dengan:
exec(open('smart_controller.py').read())
6.2 Troubleshooting dan Best Practices
Panduan untuk mengatasi masalah umum dan best practices dalam pengembangan aplikasi GPIO.
Praktikum 6.2: Diagnostic Tool
Langkah 1: Buat File diagnostic.py
# diagnostic.py - Diagnostic tool untuk GPIO ESP32
import machine
import utime
import gc
class ESP32Diagnostic:
"""Tool diagnostic untuk ESP32 GPIO"""
def __init__(self):
"""Inisialisasi diagnostic tool"""
self.test_pins = [2, 4, 5, 18, 19, 21, 22, 23]
self.results = {}
print("ESP32 GPIO Diagnostic Tool initialized")
def test_pin_output(self, pin_num):
"""Test pin sebagai output"""
try:
pin = machine.Pin(pin_num, machine.Pin.OUT)
# Test digital output
pin.on()
utime.sleep_ms(100)
pin.off()
# Test PWM (jika mendukung)
try:
pwm = machine.PWM(pin)
pwm.freq(1000)
pwm.duty(512)
utime.sleep_ms(100)
pwm.duty(0)
pwm.deinit()
pwm_support = True
except:
pwm_support = False
return {
'status': 'OK',
'digital_out': True,
'pwm_support': pwm_support
}
except Exception as e:
return {
'status': 'ERROR',
'error': str(e),
'digital_out': False,
'pwm_support': False
}
def test_pin_input(self, pin_num):
"""Test pin sebagai input"""
try:
# Test dengan pull-up
pin_up = machine.Pin(pin_num, machine.Pin.IN, machine.Pin.PULL_UP)
val_up = pin_up.value()
# Test dengan pull-down
pin_down = machine.Pin(pin_num, machine.Pin.IN, machine.Pin.PULL_DOWN)
val_down = pin_down.value()
return {
'status': 'OK',
'pull_up_value': val_up,
'pull_down_value': val_down,
'pull_resistors': True
}
except Exception as e:
return {
'status': 'ERROR',
'error': str(e),
'pull_resistors': False
}
def test_system_info(self):
"""Test informasi sistem"""
try:
info = {
'chip_id': machine.unique_id().hex(),
'frequency': machine.freq(),
'free_memory': gc.mem_free(),
'allocated_memory': gc.mem_alloc(),
}
# Test built-in sensors
try:
import esp32
info['hall_sensor'] = esp32.hall_sensor()
info['temperature'] = esp32.raw_temperature()
except:
info['built_in_sensors'] = 'Not available'
return info
except Exception as e:
return {'error': str(e)}
def run_full_diagnostic(self):
"""Jalankan diagnostic lengkap"""
print("\n" + "="*50)
print(" ESP32 GPIO DIAGNOSTIC REPORT")
print("="*50)
# System info
print("\n--- System Information ---")
sys_info = self.test_system_info()
for key, value in sys_info.items():
print(f"{key}: {value}")
# GPIO tests
print(f"\n--- GPIO Pin Tests ---")
print("Testing pins: {}".format(self.test_pins))
for pin in self.test_pins:
print(f"\nTesting GPIO{pin}:")
# Test as output
output_result = self.test_pin_output(pin)
print(f" Output Test: {output_result['status']}")
if output_result['status'] == 'OK':
print(f" Digital Output: {'OK' if output_result['digital_out'] else 'FAIL'}")
print(f" PWM Support: {'OK' if output_result['pwm_support'] else 'NO'}")
else:
print(f" Error: {output_result.get('error', 'Unknown')}")
# Test as input
input_result = self.test_pin_input(pin)
print(f" Input Test: {input_result['status']}")
if input_result['status'] == 'OK':
print(f" Pull-up value: {input_result['pull_up_value']}")
print(f" Pull-down value: {input_result['pull_down_value']}")
else:
print(f" Error: {input_result.get('error', 'Unknown')}")
self.results[pin] = {
'output': output_result,
'input': input_result
}
# Summary
print(f"\n--- Summary ---")
working_pins = []
failed_pins = []
for pin, result in self.results.items():
if (result['output']['status'] == 'OK' and
result['input']['status'] == 'OK'):
working_pins.append(pin)
else:
failed_pins.append(pin)
print(f"Working pins: {working_pins}")
print(f"Failed pins: {failed_pins}")
print(f"Success rate: {len(working_pins)}/{len(self.test_pins)} ({len(working_pins)/len(self.test_pins)*100:.1f}%)")
print("\n" + "="*50)
print("Diagnostic complete!")
return self.results
def interactive_pin_test(self):
"""Test interaktif untuk pin tertentu"""
print("\n=== Interactive Pin Test ===")
while True:
try:
pin_input = input("Enter GPIO pin number to test (or 'q' to quit): ")
if pin_input.lower() == 'q':
break
pin_num = int(pin_input)
print(f"\nTesting GPIO{pin_num}...")
# Test output
print("Testing as output (LED should blink if connected):")
pin = machine.Pin(pin_num, machine.Pin.OUT)
for i in range(3):
pin.on()
print(f" ON ({i+1}/3)")
utime.sleep(0.5)
pin.off()
print(f" OFF ({i+1}/3)")
utime.sleep(0.5)
# Test input
print("Testing as input (press button if connected):")
pin = machine.Pin(pin_num, machine.Pin.IN, machine.Pin.PULL_UP)
print("Reading pin state for 5 seconds...")
start_time = utime.ticks_ms()
last_state = None
while utime.ticks_diff(utime.ticks_ms(), start_time) < 5000:
current_state = pin.value()
if current_state != last_state:
print(f" Pin state: {current_state}")
last_state = current_state
utime.sleep_ms(100)
print("Pin test complete!\n")
except ValueError:
print("Invalid pin number!")
except Exception as e:
print(f"Error testing pin: {e}")
# Main diagnostic program
if __name__ == "__main__":
diagnostic = ESP32Diagnostic()
print("ESP32 GPIO Diagnostic Tool")
print("1. Run full diagnostic")
print("2. Interactive pin test")
try:
choice = input("Select option (1 or 2): ")
if choice == "1":
diagnostic.run_full_diagnostic()
elif choice == "2":
diagnostic.interactive_pin_test()
else:
print("Invalid choice")
except:
# Fallback jika input() tidak tersedia di REPL
print("Running full diagnostic...")
diagnostic.run_full_diagnostic()