3.11. Sıçrama Önleme (Debouncing)¶
Bir anahtar, mükemmel açık-veya-kapalı bir kontak olarak çizilir, ancak gerçek bir anahtarın kontakları iki durum arasında temiz bir şekilde geçiş yapmaz. Cızırdarlar – birkaç milisaniye içinde yerleşmeden önce elektriksel teması defalarca kurar ve keser. Pini okuyan bir GPIO girişi bunu bir kenar patlaması olarak görür; dikkatsiz bir yoklama döngüsü gerçek bir basış için birkaç “basma” sayar ve bir kesme işleyicisi her gerçek basışta birkaç kez çalışır.
Sıçrayan bir anahtar, yerleşmeden önce hızlı geçişlerden oluşan bir patlama üretir.¶
Sıçrama önleme, her fiziksel basışın tek bir olay olarak kaydedilmesi için cızırtının süzülmesi uygulamasıdır. Bunu iki yaklaşım çözer – yazılım (aygıt yazılımında (firmware) bir zamanlama kuralı) veya donanım (kablo üzerinde küçük bir filtre). Bunlar birbirini dışlamaz.
3.11.1. Yazılımla sıçrama önleme¶
Buradaki fikir, girişin en son ne zaman değiştiğini hatırlamak ve o zaman damgasının kısa bir penceresi içinde gelen diğer değişiklikleri reddetmektir. Kontak sıçraması tipik olarak 10 ms’nin altında sürer; gerçek bir basış 50 – 100 ms alır; 30 – 50 ms’lik bir pencere, gerçek basışları engellemeden tüm sıçramaları yakalar.
Bir yoklama döngüsünde, pini okuyun, son kararlı değerle karşılaştırın ve yalnızca sıçrama önleme penceresi geçtikten sonra bir değişikliği kabul edin:
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)
Kesme tabanlı okumalar için, aynı zamanlama kuralını işleyicinin içinde uygulayın, ardından gerçek basışı micropython.schedule() aracılığıyla ana bağlama devredin (bkz. GPIO girişi):
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, sıçramaları zaman damgasına göre süzer ve geri çağırmayı (callback) sıraya koyar; handle_press ise tahsisat ve yavaş G/Ç’nin güvenli olduğu ana bağlamda tekrar çalışır.
3.11.2. Donanımla sıçrama önleme¶
Donanımla sıçrama önleme, cızırtıyı pine ulaşmadan önce elektriksel olarak süzer. Standart araç bir kondansatördür.
Kondansatör, elektrik yükü depolayan iki uçlu bir bileşendir. Fiziksel olarak, kısa bir mesafe ile birbirinden ayrı tutulan, bir yalıtkanla (dielektrik) ayrılmış iki iletken plakadan oluşur.
Paralel plakalı bir kondansatör: yalıtkan bir katmanla ayrılmış iki iletken.¶
Uçları arasına gerilim uygulamak, iki plakaya eşit ve zıt yükler sürer; ilişki şudur:
Q = C × V
burada Q depolanan yüktür (coulomb), V kondansatör üzerindeki gerilimdir ve C onun kapasitansıdır (farad). Kapasitans, cihazın yapısı tarafından sabitlenir; daha fazla kapasitans, aynı gerilimde daha fazla yük depolanması anlamına gelir.
Sonuç: bir kondansatör gerilimini anında değiştiremez. İçeri veya dışarı akan yük, yoldaki herhangi bir dirençten geçmek zorundadır ve bu direnç, gerilimin ne kadar hızlı değişebileceğini belirler.
3.11.2.1. RC zaman sabiti¶
Bir kondansatörü bir direnç üzerinden şarj etmek, besleme gerilimine doğru bir adım değil, düzgün bir üstel yükseliş üretir. Bu yükselişin karakteristik süresi RC zaman sabitidir:
τ = R × C
Bir τ sonrasında, kondansatör besleme geriliminin yaklaşık %63’üne ulaşmıştır. 5 τ sonrasında, %99’un üzerindedir – pratik amaçlar için “tamamen şarj olmuş” sayılır.
Bir kondansatör, üstel bir eğri boyunca şarj olur. τ = RC, son gerilimin %63’üne ulaşma süresidir.¶
Bir direnç üzerinden boşalma, ayna görüntüsünü izler: gerilim, başlangıç değerinden sıfıra doğru üstel olarak düşer; bir τ sonrasında başlangıç geriliminin %37’sine ve 5 τ sonrasında %1’in altına iner.
Bir kondansatör, üstel bir azalma boyunca boşalır. τ = RC, başlangıç geriliminin %37’sine düşme süresidir.¶
3.11.2.2. Sıçrama önleme devresi¶
Bir giriş pini ile toprak arasına yerleştirilen ve seri bir direnç üzerinden beslenen bir kondansatör, bir alçak geçiren filtre oluşturur. Hızlı ani yükselmelerin, kondansatörü o direnç üzerinden şarj veya deşarj edecek zamanı yoktur; pin, ani yükselmeden önce hangi gerilimdeyse ona yakın kalır. Yavaş değişiklikler – kasıtlı bir basış – kondansatörü şarj veya deşarj eder ve okuma bunu izler.
R1, anahtarın yüksek tarafını Vcc’ye çekerek sıçrayan ham bir anahtar sinyali üretir. R2 ve C ardından bu sinyali pine doğru alçak geçiren filtreden geçirir:
Donanımla sıçrama önleme: R2 ve C, ham anahtar sinyalini pine ulaşmadan önce alçak geçiren filtreden geçirir.¶
Tipik değerler: R1 = 10 kΩ (çekme/pull-up), R2 = 10 kΩ (seri), C = 100 nF.
Anahtar açıkken, akım Vcc → R1 → R2 → kondansatör (seri olarak) akar ve kondansatörü τ_charge = (R1 + R2) × C = 2 ms ile Vcc’ye şarj eder.
Anahtar kapandığında, anahtar düğümü toprağa kenetlenir ve kondansatör yalnızca R2 üzerinden o toprağa τ_discharge = R2 × C = 1 ms ile boşalır.
Her iki kenar da RC ile süzülür. Kondansatör, anahtardan R2 aşağısında kendi düğümünde durduğu için, Vcc (açık) ile 0 V (kapalı) arasında temiz bir şekilde salınır – her iki durumda da kararlı durumda R1 üzerinden hiçbir akımın akması gerekmez.
3.11.3. Aralarında seçim yapmak¶
Yazılım varsayılandır. Bileşen olarak hiçbir maliyeti yoktur, eşiğin ayarlanması kolaydır ve CPU’nun okuduğu herhangi bir pinde çalışır.
Donanım, sıçrama CPU’nun yoklama koduna değil de başka bir şeye ulaştığında – iki kez tetiklenmemesi gereken bir kesme, bir donanım sayacı, kendi filtresi olmayan bir çevre birimi – parçalara değer.
Yazılım ve donanımla sıçrama önleme de barış içinde bir arada bulunabilir: küçük bir RC filtresi en kötü ani yükselmeleri bastırır ve bir yazılım sıçrama önleme penceresi geri kalanı kapsar.