3.11. การดีเบาวน์ซิง

สวิตช์ถูกวาดเป็นหน้าสัมผัสที่เปิดหรือปิดอย่างสมบูรณ์แบบ แต่หน้าสัมผัสของสวิตช์จริงไม่ได้สลับระหว่างสองสถานะอย่างคมชัด หน้าสัมผัสจะ สั่น -- เกิดและตัดการสัมผัสทางไฟฟ้าหลายครั้งในเวลาไม่กี่มิลลิวินาทีก่อนที่จะนิ่ง การอ่านค่า GPIO input บนพินนั้นจะเห็นเป็นชุดของขอบสัญญาณ; ลูปการสำรวจที่ไม่ระมัดระวังจะนับหลาย "การกด" สำหรับการกดจริงหนึ่งครั้ง และตัวจัดการอินเทอร์รัปต์จะทำงานหลายครั้งต่อการกดจริงหนึ่งครั้ง

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. การดีเบาวน์ซิงด้วยซอฟต์แวร์

แนวคิดคือจำไว้ว่า input เปลี่ยนแปลงครั้งล่าสุดเมื่อใด และปฏิเสธการเปลี่ยนแปลงเพิ่มเติมภายในช่วงเวลาสั้นๆ นับจากเวลาประทับนั้น การกระเด้งของหน้าสัมผัสมักกินเวลาน้อยกว่า 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)

สำหรับการอ่านที่ขับเคลื่อนด้วยอินเทอร์รัปต์ ให้ใช้กฎการจับเวลาเดียวกันภายในตัวจัดการ จากนั้นส่งการกดจริงไปยัง main context ผ่าน micropython.schedule() (ดู GPIO input):

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 ทำงานกลับใน main context ซึ่งการจัดสรรหน่วยความจำและ I/O ที่ช้าเป็นเรื่องปลอดภัย

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. วงจรดีเบาวน์ซิง

ตัวเก็บประจุระหว่างพิน input และกราวด์ ที่ป้อนผ่านตัวต้านทานแบบอนุกรม ก่อตัวเป็น ตัวกรองความถี่ต่ำ สัญญาณรบกวนสั้นๆ ไม่มีเวลาพอที่จะชาร์จหรือคายประจุตัวเก็บประจุผ่านตัวต้านทานนั้น; พินจะอยู่ใกล้กับแรงดันไฟฟ้าเดิมก่อนที่จะมีสัญญาณรบกวน การเปลี่ยนแปลงที่ช้า -- การกดตั้งใจ -- จะชาร์จหรือคายประจุตัวเก็บประจุและการอ่านค่าจะตาม

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 → cap (แบบอนุกรม) ชาร์จ cap ไปยัง Vcc ด้วย τ_charge = (R1 + R2) × C = 2 ms

เมื่อสวิตช์ปิด โหนดสวิตช์จะถูกล็อคไปยังกราวด์และ cap จะระบายออกผ่าน R2 เพียงอย่างเดียวไปยังกราวด์นั้นด้วย τ_discharge = R2 × C = 1 ms

ขอบสัญญาณทั้งสองถูกกรองด้วย RC เนื่องจาก cap อยู่บนโหนดของตัวเอง ปลายน้ำจาก R2 ของสวิตช์ มันจะสวิงอย่างชัดเจนระหว่าง Vcc (เปิด) และ 0 V (ปิด) -- ไม่มีกระแสต้องไหลผ่าน R1 ที่สถานะคงที่ในทั้งสองกรณี

3.11.3. การเลือกระหว่างทั้งสอง

  • ซอฟต์แวร์ คือค่าเริ่มต้น ไม่มีต้นทุนในชิ้นส่วน ค่าขีดแบ่งปรับแต่งได้ง่าย และทำงานได้บนพินใดก็ตามที่ CPU อ่าน

  • ฮาร์ดแวร์ คุ้มค่าชิ้นส่วนเมื่อการกระเด้งไปถึงสิ่งอื่นนอกจากโค้ดการสำรวจของ CPU -- อินเทอร์รัปต์ที่ต้องไม่ยิงสองครั้ง ตัวนับฮาร์ดแวร์ อุปกรณ์ต่อพ่วงที่ไม่มีตัวกรองของตัวเอง

การดีเบาวน์ซิงด้วยซอฟต์แวร์และฮาร์ดแวร์ยังอยู่ร่วมกันได้อย่างสงบสุข: ตัวกรอง RC ขนาดเล็กระงับสัญญาณรบกวนที่เลวร้ายที่สุด และหน้าต่างดีเบาวน์ซิงซอฟต์แวร์จะครอบคลุมสิ่งที่เหลืออยู่