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.

Bir anahtar giriş sinyalini gösteren idealize edilmiş bir osiloskop izi. Sinyal yüksek başlar (açık anahtar), düşük seviyeye iner, birkaç milisaniye içinde defalarca ileri geri sıçrar, ardından düşük seviyede yerleşir (kapalı anahtar).

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.

Aralarında bir dielektrik (yalıtkan) bulunan iki paralel yatay plaka olarak çizilmiş bir kondansatör. Her plakayı harici bir uca bağlayan bir kablo vardır -- üstte A, altta B. Uçlar arasına bir V gerilimi uygulandığında iki plakada eşit ve zıt yükler +Q ve -Q birikir.

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ün geriliminin 0 V'tan besleme rayına doğru üstel bir eğri boyunca yükselişini gösteren bir grafik. τ = RC süresi, eğrinin besleme geriliminin %63'üne ulaştığı x ekseninde işaretlenmiştir.

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ün geriliminin Vmax'tan 0 V'a doğru üstel bir eğri boyunca düşüşünü gösteren bir grafik. τ = RC süresi, eğrinin başlangıç geriliminin %37'sine indiği x ekseninde işaretlenmiştir.

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 önlemeli bir anahtar girişi. Vcc, 10 kΩ'luk bir çekme (pull-up) direnci üzerinden aşağıdaki bir kavşağa bağlanır. O kavşak, bir dalda anahtar üzerinden toprağa, diğer dalda ise 10 kΩ'luk bir seri direnç üzerinden Pin'e bağlanır. Pin ile toprak arasındaki 100 nF'lık bir kondansatör, alçak geçiren filtreyi tamamlar.

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 (çekme/pull-up), R2 = 10 (seri), C = 100 nF.

Anahtar açıkken, akım Vcc → R1R2 → 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.