這個議題本來是想與昨天的按鍵彈跳問題一起探討的,但由於一直在 BPI-leaf-S3 板子 BOOT 按鈕上捕捉不到彈跳,做了很多實驗,最後只好自己搞了一個按鈕開關電路:
產生了彈跳,才能實驗用軟硬體的方式來抑制彈跳效應!
昨天我們用軟硬體來降低彈跳效應,主要的癥結點在於延時,由於彈跳的發生大都發生在按鈕按下或釋放的當下,因此,我們在那段時間忽略GPIO輸入值的變化,就可以避免獲取那些不正確的內容。
但這畢竟是延時,讓 CPU 不做事去睡覺!就跟前面 PWM 或者 Timer 一樣,我們是否可以利用 GPIO 中斷處理的一些特性,來降低處理彈跳延時的程式複雜度。
讓我們來看下面的例子:
from machine import Pin
SW = Pin(4, Pin.IN)
key = 0 # released
def SW_callback(pin):
global key
key = key + 1
SW.irq(handler=SW_callback, trigger=Pin.IRQ_FALLING)
# 在 SW 腳位由高電位轉低電位的當下,觸發中斷,執行 SW_callback() 函數
while True :
if key != 0: # pressed
print(key)
key = 0
理論上,按一個按鍵,應該出現一個 1 。執行後,我們發現我們發現印出好多!而且有些數值高於 1,這都是彈跳造成的。
在 while loop 中,我們對於改變 key 內容的操作,並沒使用一些同步的防護限制,主要考慮這是一個簡單的例子, 複雜的同步機制超出我們要討論的範圍,詳細的一些限制,請您參考作業系統相關的書籍。
我們再修改一下程式,在中斷中加入了時間的判斷:
import time
from machine import Pin
SW = Pin(4, Pin.IN)
key = 0
t0 = 0
delay = 1000 # 1000 ms
def SW_callback(pin):
global key
global t0
global delay
if (key == 0):
t1 = time.ticks_ms()
if (t1 - t0) > delay :
key = 1
t0 = t1
SW.irq(handler=SW_callback, trigger=Pin.IRQ_FALLING)
while True :
if key != 0: # pressed
print(key)
key = 0
彈跳不見了! 您可以調整一下 delay 的數值,看看效果。
最終我們自鎖開關,開滅 LED 的程式可以改成:
import time
from machine import Pin
SW = Pin(4, Pin.IN)
LED = Pin(1, Pin.OUT)
key = 0
t0 = 0
delay = 1000 # 1000 ms
def SW_callback(pin):
global key
global t0
global delay
if (key == 0):
t1 = time.ticks_ms()
if (t1 - t0) > delay :
key = 1
t0 = t1
SW.irq(handler=SW_callback, trigger=Pin.IRQ_FALLING)
LED.value(0) # turn off LED at beginning
while True :
if key:
LED.value(not LED.value())
key = 0
while 主迴路是否清爽多了呢 ?