3.11. Debouncing¶
Sebuah sakelar digambarkan sebagai kontak terbuka-atau-tertutup yang sempurna, namun kontak sakelar nyata tidak berpindah dengan bersih antara kedua kondisi tersebut. Kontak itu bergetar -- membuat dan memutus kontak listrik berkali-kali dalam beberapa milidetik sebelum stabil. Input GPIO yang membaca pin melihat hal itu sebagai serangkaian tepi; loop polling yang ceroboh menghitung beberapa "penekanan" untuk satu penekanan nyata, dan handler interupsi berjalan beberapa kali per penekanan aktual.
Sakelar yang memantul menghasilkan serangkaian transisi cepat sebelum stabil.¶
Debouncing adalah praktik memfilter getaran tersebut sehingga setiap penekanan fisik terdaftar sebagai satu peristiwa. Dua pendekatan menyelesaikan ini -- perangkat lunak (aturan waktu dalam firmware) atau perangkat keras (filter kecil pada kabel). Keduanya tidak saling eksklusif.
3.11.1. Debouncing perangkat lunak¶
Idenya adalah mengingat kapan input terakhir berubah dan menolak perubahan lebih lanjut dalam jendela waktu singkat dari timestamp tersebut. Getaran kontak biasanya berlangsung kurang dari 10 ms; penekanan nyata membutuhkan 50 -- 100 ms; jendela 30 -- 50 ms menangkap semua getaran tanpa menghalangi penekanan nyata.
Dalam loop polling, baca pin, bandingkan dengan nilai stabil terakhir, dan hanya terima perubahan setelah jendela debounce telah berlalu:
import time
from machine import Pin
button = Pin("P0", Pin.IN, Pin.PULL_UP)
last_state = 1
last_change = 0
DEBOUNCE_MS = 50
while True:
now = time.ticks_ms()
state = button.value()
if state != last_state and time.ticks_diff(now, last_change) > DEBOUNCE_MS:
last_change = now
last_state = state
if state == 0:
do_action()
time.sleep_ms(10)
Untuk pembacaan berbasis interupsi, terapkan aturan waktu yang sama di dalam handler, lalu serahkan penekanan nyata ke konteks utama melalui micropython.schedule() (lihat Input GPIO):
import time
import micropython
from machine import Pin
button = Pin("P0", Pin.IN, Pin.PULL_UP)
last_irq = 0
DEBOUNCE_MS = 50
def handle_press(pin):
do_action()
def on_press(pin):
global last_irq
now = time.ticks_ms()
if time.ticks_diff(now, last_irq) < DEBOUNCE_MS:
return
last_irq = now
micropython.schedule(handle_press, pin)
button.irq(handler=on_press, trigger=Pin.IRQ_FALLING)
ISR memfilter getaran berdasarkan timestamp dan mengantrekan callback; handle_press berjalan kembali di konteks utama, di mana alokasi dan I/O lambat aman dilakukan.
3.11.2. Debouncing perangkat keras¶
Debouncing perangkat keras memfilter getaran secara elektris, sebelum mencapai pin. Alat standar adalah kapasitor.
Kapasitor adalah komponen dua terminal yang menyimpan muatan listrik. Secara fisik, kapasitor terdiri dari dua pelat konduktif yang ditempatkan berdekatan, dipisahkan oleh isolator (dielektrik).
Kapasitor pelat paralel: dua konduktor yang dipisahkan oleh lapisan isolasi.¶
Menerapkan tegangan di terminal-terminalnya mendorong muatan yang sama dan berlawanan ke dua pelat; hubungannya adalah
Q = C × V
di mana Q adalah muatan yang tersimpan (coulomb), V adalah tegangan di kapasitor, dan C adalah kapasitansi-nya (farad). Kapasitansi ditentukan oleh konstruksi perangkat; kapasitansi lebih besar berarti lebih banyak muatan tersimpan pada tegangan yang sama.
Konsekuensinya: kapasitor tidak dapat mengubah tegangannya secara instan. Muatan yang mengalir masuk atau keluar harus melewati resistansi yang ada di jalurnya, dan resistansi itu menentukan seberapa cepat tegangan dapat berubah.
3.11.2.1. Konstanta waktu RC¶
Mengisi kapasitor melalui resistor menghasilkan kenaikan eksponensial yang mulus menuju tegangan sumber, bukan langkah tiba-tiba. Waktu karakteristik kenaikan tersebut adalah konstanta waktu RC:
τ = R × C
Setelah satu τ, kapasitor telah mencapai sekitar 63 % dari tegangan sumber. Setelah 5 τ, sudah lebih dari 99 % -- "terisi penuh" untuk keperluan praktis.
Kapasitor terisi sepanjang kurva eksponensial. τ = RC adalah waktu untuk mencapai 63 % dari tegangan akhir.¶
Pengosongan melalui resistor mengikuti gambar cermin: tegangan turun secara eksponensial dari nilai awalnya menuju nol, turun ke 37 % dari tegangan awal setelah satu τ, dan ke bawah 1 % setelah 5 τ.
Kapasitor mengosongkan diri sepanjang peluruhan eksponensial. τ = RC adalah waktu untuk turun ke 37 % dari tegangan awal.¶
3.11.2.2. Sirkuit debounce¶
Kapasitor antara pin input dan ground, yang diumpankan melalui resistor seri, membentuk filter lolos-rendah. Lonjakan cepat tidak punya waktu untuk mengisi atau mengosongkan kapasitor melalui resistor tersebut; pin tetap dekat dengan tegangan sebelum lonjakan. Perubahan lambat -- penekanan yang disengaja -- mengisi atau mengosongkan kapasitor dan pembacaan mengikutinya.
R1 menarik sisi tinggi sakelar ke Vcc, menghasilkan sinyal sakelar mentah yang memantul. R2 dan C kemudian memfilter sinyal tersebut dengan filter lolos-rendah ke pin:
Debouncing perangkat keras: R2 dan C memfilter sinyal sakelar mentah dengan filter lolos-rendah sebelum mencapai pin.¶
Nilai tipikal: R1 = 10 kΩ (pull-up), R2 = 10 kΩ (seri), C = 100 nF.
Ketika sakelar terbuka, arus mengalir Vcc → R1 → R2 → kapasitor (secara seri), mengisi kapasitor ke Vcc dengan τ_charge = (R1 + R2) × C = 2 ms.
Ketika sakelar menutup, node sakelar diklem ke ground dan kapasitor mengosongkan diri melalui R2 saja ke ground tersebut dengan τ_discharge = R2 × C = 1 ms.
Kedua tepi difilter RC. Karena kapasitor berada di nodenya sendiri, di hilir R2 dari sakelar, kapasitor berayun bersih antara Vcc (terbuka) dan 0 V (tertutup) -- tidak ada arus yang harus mengalir melalui R1 pada kondisi tunak dalam kedua kasus.
3.11.3. Memilih di antara keduanya¶
Perangkat lunak adalah pilihan default. Tidak memerlukan komponen tambahan, ambang batas mudah disesuaikan, dan bekerja pada pin mana pun yang dibaca CPU.
Perangkat keras layak digunakan saat getaran mencapai sesuatu selain kode polling CPU -- interupsi yang tidak boleh terpicu ganda, counter perangkat keras, periferal tanpa filter sendiri.
Debouncing perangkat lunak dan perangkat keras juga dapat hidup berdampingan dengan damai: filter RC kecil menekan lonjakan terburuk, dan jendela debounce perangkat lunak menangani sisanya.