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.

An idealised scope trace showing a switch input signal. The signal starts high (open switch), drops low, bounces back and forth several times within a few milliseconds, then settles low (closed switch).

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.

A capacitor drawn as two parallel horizontal plates with a dielectric (insulator) between them. A lead connects each plate to an external terminal -- A on top, B on bottom. Equal and opposite charges +Q and -Q accumulate on the two plates when a voltage V is applied across the terminals.

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.

A graph showing a capacitor's voltage rising along an exponential curve from 0 V toward the supply rail. The time τ = RC is marked on the x-axis where the curve reaches 63 % of the supply voltage.

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.

A graph showing a capacitor's voltage falling along an exponential curve from Vmax toward 0 V. The time τ = RC is marked on the x-axis where the curve drops to 37 % of the starting voltage.

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:

A switch input with hardware debouncing. Vcc connects through a 10 kΩ pull-up resistor down to a junction. That junction connects to ground through the switch on one branch, and through a 10 kΩ series resistor to the Pin on the other branch. A 100 nF capacitor between Pin and ground completes the low-pass filter.

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.