3.11. إزالة الارتداد

يُرسم المفتاح على أنه تماس مثالي مفتوح أو مغلق، لكن تماسات المفتاح الحقيقي لا تنتقل بشكل نظيف بين الحالتين. فهي ترتعش -- تصل وتقطع التماس الكهربائي عدة مرات خلال أجزاء قليلة من الألف من الثانية قبل أن تستقر. ويرى دخل GPIO الذي يقرأ الدبوس ذلك على أنه دفقة من الحواف؛ فحلقة استطلاع غير متأنية تحسب عدة "ضغطات" لضغطة حقيقية واحدة، ومعالج المقاطعة يعمل عدة مرات لكل ضغطة فعلية.

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).

ينتج المفتاح المرتد دفقة من الانتقالات السريعة قبل أن يستقر.

إزالة الارتداد هي ممارسة ترشيح الارتعاش بحيث تُسجَّل كل ضغطة فعلية على أنها حدث واحد. ويحل هذه المشكلة أسلوبان -- برمجي (قاعدة توقيت في البرنامج الثابت) أو عتادي (مرشّح صغير على السلك). وهما ليسا متعارضين.

3.11.1. إزالة الارتداد البرمجية

الفكرة هي تذكر آخر مرة تغير فيها الدخل ورفض أي تغييرات أخرى ضمن نافذة زمنية قصيرة من تلك العلامة الزمنية. عادة ما يدوم ارتداد التماس أقل من 10 ms؛ وتستغرق الضغطة الحقيقية 50 -- 100 ms؛ بينما تلتقط نافذة 30 -- 50 ms كل حالات الارتداد دون أن تحجب الضغطات الحقيقية.

في حلقة استطلاع، اقرأ الدبوس وقارنه بآخر قيمة مستقرة، ولا تقبل التغيير إلا بعد انقضاء نافذة إزالة الارتداد:

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)

بالنسبة إلى القراءات المعتمدة على المقاطعات، طبّق قاعدة التوقيت نفسها داخل المعالج، ثم سلّم الضغطة الحقيقية إلى السياق الرئيسي عبر micropython.schedule() (انظر دخل 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 حالات الارتداد عن طريق العلامة الزمنية وتضع دالة رد النداء في الطابور؛ وتعمل handle_press مجددًا في السياق الرئيسي، حيث يكون التخصيص والإدخال/الإخراج البطيء آمنين.

3.11.2. إزالة الارتداد العتادية

تُرشّح إزالة الارتداد العتادية الارتعاش كهربائيًا، قبل أن يصل أبدًا إلى الدبوس. والأداة القياسية هي المكثّف.

المكثّف مكوّن ذو طرفين يخزّن الشحنة الكهربائية. وهو فيزيائيًا عبارة عن لوحين موصلين موضوعين على مسافة قصيرة، يفصل بينهما عازل (العازل الكهربائي).

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.

مكثّف متوازي اللوحين: موصلان يفصل بينهما طبقة عازلة.

يؤدي تطبيق جهد عبر طرفيه إلى دفع شحنتين متساويتين ومتعاكستين على اللوحين؛ والعلاقة هي

Q = C × V

حيث Q هي الشحنة المخزّنة (بالكولوم)، و V هي الجهد عبر المكثّف، و C هي سعته (بالفاراد). والسعة محددة ببنية الجهاز؛ والسعة الأكبر تعني تخزين شحنة أكبر عند الجهد نفسه.

والنتيجة: لا يمكن للمكثّف أن يغيّر جهده فورًا. إذ يجب أن تمر الشحنة المتدفقة داخلًا أو خارجًا عبر أي مقاومة تكون في المسار، وتلك المقاومة تحدد مدى سرعة تغير الجهد.

3.11.2.1. ثابت الزمن RC

ينتج عن شحن مكثّف عبر مقاومة ارتفاع أسّي سلس نحو جهد التغذية، وليس قفزة. والزمن المميز لذلك الارتفاع هو ثابت الزمن RC:

τ = R × C

بعد τ واحد، يكون المكثّف قد بلغ نحو 63 % من جهد التغذية. وبعد 5 من τ، يتجاوز 99 % -- أي "مشحون بالكامل" لأغراض عملية.

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.

يُشحن المكثّف على طول منحنى أسّي. و τ = RC هو الزمن اللازم لبلوغ 63 % من الجهد النهائي.

يتبع التفريغ عبر مقاومة الصورة المعكوسة: يهبط الجهد أسّيًا من قيمته الابتدائية نحو الصفر، فينخفض إلى 37 % من جهد البداية بعد τ واحد، وإلى أقل من 1 % بعد 5 من τ.

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.

يُفرَّغ المكثّف على طول اضمحلال أسّي. و τ = RC هو الزمن اللازم للهبوط إلى 37 % من جهد البداية.

3.11.2.2. دائرة إزالة الارتداد

يشكّل مكثّف بين دبوس دخل والأرضي، يُغذّى عبر مقاومة على التوالي، مرشّحًا منخفض التمرير. فالنبضات السريعة لا تجد وقتًا لشحن المكثّف أو تفريغه عبر تلك المقاومة؛ ويبقى الدبوس قريبًا من أي جهد كان عليه قبل النبضة. أما التغييرات البطيئة -- مثل ضغطة متعمّدة -- فتشحن المكثّف أو تفرّغه وتتبعها القراءة.

تسحب R1 الجانب المرتفع من المفتاح إلى Vcc، منتجةً إشارة مفتاح خام مرتدة. ثم ترشّح R2 و C تلك الإشارة بترشيح منخفض التمرير إلى داخل الدبوس:

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.

إزالة الارتداد العتادية: تقوم R2 و C بترشيح إشارة المفتاح الخام بترشيح منخفض التمرير قبل أن تصل إلى الدبوس.

القيم النموذجية: R1 = 10 (سحب لأعلى)، R2 = 10 (على التوالي)، C = 100 nF.

عندما يكون المفتاح مفتوحًا، يتدفق التيار Vcc ← R1R2 ← المكثّف (على التوالي)، فيشحن المكثّف إلى Vcc بـ τ_charge = (R1 + R2) × C = 2 ms.

عندما يُغلق المفتاح، تُثبَّت عقدة المفتاح عند الأرضي، ويُفرَّغ المكثّف عبر R2 وحدها إلى ذلك الأرضي بـ τ_discharge = R2 × C = 1 ms.

تُرشَّح كلتا الحافتين بترشيح RC. ولأن المكثّف يقع على عقدته الخاصة، أسفل تيار R2 من المفتاح، فإنه يتأرجح بنظافة بين Vcc (مفتوح) و 0 V (مغلق) -- ولا يضطر أي تيار إلى التدفق عبر R1 في الحالة المستقرة في أي من الحالتين.

3.11.3. الاختيار بينهما

  • البرمجية هي الخيار الافتراضي. فهي لا تكلّف شيئًا من المكونات، والعتبة سهلة الضبط، وتعمل على أي دبوس يقرأه المعالج.

  • العتادية تستحق ثمن القطع عندما يصل الارتداد إلى شيء آخر غير شِفرة الاستطلاع في المعالج -- مقاطعة يجب ألا تُطلَق مرتين، أو عدّاد عتادي، أو طرفية لا تملك مرشّحًا خاصًا بها.

كما تتعايش إزالة الارتداد البرمجية والعتادية بسلام: فمرشّح RC صغير يكبت أسوأ النبضات، ونافذة إزالة ارتداد برمجية تغطي ما تبقى.